AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) { // Return lhs-rhs, but if rhs is negative use an add, so we won't // have to deal with signed math and related 32bit sign extension problems if (rhs == 0) { return lhsp; } else if (lhsp->castConst()) { // Optional vs just making add/sub below, but saves constification some work V3Number num (lhsp->fileline(), lhsp->width()); num.opSub(lhsp->castConst()->num(), V3Number(lhsp->fileline(), 32, rhs)); num.isSigned(lhsp->isSigned()); AstNode* newp = new AstConst(lhsp->fileline(), num); return newp; } else if (rhs > 0) { AstNode* newp = new AstSub(lhsp->fileline(), lhsp, new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs)); // We must make sure sub gets sign of original value, not from the constant newp->dtypeFrom(lhsp); return newp; } else { // rhs < 0; AstNode* newp = new AstAdd(lhsp->fileline(), lhsp, new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs)); // We must make sure sub gets sign of original value, not from the constant newp->dtypeFrom(lhsp); return newp; } }
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; }
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); }
virtual void visit(AstGenCase* nodep, AstNUser*) { UINFO(9," GENCASE "<<nodep<<endl); AstNode* keepp = NULL; nodep->exprp()->iterateAndNext(*this); V3Case::caseLint(nodep); V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body, // don't trigger errors yet. V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change AstConst* exprp = nodep->exprp()->castConst(); // Constify for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { for (AstNode* ep = itemp->condsp(); ep; ) { AstNode* nextp = ep->nextp(); //May edit list ep->iterateAndNext(*this); V3Const::constifyParamsEdit(ep); ep=NULL; // ep may change // cppcheck-suppress redundantAssignment ep = nextp; } } // Item match for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { if (!itemp->isDefault()) { for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) { if (AstConst* ccondp = ep->castConst()) { V3Number match (nodep->fileline(), 1); match.opEq(ccondp->num(), exprp->num()); if (!keepp && match.isNeqZero()) { keepp = itemp->bodysp(); } } else { itemp->v3error("Generate Case item does not evaluate to constant"); } } } } // Else default match for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { if (itemp->isDefault()) { if (!keepp) keepp=itemp->bodysp(); } } // Replace if (keepp) { keepp->unlinkFrBackWithNext(); nodep->replaceWith(keepp); } else nodep->unlinkFrBack(); nodep->deleteTree(); nodep=NULL; }
void visit(AstSel* nodep, AstNUser*) { nodep->iterateChildren(*this); if (!nodep->user1Inc()) { // Guard against reading/writing past end of bit vector array int maxmsb = 0; bool lvalue = false; AstNode* basefromp = AstArraySel::baseFromp(nodep); if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { lvalue = varrefp->lvalue(); maxmsb = (varrefp->varp()->width()-1); } else { // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp maxmsb = basefromp->width()-1; } int maxlsb = maxmsb - nodep->width() + 1; if (debug()>=9) nodep->dumpTree(cout,"sel_old: "); V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb); // See if the condition is constant true AstNode* condp = new AstLte (nodep->fileline(), nodep->lsbp()->cloneTree(false), new AstConst(nodep->fileline(), maxlsbnum)); // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { // We don't need to add a conditional; we know the existing expression is ok condp->deleteTree(); } else if (!lvalue) { // SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}}) AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); V3Number xnum (nodep->fileline(), nodep->width()); xnum.setAllBitsX(); AstNode* newp = new AstCondBound (nodep->fileline(), condp, nodep, new AstConst(nodep->fileline(), xnum)); if (debug()>=9) newp->dumpTree(cout," _new: "); // Link in conditional replaceHandle.relink(newp); // Added X's, tristate them too newp->accept(*this); } else { // lvalue replaceBoundLvalue(nodep, condp); } } }
virtual void visit(AstSel* nodep) { nodep->iterateChildren(*this); if (!nodep->user1SetOnce()) { // Guard against reading/writing past end of bit vector array AstNode* basefromp = AstArraySel::baseFromp(nodep); bool lvalue = false; if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { lvalue = varrefp->lvalue(); } // Find range of dtype we are selecting from // Similar code in V3Const::warnSelect int maxmsb = nodep->fromp()->dtypep()->width()-1; if (debug()>=9) nodep->dumpTree(cout,"sel_old: "); V3Number maxmsbnum (nodep->fileline(), nodep->lsbp()->width(), maxmsb); // If (maxmsb >= selected), we're in bound AstNode* condp = new AstGte (nodep->fileline(), new AstConst(nodep->fileline(), maxmsbnum), nodep->lsbp()->cloneTree(false)); // See if the condition is constant true (e.g. always in bound due to constant select) // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { // We don't need to add a conditional; we know the existing expression is ok condp->deleteTree(); } else if (!lvalue) { // SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}}) AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); V3Number xnum (nodep->fileline(), nodep->width()); xnum.setAllBitsX(); AstNode* newp = new AstCondBound (nodep->fileline(), condp, nodep, new AstConst(nodep->fileline(), xnum)); if (debug()>=9) newp->dumpTree(cout," _new: "); // Link in conditional replaceHandle.relink(newp); // Added X's, tristate them too newp->accept(*this); } else { // lvalue replaceBoundLvalue(nodep, condp); } } }
void visitEqNeqWild(AstNodeBiop* nodep) { UINFO(4," N/EQWILD->EQ "<<nodep<<endl); V3Const::constifyEdit(nodep->lhsp()); // lhsp may change V3Const::constifyEdit(nodep->rhsp()); // rhsp may change if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) { // Both sides are constant, node can be constant V3Const::constifyEdit(nodep); VL_DANGLING(nodep); return; } else { AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* newp; if (!rhsp->castConst()) { nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // Says spec. // Replace with anything that won't cause more errors newp = new AstEq (nodep->fileline(), lhsp, rhsp); } else { // X or Z's become mask, ala case statements. V3Number nummask (rhsp->fileline(), rhsp->width()); nummask.opBitsNonX(rhsp->castConst()->num()); V3Number numval (rhsp->fileline(), rhsp->width()); numval.opBitsOne (rhsp->castConst()->num()); AstNode* and1p = new AstAnd(nodep->fileline(), lhsp, new AstConst(nodep->fileline(), nummask)); AstNode* and2p = new AstConst(nodep->fileline(), numval); if (nodep->castEqWild()) newp = new AstEq (nodep->fileline(), and1p, and2p); else newp = new AstNeq (nodep->fileline(), and1p, and2p); rhsp->deleteTree(); VL_DANGLING(rhsp); } nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); // Iterate tree now that we may have gotten rid of the compare newp->iterateChildren(*this); } }
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 replaceCaseComplicated(AstCase* nodep) { // CASEx(cexpr,ITEM(icond1,istmts1),ITEM(icond2,istmts2),ITEM(default,istmts3)) // -> IF((cexpr==icond1),istmts1, // IF((EQ (AND MASK cexpr) (AND MASK icond1) // ,istmts2, istmts3 AstNode* cexprp = nodep->exprp()->unlinkFrBack(); // We'll do this in two stages. First stage, convert the conditions to // the appropriate IF AND terms. if (debug()>=9) nodep->dumpTree(cout," _comp_IN: "); bool hadDefault = false; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { if (!itemp->condsp()) { // Default clause. Just make true, we'll optimize it away later itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue())); hadDefault = true; } else { // Expressioned clause AstNode* icondNextp = NULL; AstNode* ifexprp = NULL; // If expression to test for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) { icondNextp = icondp->nextp(); icondp->unlinkFrBack(); AstNode* condp = NULL; // Default is to use and1p/and2p AstConst* iconstp = icondp->castConst(); if (iconstp && neverItem(nodep, iconstp)) { // X in casez can't ever be executed icondp->deleteTree(); icondp=NULL; iconstp=NULL; // For simplicity, make expression that is not equal, and let later // optimizations remove it condp = new AstConst(itemp->fileline(), AstConst::LogicFalse()); } else if (AstInsideRange* irangep = icondp->castInsideRange()) { // Similar logic in V3Width::visit(AstInside) AstNode* ap = AstGte::newTyped(itemp->fileline(), cexprp->cloneTree(false), irangep->lhsp()->unlinkFrBack()); AstNode* bp = AstLte::newTyped(itemp->fileline(), cexprp->cloneTree(false), irangep->rhsp()->unlinkFrBack()); condp = new AstAnd(itemp->fileline(), ap, bp); } else if (iconstp && iconstp->num().isFourState() && (nodep->casex() || nodep->casez() || nodep->caseInside())) { V3Number nummask (itemp->fileline(), iconstp->width()); nummask.opBitsNonX(iconstp->num()); V3Number numval (itemp->fileline(), iconstp->width()); numval.opBitsOne(iconstp->num()); AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false), new AstConst(itemp->fileline(), nummask)); AstNode* and2p = new AstAnd(itemp->fileline(), new AstConst(itemp->fileline(), numval), new AstConst(itemp->fileline(), nummask)); icondp->deleteTree(); icondp=NULL; iconstp=NULL; condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } else { // Not a caseX mask, we can simply build CASEEQ(cexpr icond) AstNode* and1p = cexprp->cloneTree(false); AstNode* and2p = icondp; condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } if (!ifexprp) { ifexprp = condp; } else { ifexprp = new AstLogOr(itemp->fileline(), ifexprp, condp); } } // Replace expression in tree itemp->condsp(ifexprp); } } cexprp->deleteTree(); cexprp=NULL; if (!hadDefault) { // If there was no default, add a empty one, this greatly simplifies below code // and constant propagation will just eliminate it for us later. nodep->addItemsp(new AstCaseItem(nodep->fileline(), new AstConst(nodep->fileline(), AstConst::LogicTrue()), NULL)); } if (debug()>=9) nodep->dumpTree(cout," _comp_COND: "); // Now build the IF statement tree // The tree can be quite huge. Pull ever group of 8 out, and make a OR tree. // This reduces the depth for the bottom elements, at the cost of some of the top elements. // If we ever have profiling data, we should pull out the most common item from here and // instead make it the first IF branch. int depth = 0; AstNode* grouprootp = NULL; AstIf* groupnextp = NULL; AstIf* itemnextp = NULL; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action. if (istmtsp) istmtsp->unlinkFrBackWithNext(); // Expressioned clause AstNode* ifexprp = itemp->condsp()->unlinkFrBack(); { // Prepare for next group if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1; if (depth == 1) { // First group or starting new group itemnextp = NULL; AstIf* newp = new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL); if (groupnextp) groupnextp->addElsesp(newp); else grouprootp = newp; groupnextp = newp; } else { // Continue group, modify if condition to OR in this new condition AstNode* condp = groupnextp->condp()->unlinkFrBack(); groupnextp->condp(new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true))); } } { // Make the new lower IF and attach in the tree AstNode* itemexprp = ifexprp; ifexprp=NULL; if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition itemexprp->deleteTree(); itemexprp=NULL; itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue()); } AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL); if (itemnextp) itemnextp->addElsesp(newp); else groupnextp->addIfsp(newp); // First in a new group itemnextp = newp; } } if (debug()>=9) nodep->dumpTree(cout," _comp_TREE: "); // Handle any assertions replaceCaseParallel(nodep, false); // Replace the CASE... with IF... if (debug()>=9) grouprootp->dumpTree(cout," _new: "); if (grouprootp) nodep->replaceWith(grouprootp); else nodep->unlinkFrBack(); nodep->deleteTree(); nodep=NULL; }
bool isCaseTreeFast(AstCase* nodep) { int width = 0; bool opaque = false; m_caseItems = 0; m_caseNoOverlapsAllCovered = true; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { if (icondp->width() > width) width = icondp->width(); if (icondp->isDouble()) opaque = true; if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant m_caseItems++; } } m_caseWidth = width; if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) { m_caseNoOverlapsAllCovered = false; return false; // Too wide for analysis } UINFO(8,"Simple case statement: "<<nodep<<endl); // Zero list of items for each value for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) m_valueItem[i] = NULL; // Now pick up the values for each assignment // We can cheat and use uint32_t's because we only support narrow case's bool bitched = false; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { //if (debug()>=9) icondp->dumpTree(cout," caseitem: "); AstConst* iconstp = icondp->castConst(); if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this\n"); if (neverItem(nodep, iconstp)) { // X in casez can't ever be executed } else { V3Number nummask (itemp->fileline(), iconstp->width()); nummask.opBitsNonX(iconstp->num()); uint32_t mask = nummask.toUInt(); V3Number numval (itemp->fileline(), iconstp->width()); numval.opBitsOne(iconstp->num()); uint32_t val = numval.toUInt(); for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) { if ((i & mask) == val) { if (!m_valueItem[i]) { m_valueItem[i] = itemp; } else if (!itemp->ignoreOverlap() && !bitched) { itemp->v3warn(CASEOVERLAP,"Case values overlap (example pattern 0x"<<hex<<i<<")"); bitched = true; m_caseNoOverlapsAllCovered = false; } } } } } // Defaults were moved to last in the caseitem list by V3LinkDot if (itemp->isDefault()) { // Case statement's default... Fill the table for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) { if (!m_valueItem[i]) m_valueItem[i] = itemp; } } } for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) { if (!m_valueItem[i]) { nodep->v3warn(CASEINCOMPLETE,"Case values incompletely covered (example pattern 0x"<<hex<<i<<")"); m_caseNoOverlapsAllCovered = false; return false; } } if (m_caseItems <= 3) return false; // Not worth simplifing // Convert valueItem from AstCaseItem* to the expression // Not done earlier, as we may now have a NULL because it's just a ";" NOP branch for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) { m_valueItem[i] = m_valueItem[i]->castCaseItem()->bodysp(); } return true; // All is fine }
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: "); }
virtual void visit(AstArraySel* nodep) { nodep->iterateChildren(*this); if (!nodep->user1SetOnce()) { if (debug()==9) nodep->dumpTree(cout,"-in: "); // Guard against reading/writing past end of arrays AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp()); bool lvalue = false; if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { lvalue = varrefp->lvalue(); } else if (basefromp->castConst()) { // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp } else { nodep->v3fatalSrc("No VarRef or Const under ArraySel"); } // Find range of dtype we are selecting from int declElements = -1; AstNodeDType* dtypep = nodep->fromp()->dtypep()->skipRefp(); if (!dtypep) nodep->v3fatalSrc("Select of non-selectable type"); if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) { declElements = adtypep->elementsConst(); } else { nodep->v3error("Select from non-array "<<dtypep->prettyTypeName()); } if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: "); V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), declElements-1); // See if the condition is constant true AstNode* condp = new AstGte (nodep->fileline(), new AstConst(nodep->fileline(), widthnum), nodep->bitp()->cloneTree(false)); // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { // We don't need to add a conditional; we know the existing expression is ok condp->deleteTree(); } else if (!lvalue && !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension // ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}}) AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); V3Number xnum (nodep->fileline(), nodep->width()); if (nodep->isString()) { xnum = V3Number(V3Number::String(), nodep->fileline(), ""); } else { xnum.setAllBitsX(); } AstNode* newp = new AstCondBound (nodep->fileline(), condp, nodep, new AstConst(nodep->fileline(), xnum)); if (debug()>=9) newp->dumpTree(cout," _new: "); // Link in conditional, can blow away temp xor replaceHandle.relink(newp); // Added X's, tristate them too newp->accept(*this); } else if (!lvalue) { // Mid-multidimension read, just use zero // ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0)) AstNRelinker replaceHandle; AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle); V3Number zeronum (nodep->fileline(), bitp->width(), 0); AstNode* newp = new AstCondBound (bitp->fileline(), condp, bitp, new AstConst(bitp->fileline(), zeronum)); // Added X's, tristate them too if (debug()>=9) newp->dumpTree(cout," _new: "); replaceHandle.relink(newp); newp->accept(*this); } else { // lvalue replaceBoundLvalue(nodep, condp); } } }
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); } } }
void test(string lhss, string op, string rhss, string exps) { char* l1 = strdup(lhss.c_str()); char* r1 = strdup(rhss.c_str()); char* e1 = strdup(exps.c_str()); V3Number lhnum (new FileLine ("ck",__LINE__), l1); V3Number rhnum (new FileLine ("ck",__LINE__), r1); V3Number expnum (new FileLine("ck",__LINE__), e1); V3Number gotnum (new FileLine("ck",__LINE__), expnum.width()); if (op=="redOr") gotnum.opRedOr (lhnum); else if (op=="redAnd") gotnum.opRedAnd (lhnum); else if (op=="redXor") gotnum.opRedXor (lhnum); else if (op=="redXnor") gotnum.opRedXnor (lhnum); else if (op=="concat") gotnum.opConcat (lhnum,rhnum); else if (op=="repl") gotnum.opRepl (lhnum,rhnum); else if (op=="~") gotnum.opNot (lhnum); else if (op=="!") gotnum.opLogNot (lhnum); else if (op=="negate") gotnum.opNegate (lhnum); else if (op=="+") gotnum.opAdd (lhnum,rhnum); else if (op=="-") gotnum.opSub (lhnum,rhnum); else if (op=="*") gotnum.opMul (lhnum,rhnum); else if (op=="/") gotnum.opDiv (lhnum,rhnum); else if (op=="%") gotnum.opModDiv (lhnum,rhnum); else if (op=="&") gotnum.opAnd (lhnum,rhnum); else if (op=="|") gotnum.opOr (lhnum,rhnum); else if (op=="<") gotnum.opLt (lhnum,rhnum); else if (op==">") gotnum.opGt (lhnum,rhnum); else if (op==">>") gotnum.opShiftR (lhnum,rhnum); else if (op=="<<") gotnum.opShiftL (lhnum,rhnum); else if (op=="==") gotnum.opEq (lhnum,rhnum); else if (op=="===") gotnum.opCaseEq (lhnum,rhnum); else if (op=="==?") gotnum.opWildEq (lhnum,rhnum); else if (op=="!=") gotnum.opNeq (lhnum,rhnum); else if (op=="!==") gotnum.opCaseNeq (lhnum,rhnum); else if (op=="!=?") gotnum.opWildNeq (lhnum,rhnum); else if (op=="<=") gotnum.opLte (lhnum,rhnum); else if (op==">=") gotnum.opGte (lhnum,rhnum); else if (op=="&&") gotnum.opLogAnd (lhnum,rhnum); else if (op=="||") gotnum.opLogOr (lhnum,rhnum); else v3fatalSrc("Bad opcode: "<<op); UINFO(0,"------- Test:\n" <<" "<<lhnum<<" "<<op<<endl <<" "<<rhnum<<endl <<" = "<<expnum<<endl <<" =? "<<gotnum<<endl); V3Number ok (new FileLine("ck",__LINE__), 1); ok.opCaseEq(expnum,gotnum); if (ok.toUInt()!=1) { v3fatalSrc("%Error:Test FAILED\n"); } }
virtual void visit(AstArraySel* nodep, AstNUser*) { nodep->iterateChildren(*this); if (!nodep->user1Inc()) { if (debug()==9) nodep->dumpTree(cout,"-in: "); // Guard against reading/writing past end of arrays AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp()); int dimension = AstArraySel::dimension(nodep->fromp()); int maxmsb = 0; bool lvalue = false; if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { AstArrayDType* adtypep = varrefp->varp()->dtypep()->dtypeDimensionp(dimension)->castArrayDType(); if (!adtypep) nodep->v3fatalSrc("ArraySel to type without array at same depth"); lvalue = varrefp->lvalue(); maxmsb = adtypep->elementsConst()-1; } else if (AstConst* lhconstp = basefromp->castConst()) { // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp maxmsb = lhconstp->width(); } else { nodep->v3fatalSrc("No VarRef or Const under ArraySel\n"); } if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: "); V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), maxmsb); // See if the condition is constant true AstNode* condp = new AstLte (nodep->fileline(), nodep->bitp()->cloneTree(false), new AstConst(nodep->fileline(), widthnum)); // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { // We don't need to add a conditional; we know the existing expression is ok condp->deleteTree(); } else if (!lvalue && !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension // ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}}) AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); V3Number xnum (nodep->fileline(), nodep->width()); xnum.setAllBitsX(); AstNode* newp = new AstCondBound (nodep->fileline(), condp, nodep, new AstConst(nodep->fileline(), xnum)); if (debug()>=9) newp->dumpTree(cout," _new: "); // Link in conditional, can blow away temp xor replaceHandle.relink(newp); // Added X's, tristate them too newp->accept(*this); } else if (!lvalue) { // Mid-multidimension read, just use zero // ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0)) AstNRelinker replaceHandle; AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle); V3Number zeronum (nodep->fileline(), bitp->width(), 0); AstNode* newp = new AstCondBound (bitp->fileline(), condp, bitp, new AstConst(bitp->fileline(), zeronum)); // Added X's, tristate them too if (debug()>=9) newp->dumpTree(cout," _new: "); replaceHandle.relink(newp); newp->accept(*this); } else { // lvalue replaceBoundLvalue(nodep, condp); } } }