void createDeepTemp(AstNode* nodep) { UINFO(6," Deep "<<nodep<<endl); //if (debug()>=9) nodep->dumpTree(cout,"deep:"); string newvarname = ((string)"__Vdeeptemp"+cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname, // Width, not widthMin, as we may be in middle of BITSEL expression which // though it's one bit wide, needs the mask in the upper bits. // (Someday we'll have a valid bitmask instead of widths....) // See t_func_crc for an example test that requires this VFlagLogicPacked(), nodep->width()); if (!m_funcp) nodep->v3fatalSrc("Deep expression not under a function"); m_funcp->addInitsp(varp); // Replace node tree with reference to var AstVarRef* newp = new AstVarRef (nodep->fileline(), varp, false); nodep->replaceWith(newp); // Put assignment before the referencing statement AstAssign* assp = new AstAssign (nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true), nodep); AstNRelinker linker2; m_stmtp->unlinkFrBack(&linker2); assp->addNext(m_stmtp); linker2.relink(assp); }
AstVar* getBlockTemp(AstNode* nodep) { string newvarname = ((string)"__Vtemp"+cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); m_funcp->addInitsp(varp); return varp; }
void replaceBoundLvalue(AstNode* nodep, AstNode* condp) { // Spec says a out-of-range LHS SEL results in a NOP. // This is a PITA. We could: // 1. IF(...) around an ASSIGN, // but that would break a "foo[TOO_BIG]=$fopen(...)". // 2. Hack to extend the size of the output structure // by one bit, and write to that temporary, but never read it. // That makes there be two widths() and is likely a bug farm. // 3. Make a special SEL to choose between the real lvalue // and a temporary NOP register. // 4. Assign to a temp, then IF that assignment. // This is suspected to be nicest to later optimizations. // 4 seems best but breaks later optimizations. 3 was tried, // but makes a mess in the emitter as lvalue switching is needed. So 4. // SEL(...) -> temp // if (COND(LTE(bit<=maxlsb))) ASSIGN(SEL(...)),temp) if (m_assignwp) { // Wire assigns must become always statements to deal with insertion // of multiple statements. Perhaps someday make all wassigns into always's? UINFO(5," IM_WireRep "<<m_assignwp<<endl); m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL; } bool needDly = (m_assigndlyp != NULL); if (m_assigndlyp) { // Delayed assignments become normal assignments, // then the temp created becomes the delayed assignment AstNode* newp = new AstAssign(m_assigndlyp->fileline(), m_assigndlyp->lhsp()->unlinkFrBackWithNext(), m_assigndlyp->rhsp()->unlinkFrBackWithNext()); m_assigndlyp->replaceWith(newp); pushDeletep(m_assigndlyp); m_assigndlyp=NULL; } AstNode* prep = nodep; // Scan back to put the condlvalue above all selects (IE top of the lvalue) while (prep->backp()->castNodeSel() || prep->backp()->castSel()) { prep=prep->backp(); } FileLine* fl = nodep->fileline(); VL_DANGLING(nodep); // Zap it so we don't use it by mistake - use prep // Already exists; rather than IF(a,... IF(b... optimize to IF(a&&b, // Saves us teaching V3Const how to optimize, and it won't be needed again. if (AstIf* ifp = prep->user2p()->castIf()) { if (needDly) prep->v3fatalSrc("Should have already converted to non-delay"); AstNRelinker replaceHandle; AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle); AstNode* newp = new AstLogAnd (condp->fileline(), condp, earliercondp); UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl); replaceHandle.relink(newp); } else { string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep()); m_modp->addStmtp(varp); AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace prep->replaceWith(new AstVarRef(fl, varp, true)); AstNode* newp = new AstIf(fl, condp, (needDly ? static_cast<AstNode*> (new AstAssignDly(fl, prep, new AstVarRef(fl, varp, false))) : static_cast<AstNode*> (new AstAssign (fl, prep, new AstVarRef(fl, varp, false)))), NULL); if (debug()>=9) newp->dumpTree(cout," _new: "); abovep->addNextStmt(newp,abovep); prep->user2p(newp); // Save so we may LogAnd it next time } }
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); } } }