Пример #1
0
    void insertCast(AstNode* nodep, int needsize) {  // We'll insert ABOVE passed node
	UINFO(4,"  NeedCast "<<nodep<<endl);
	AstNRelinker relinkHandle;
	nodep->unlinkFrBack(&relinkHandle);
	//
	AstCCast* castp = new AstCCast (nodep->fileline(), nodep, needsize, nodep->widthMin());
	relinkHandle.relink(castp);
	//if (debug()>8) castp->dumpTree(cout,"-castins: ");
	//
	insureLower32Cast(castp);
	nodep->user1(1);  // Now must be of known size
    }
Пример #2
0
    AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
	// Put label under given node, and if WHILE optionally at end of iteration
	UINFO(4,"Create label for "<<nodep<<endl);
	if (nodep->castJumpLabel()) return nodep->castJumpLabel(); // Done

	AstNode* underp = NULL;
	bool     under_and_next = true;
	if (nodep->castBegin()) underp = nodep->castBegin()->stmtsp();
	else if (nodep->castNodeFTask()) underp = nodep->castNodeFTask()->stmtsp();
	else if (nodep->castWhile()) {
	    if (endOfIter) {
		// Note we jump to end of bodysp; a FOR loop has its increment under incsp() which we don't skip
		underp = nodep->castWhile()->bodysp();
	    } else {
		underp = nodep; under_and_next=false; // IE we skip the entire while
	    }
	}
	else {
	    nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
	    return NULL;
	}
	// Skip over variables as we'll just move them in a momement
	// Also this would otherwise prevent us from using a label twice
	// see t_func_return test.
	while (underp && underp->castVar()) underp = underp->nextp();
	if (underp) UINFO(5,"  Underpoint is "<<underp<<endl);

	if (!underp) {
	    nodep->v3fatalSrc("Break/disable/continue not under expected statement");
	    return NULL;
	} else if (underp->castJumpLabel()) {
	    return underp->castJumpLabel();
	} else { // Move underp stuff to be under a new label
	    AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL);

	    AstNRelinker repHandle;
	    if (under_and_next) underp->unlinkFrBackWithNext(&repHandle);
	    else underp->unlinkFrBack(&repHandle);
	    repHandle.relink(labelp);

	    labelp->addStmtsp(underp);
	    // Keep any AstVars under the function not under the new JumpLabel
	    for (AstNode* nextp, *varp=underp; varp; varp = nextp) {
		nextp = varp->nextp();
		if (varp->castVar()) {
		    labelp->addPrev(varp->unlinkFrBack());
		}
	    }
	    return labelp;
	}
    }
Пример #3
0
    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);
	    }
	}
    }
Пример #4
0
    void visitShift (AstNodeBiop* nodep) {
	// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
	if (!nodep->user2SetOnce()) {
	    UINFO(4,"  ShiftFix  "<<nodep<<endl);
	    AstConst* shiftp = nodep->rhsp()->castConst();
	    if (shiftp && shiftp->num().mostSetBitP1() > 32) {
		shiftp->v3error("Unsupported: Shifting of by over 32-bit number isn't supported."
				<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
	    }
	    if (nodep->widthMin()<=64  // Else we'll use large operators which work right
		// C operator's width must be < maximum shift which is based on Verilog width
		&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		AstNode* constzerop;
		int m1value = nodep->widthMin()-1; // Constant of width-1; not changing dtype width
		if (nodep->signedFlavor()) {
		    // Then over shifting gives the sign bit, not all zeros
		    // Note *NOT* clean output -- just like normal shift!
		    // Create equivalent of VL_SIGNONES_(node_width)
		    constzerop = new AstNegate (nodep->fileline(),
						new AstShiftR(nodep->fileline(),
							      nodep->lhsp()->cloneTree(false),
							      new AstConst(nodep->fileline(),
									   m1value),
							      nodep->width()));
		} else {
		    V3Number zeronum  (nodep->fileline(), nodep->width(), 0);
		    constzerop = new AstConst(nodep->fileline(), zeronum);
		}
		constzerop->dtypeFrom (nodep);  // unsigned

		V3Number widthnum (nodep->fileline(), nodep->rhsp()->widthMin(), m1value);
		AstNode* constwidthp = new AstConst(nodep->fileline(), widthnum);
		constwidthp->dtypeFrom (nodep->rhsp());  // unsigned
		AstCond* newp =
		    new AstCond (nodep->fileline(),
				 new AstGte (nodep->fileline(),
					     constwidthp,
					     nodep->rhsp()->cloneTree(false)),
				 nodep,
				 constzerop);
		replaceHandle.relink(newp);
	    }
	}
	nodep->iterateChildren(*this); checkNode(nodep);
    }
Пример #5
0
    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);
	    }
	}
    }
