Beispiel #1
0
    void genChangeDet(AstVarScope* vscp) {
#ifdef NEW_ORDERING
	vscp->v3fatalSrc("Not applicable\n");
#endif
	AstVar* varp = vscp->varp();
	vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
	AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
	AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
	bool isArray = arrayp;
	bool isStruct = structp && structp->packedUnsup();
	int elements = isArray ? arrayp->elementsConst() : 1;
	if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
			 <<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
			 <<vscp->warnMore()
			 <<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
	} else if (!isArray && !isStruct
		   && !varp->dtypeSkipRefp()->castBasicDType()) {
	    if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
	} else {
	    string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
	    // Create:  VARREF(_last)
	    //          ASSIGN(VARREF(_last), VARREF(var))
	    //          ...
	    //          CHANGEDET(VARREF(_last), VARREF(var))
	    AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
	    m_topModp->addStmtp(newvarp);
	    AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
	    m_scopetopp->addVarp(newvscp);
	    for (int index=0; index<elements; ++index) {
		AstChangeDet* changep
		    = new AstChangeDet (vscp->fileline(),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), vscp, false)),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), newvscp, false)),
					false);
		m_chgFuncp->addStmtsp(changep);
		AstAssign* initp
		    = new AstAssign (vscp->fileline(),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), newvscp, true)),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), vscp, false)));
		m_chgFuncp->addFinalsp(initp);
	    }
	}
    }
