virtual void visit(AstRepeat* nodep, AstNUser*) { // So later optimizations don't need to deal with them, // REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- } // Note var can be signed or unsigned based on original number. AstNode* countp = nodep->countp()->unlinkFrBackWithNext(); string name = string("__Vrepeat")+cvtToStr(m_repeatNum++); // Spec says value is integral, if negative is ignored AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, nodep->findSigned32DType()); varp->usedLoopIdx(true); m_modp->addStmtp(varp); AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true), countp); AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true), new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), new AstConst(nodep->fileline(), 1))); V3Number zero (nodep->fileline(), 32, 0); zero.isSigned(true); AstNode* zerosp = new AstConst(nodep->fileline(), zero); AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp); AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext(); AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp); initsp = initsp->addNext(newp); newp = initsp; nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); }
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; }
void forUnroller(AstNode* nodep, AstNode* initp, AstNode* precondsp, AstNode* condp, AstNode* incp, AstNode* bodysp, const V3Number& numInit, AstNodeBiop* cmpInstrp, const V3Number& numStop, AstNodeBiop* incInstrp, const V3Number& numInc) { UINFO(4, " Unroll for var="<<numInit<<"; var<"<<numStop<<"; var+="<<numInc<<endl); UINFO(6, " cmpI "<<cmpInstrp<<endl); UINFO(6, " IncI "<<incInstrp<<endl); 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); // If it's a While, then incp is already part of bodysp. V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp loopValue.opAssign(numInit); AstNode* newbodysp = NULL; ++m_statLoops; if (stmtsp) { int times = 0; while (1) { UINFO(8," Looping "<<loopValue<<endl); // if loopValue<valStop V3Number contin (nodep->fileline(), 1); cmpInstrp->numberOperate(contin, loopValue, numStop); if (contin.isEqZero()) { 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(); tempp=NULL; } 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); } 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 V3Number newnum(nodep->fileline(), m_forVarp->width()); // Can't increment in-place incInstrp->numberOperate(newnum, loopValue, numInc); loopValue.opAssign(newnum); pushDeletep(m_varValuep); m_varValuep=NULL; } } } // Replace the FOR() if (newbodysp) nodep->replaceWith(newbodysp); else nodep->unlinkFrBack(); if (bodysp) { pushDeletep(bodysp); bodysp=NULL; } if (precondsp) { pushDeletep(precondsp); precondsp=NULL; } if (initp) { pushDeletep(initp); initp=NULL; } if (incp && !incp->backp()) { pushDeletep(incp); incp=NULL; } if (debug()>=9) newbodysp->dumpTree(cout,"- _new: "); }