Пример #6
0
    void insertBeforeStmt(AstNode* newp) {
	// Insert newp before m_stmtp
	if (m_inWhilep) {
	    // Statements that are needed for the 'condition' in a while actually have to
	    // be put before & after the loop, since we can't do any statements in a while's (cond).
	    m_inWhilep->addPrecondsp(newp);
	} else if (m_inTracep) {
	    m_inTracep->addPrecondsp(newp);
	} else if (m_stmtp) {
	    AstNRelinker linker;
	    m_stmtp->unlinkFrBack(&linker);
	    newp->addNext(m_stmtp);
	    linker.relink(newp);
	} else {
	    newp->v3fatalSrc("No statement insertion point.");
	}
    }
Пример #7
0
    AstCFunc* createDeepFunc(AstNode* nodep) {
	AstNRelinker relinkHandle;
	nodep->unlinkFrBack(&relinkHandle);
	// Create function
	string name = m_funcp->name()+"__deep"+cvtToStr(++m_deepNum);
	AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL);
	funcp->argTypes(EmitCBaseVisitor::symClassVar());
	funcp->symProlog(true);
	funcp->slow(m_funcp->slow());
	funcp->addStmtsp(nodep);
	m_modp->addStmtp(funcp);
	// Call it at the point where the body was removed from
	AstCCall* callp = new AstCCall(nodep->fileline(), funcp);
	callp->argTypes("vlSymsp");
	UINFO(6,"      New "<<callp<<endl);
	//
	relinkHandle.relink(callp);
	return funcp;
    }
Пример #8
0
    void createDeepTemp(AstNode* nodep, bool noSubst) {
	if (debug()>8) nodep->dumpTree(cout,"deepin:");

	AstNRelinker linker;
	nodep->unlinkFrBack(&linker);

	AstVar* varp = getBlockTemp(nodep);
	if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const
	// Replace node tree with reference to var
	AstVarRef* newp = new AstVarRef (nodep->fileline(), varp, false);
	linker.relink(newp);
	// Put assignment before the referencing statement
	AstAssign* assp = new AstAssign (nodep->fileline(),
					 new AstVarRef(nodep->fileline(), varp, true),
					 nodep);
	insertBeforeStmt(assp);
	if (debug()>8) assp->dumpTree(cout,"deepou:");
	nodep->user1(true);  // Don't add another assignment
    }
Пример #9
0
    void reorderBlock(AstNode* nodep) {
	// Reorder statements in the completed graph

	// Map the rank numbers into nodes they associate with
        typedef std::multimap<uint32_t,AstNode*> RankNodeMap;
        RankNodeMap rankMap;
	int currOrder = 0;	// Existing sequence number of assignment
	for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
	    SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
	    rankMap.insert(make_pair(vvertexp->rank(), nextp));
	    nextp->user4(++currOrder);   // Record current ordering
	}

	// Is the current ordering OK?
	bool leaveAlone=true;
	int newOrder = 0;	// New sequence number of assignment
        for (RankNodeMap::const_iterator it = rankMap.begin();
             it != rankMap.end(); ++it) {
            AstNode* nextp = it->second;
            if (++newOrder != nextp->user4()) leaveAlone=false;
        }
	if (leaveAlone) {
	    UINFO(6,"   No changes\n");
	} else {
	    AstNRelinker replaceHandle;	// Where to add the list
            AstNode* newListp = NULL;
            for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
                AstNode* nextp = it->second;
                UINFO(6, "   New order: "<<nextp<<endl);
                if (nextp == nodep) nodep->unlinkFrBack(&replaceHandle);
                else nextp->unlinkFrBack();
                if (newListp) newListp = newListp->addNext(nextp);
                else newListp = nextp;
            }
            replaceHandle.relink(newListp);
	} // leaveAlone
    }
