Example #1
0
    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
	}
    }