bool countLoops(AstAssign *initp, AstNode *condp, AstNode *incp, int max, int &outLoopsr) { outLoopsr = 0; V3Number loopValue = V3Number(initp->fileline()); if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { return false; } while (1) { V3Number res = V3Number(initp->fileline()); if (!simulateTree(condp, &loopValue, NULL, res)) { return false; } if (!res.isEqOne()) { break; } outLoopsr++; // Run inc AstAssign* incpass = incp->castAssign(); V3Number newLoopValue = V3Number(initp->fileline()); if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) { return false; } loopValue.opAssign(newLoopValue); if (outLoopsr > max) { return false; } } return true; }
bool forUnroller(AstNode* nodep, AstAssign* initp, AstNode* condp, AstNode* precondsp, AstNode* incp, AstNode* bodysp) { V3Number loopValue = V3Number(nodep->fileline()); if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { return false; } AstNode* stmtsp = NULL; if (initp) { initp->unlinkFrBack(); // Always a single statement; nextp() may be nodep // Don't add to list, we do it once, and setting loop index isn't needed as we're constant propagating it } if (precondsp) { precondsp->unlinkFrBackWithNext(); // cppcheck-suppress nullPointer // addNextNull deals with it stmtsp = stmtsp->addNextNull(precondsp); } if (bodysp) { bodysp->unlinkFrBackWithNext(); // cppcheck-suppress nullPointer // addNextNull deals with it stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body } if (incp && !nodep->castGenFor()) { // Generates don't need to increment loop index incp->unlinkFrBackWithNext(); // cppcheck-suppress nullPointer // addNextNull deals with it stmtsp = stmtsp->addNextNull(incp); // Maybe null if no body } // Mark variable to disable some later warnings m_forVarp->usedLoopIdx(true); AstNode* newbodysp = NULL; ++m_statLoops; if (stmtsp) { int times = 0; while (1) { UINFO(8," Looping "<<loopValue<<endl); V3Number res = V3Number(nodep->fileline()); if (!simulateTree(condp, &loopValue, NULL, res)) { nodep->v3error("Loop unrolling failed."); return false; } if (!res.isEqOne()) { break; // Done with the loop } else { // Replace iterator values with constant. AstNode* oneloopp = stmtsp->cloneTree(true); m_varValuep = new AstConst(nodep->fileline(), loopValue); // Iteration requires a back, so put under temporary node if (oneloopp) { AstBegin* tempp = new AstBegin(oneloopp->fileline(),"[EditWrapper]",oneloopp); m_varModeReplace = true; tempp->stmtsp()->iterateAndNext(*this); m_varModeReplace = false; oneloopp = tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); VL_DANGLING(tempp); } if (m_generate) { string index = AstNode::encodeNumber(m_varValuep->toSInt()); string nname = m_beginName + "__BRA__" + index + "__KET__"; oneloopp = new AstBegin(oneloopp->fileline(),nname,oneloopp,true); } pushDeletep(m_varValuep); m_varValuep=NULL; if (newbodysp) newbodysp->addNext(oneloopp); else newbodysp = oneloopp; ++m_statIters; if (++times > unrollCount()*3) { nodep->v3error("Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "<<unrollCount()); break; } // loopValue += valInc AstAssign *incpass = incp->castAssign(); V3Number newLoopValue = V3Number(nodep->fileline()); if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) { nodep->v3error("Loop unrolling failed"); return false; } loopValue.opAssign(newLoopValue); } } } // Replace the FOR() if (newbodysp) nodep->replaceWith(newbodysp); else nodep->unlinkFrBack(); if (bodysp) { pushDeletep(bodysp); VL_DANGLING(bodysp); } if (precondsp) { pushDeletep(precondsp); VL_DANGLING(precondsp); } if (initp) { pushDeletep(initp); VL_DANGLING(initp); } if (incp && !incp->backp()) { pushDeletep(incp); VL_DANGLING(incp); } if (debug()>=9) newbodysp->dumpTree(cout,"- _new: "); return true; }
virtual void visit(AstConst* nodep) { if (m_constXCvt && nodep->num().isFourState()) { UINFO(4," CONST4 "<<nodep<<endl); if (debug()>=9) nodep->dumpTree(cout," Const_old: "); // CONST(num) -> VARREF(newvarp) // -> VAR(newvarp) // -> INITIAL(VARREF(newvarp, OR(num_No_Xs,AND(random,num_1s_Where_X)) V3Number numb1 (nodep->fileline(), nodep->width()); numb1.opBitsOne(nodep->num()); V3Number numbx (nodep->fileline(), nodep->width()); numbx.opBitsXZ(nodep->num()); if (v3Global.opt.xAssign()!="unique") { // All X bits just become 0; fastest simulation, but not nice V3Number numnew (nodep->fileline(), numb1.width()); if (v3Global.opt.xAssign()=="1") { numnew.opOr(numb1, numbx); } else { numnew.opAssign(numb1); } AstConst* newp = new AstConst(nodep->fileline(), numnew); nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); UINFO(4," -> "<<newp<<endl); } else { // Make a Vxrand variable // We use the special XTEMP type so it doesn't break pure functions if (!m_modp) nodep->v3fatalSrc("X number not under module"); string newvarname = ((string)"__Vxrand" +cvtToStr(m_modp->varNumGetInc())); AstVar* newvarp = new AstVar (nodep->fileline(), AstVarType::XTEMP, newvarname, VFlagLogicPacked(), nodep->width()); ++m_statUnkVars; AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false); replaceHandle.relink(newref1p); // Replace const with varref AstInitial* newinitp = new AstInitial( nodep->fileline(), new AstAssign( nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, true), new AstOr(nodep->fileline(), new AstConst(nodep->fileline(),numb1), new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(),numbx), new AstRand(nodep->fileline(), nodep->dtypep(), true))))); // Add inits in front of other statement. // In the future, we should stuff the initp into the module's constructor. AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext(); m_modp->addStmtp(newvarp); m_modp->addStmtp(newinitp); m_modp->addStmtp(afterp); if (debug()>=9) newref1p->dumpTree(cout," _new: "); if (debug()>=9) newvarp->dumpTree(cout," _new: "); if (debug()>=9) newinitp->dumpTree(cout," _new: "); nodep->deleteTree(); VL_DANGLING(nodep); } } }