Пример #10
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
	}
    }
Пример #11
0
    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);
	    }
	}
    }
Пример #12
0
    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);
	    }
	}
    }
Пример #13
0
    void reorderBlock(AstNode* nodep) {
	// Reorder statements in the completed graph
	AstAlways* splitAlwaysp = nodep->backp()->castAlways();

	// Map the rank numbers into nodes they associate with
	typedef multimap<uint32_t,AstNode*> RankNodeMap;
	typedef map<uint32_t,RankNodeMap> ColorRankMap;
	ColorRankMap colorRankMap;
	uint32_t firstColor = 0;  bool multiColors = false;
	int currOrder = 0;	// Existing sequence number of assignment
	for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
	    SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
	    if (!splitAlwaysp) vvertexp->splitColor(1);  // All blocks remain as-is
	    RankNodeMap& rankMap = colorRankMap[vvertexp->splitColor()];
	    rankMap.insert(make_pair(vvertexp->rank(), nextp));
	    if (firstColor && firstColor != vvertexp->splitColor()) multiColors = true;
	    firstColor = vvertexp->splitColor();
	    nextp->user4(++currOrder);   // Record current ordering
	}
	// If there was only one color, we don't need multiple always blocks
	if (!multiColors) splitAlwaysp = NULL;

	// Is the current ordering OK?
	bool leaveAlone=true;
	if (splitAlwaysp) leaveAlone=false;
	int newOrder = 0;	// New sequence number of assignment
	for (ColorRankMap::iterator colorIt = colorRankMap.begin(); colorIt != colorRankMap.end(); ++colorIt) {
	    RankNodeMap& rankMap = colorIt->second;
	    for (RankNodeMap::iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
		AstNode* nextp = it->second;
		if (++newOrder != nextp->user4()) leaveAlone=false;
	    }
	}
	if (leaveAlone) {
	    UINFO(6,"   No changes\n");
	} else {
	    AstNRelinker replaceHandle;	// Where to add the list
	    AstNode* addAfterp = splitAlwaysp;

	    for (ColorRankMap::iterator colorIt = colorRankMap.begin(); colorIt != colorRankMap.end(); ++colorIt) {
		uint32_t color = colorIt->first;
		RankNodeMap& rankMap = colorIt->second;
		AstNode* newListp = NULL;
		for (RankNodeMap::iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
		    AstNode* nextp = it->second;
		    UINFO(6, "    Color="<<color<<"  New order: "<<nextp<<endl);
		    if (nextp == nodep && !splitAlwaysp) nodep->unlinkFrBack(&replaceHandle);
		    else nextp->unlinkFrBack();
		    newListp = newListp->addNext(nextp);
		}
		if (splitAlwaysp) {
		    ++m_statSplits;
		    AstAlways* alwaysp = new AstAlways(newListp->fileline(), VAlwaysKwd::ALWAYS, NULL, NULL);
		    addAfterp->addNextHere(alwaysp);  addAfterp=alwaysp;
		    alwaysp->addStmtp(newListp);
		} else {
		    // Just reordering
		    replaceHandle.relink(newListp);
		}
	    }
	    if (splitAlwaysp) {
		pushDeletep(splitAlwaysp->unlinkFrBack());
	    }
	} // leaveAlone
    }
Пример #14
0
    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);
	    }
	}
    }