Beispiel #2
0
    AstNode* createDlyArray(AstAssignDly* nodep, AstNode* lhsp) {
	// Create delayed assignment
	// See top of this file for transformation
	// Return the new LHS for the assignment, Null = unlink
	// Find selects
	AstNode* newlhsp = NULL;	// NULL = unlink old assign
	AstSel*  bitselp = NULL;
	AstArraySel*  arrayselp = NULL;
	if (lhsp->castSel()) {
	    bitselp = lhsp->castSel();
	    arrayselp = bitselp->fromp()->castArraySel();
	} else {
	    arrayselp = lhsp->castArraySel();
	}
	if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
	if (arrayselp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");

	UINFO(4,"AssignDlyArray: "<<nodep<<endl);
	//
	//=== Dimensions: __Vdlyvdim__
	deque<AstNode*> dimvalp;		// Assignment value for each dimension of assignment
	AstNode* dimselp=arrayselp;
	for (; dimselp->castArraySel(); dimselp=dimselp->castArraySel()->fromp()) {
	    AstNode* valp = dimselp->castArraySel()->bitp()->unlinkFrBack();
	    dimvalp.push_front(valp);
	}
	AstVarRef* varrefp = dimselp->castVarRef();
	if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels\n");
	if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
	varrefp->unlinkFrBack();
	AstVar* oldvarp = varrefp->varp();
	int modVecNum = oldvarp->user4();  oldvarp->user4(modVecNum+1);
	//
	deque<AstNode*> dimreadps;		// Read value for each dimension of assignment
	for (unsigned dimension=0; dimension<dimvalp.size(); dimension++) {
	    AstNode* dimp = dimvalp[dimension];
	    if (dimp->castConst()) { // bit = const, can just use it
		dimreadps.push_front(dimp);
	    } else {
		string bitvarname = (string("__Vdlyvdim")+cvtToStr(dimension)
				     +"__"+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
		AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width());
		AstAssign* bitassignp
		    = new AstAssign (nodep->fileline(),
				     new AstVarRef(nodep->fileline(), bitvscp, true),
				     dimp);
		nodep->addNextHere(bitassignp);
		dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
	    }
	}
	//
	//=== Bitselect: __Vdlyvlsb__
	AstNode* bitreadp=NULL;  // Code to read Vdlyvlsb
	if (bitselp) {
	    AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
	    if (bitselp->fromp()->castConst()) {// vlsb = constant, can just push constant into where we use it
		bitreadp = lsbvaluep;
	    } else {
		string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
		AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width());
		AstAssign* bitassignp = new AstAssign (nodep->fileline(),
						       new AstVarRef(nodep->fileline(), bitvscp, true),
						       lsbvaluep);
		nodep->addNextHere(bitassignp);
		bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
	    }
	}
	//
	//=== Value: __Vdlyvval__
	AstNode* valreadp;	// Code to read Vdlyvval
	if (nodep->rhsp()->castConst()) {	// vval = constant, can just push constant into where we use it
	    valreadp = nodep->rhsp()->unlinkFrBack();
	} else {
	    string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
	    AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, nodep->rhsp()->width());
	    newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
	    valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
	}
	//
	//=== Setting/not setting boolean: __Vdlyvset__
	AstVarScope* setvscp;
	AstAssignPre* setinitp = NULL;

	if (nodep->user3p()) {
	    // Simplistic optimization.  If the previous statement in same scope was also a =>,
	    // then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
	    // This is good for code like:
	    //    for (i=0; i<5; i++)  vector[i] <= something;
	    setvscp = nodep->user3p()->castNode()->castVarScope();
	    ++m_statSharedSet;
	} else {  // Create new one
	    string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
	    setvscp = createVarSc(varrefp->varScopep(), setvarname, 1);
	    setinitp = new AstAssignPre (nodep->fileline(),
					 new AstVarRef(nodep->fileline(), setvscp, true),
					 new AstConst(nodep->fileline(), 0));
	    AstAssign* setassignp
		= new AstAssign (nodep->fileline(),
				 new AstVarRef(nodep->fileline(), setvscp, true),
				 new AstConst(nodep->fileline(),
					      V3Number(nodep->fileline(),1,true)));
	    nodep->addNextHere(setassignp);
	}
	if (m_nextDlyp) {  // Tell next assigndly it can share the variable
	    m_nextDlyp->user3p(setvscp);
	}
	//
	// Create ALWAYSPOST for delayed variable
	// We add all logic to the same block if it's for the same memory
	// This insures that multiple assignments to the same memory will result
	// in correctly ordered code - the last assignment must be last.
	// It also has the nice side effect of assisting cache locality.
	AstNode* selectsp = varrefp;
	for (int dimension=int(dimreadps.size())-1; dimension>=0; --dimension) {
	    selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]);
	}
	if (bitselp) {
	    selectsp = new AstSel(nodep->fileline(), selectsp, bitreadp,
				  bitselp->widthp()->cloneTree(false));
	}
	// Build "IF (changeit) ...
	UINFO(9,"   For "<<setvscp<<endl);
	UINFO(9,"     & "<<varrefp<<endl);
	AstAlwaysPost* finalp = varrefp->varScopep()->user4p()->castNode()->castAlwaysPost();
	if (finalp) {
	    AstActive* oldactivep = finalp->user2p()->castNode()->castActive();
	    checkActivePost(varrefp, oldactivep);
	    if (setinitp) oldactivep->addStmtsp(setinitp);
	} else { // first time we've dealt with this memory
	    finalp = new AstAlwaysPost(nodep->fileline(), NULL/*sens*/, NULL/*body*/);
	    UINFO(9,"     Created "<<finalp<<endl);
	    AstActive* newactp = createActivePost(varrefp);
	    newactp->addStmtsp(finalp);
	    varrefp->varScopep()->user4p(finalp);
	    finalp->user2p(newactp);
	    if (setinitp) newactp->addStmtsp(setinitp);
	}
	AstIf* postLogicp;
	if (finalp->user3p()->castNode() == setvscp) {
	    // Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
	    // we can share the IF statement too
	    postLogicp = finalp->user4p()->castNode()->castIf();
	    if (!postLogicp) nodep->v3fatalSrc("Delayed assignment misoptimized; prev var found w/o associated IF");
	} else {
	    postLogicp = new AstIf (nodep->fileline(),
				    new AstVarRef(nodep->fileline(), setvscp, false),
				    NULL,
				    NULL);
	    UINFO(9,"     Created "<<postLogicp<<endl);
	    finalp->addBodysp(postLogicp);
	    finalp->user3p(setvscp);	// Remember IF's vset variable
	    finalp->user4p(postLogicp);	// and the associated IF, as we may be able to reuse it
	}
	postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp));
	return newlhsp;
    }