virtual void visit(AstBegin* nodep, AstNUser*) {
	// Begin blocks were only useful in variable creation, change names and delete
	UINFO(8,"  "<<nodep<<endl);
	string oldScope = m_namedScope;
	string oldUnnamed = m_unnamedScope;
	{
	    UINFO(8,"nname "<<m_namedScope<<endl);
	    if (nodep->name() != "") {  // Else unneeded unnamed block
		// Create data for dotted variable resolution
		string dottedname = nodep->name() + "__DOT__";  // So always found
		string::size_type pos;
		while ((pos=dottedname.find("__DOT__")) != string::npos) {
		    string ident = dottedname.substr(0,pos);
		    dottedname = dottedname.substr(pos+strlen("__DOT__"));
		    if (!nodep->unnamed()) {
			if (m_namedScope=="") m_namedScope = ident;
			else m_namedScope = m_namedScope + "__DOT__"+ident;
		    }
		    if (m_unnamedScope=="") m_unnamedScope = ident;
		    else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
		    // Create CellInline for dotted var resolution
		    if (!m_ftaskp) {
			AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
								   m_unnamedScope, "__BEGIN__");
			m_modp->addInlinesp(inlinep);  // Must be parsed before any AstCells
		    }
		}
	    }

	    // Remap var names and replace lower Begins
	    nodep->stmtsp()->iterateAndNext(*this);
	    if (nodep->genforp()) nodep->v3fatalSrc("GENFORs should have been expanded earlier");
	}
	m_namedScope = oldScope;
	m_unnamedScope = oldUnnamed;

	// Cleanup
	AstNode* addsp = NULL;
	if (AstNode* stmtsp = nodep->stmtsp()) {
	    stmtsp->unlinkFrBackWithNext();
	    if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
	}
	if (addsp) {
	    nodep->replaceWith(addsp);
	} else {
	    nodep->unlinkFrBack();
	}
	pushDeletep(nodep); nodep=NULL;
    }
Example #2
0
    virtual void visit(AstEnumItem* nodep, AstNUser*) {
	// Expand ranges
	cleanFileline(nodep);
	nodep->iterateChildren(*this);
	if (nodep->rangep()) {
	    if (!nodep->rangep()->msbp()->castConst()
		|| !nodep->rangep()->lsbp()->castConst()) nodep->v3error("Enum ranges must be integral, per spec");
	    int msb = nodep->rangep()->msbConst();
	    int lsb = nodep->rangep()->lsbConst();
	    int increment = (msb > lsb) ? -1 : 1;
	    int offset_from_init = 0;
	    AstNode* addp = NULL;
	    for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) {
		string name = nodep->name() + cvtToStr(i);
		AstNode* valuep = NULL;
		if (nodep->valuep()) valuep = new AstAdd(nodep->fileline(), nodep->valuep()->cloneTree(true),
							 new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init));
		addp = addp->addNextNull(new AstEnumItem(nodep->fileline(), name, NULL, valuep));
	    }
	    nodep->replaceWith(addp);
	    nodep->deleteTree();
	}
    }
Example #3
0
    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;
    }
Example #4
0
    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: ");
    }
Example #5
0
    void makePublicFuncWrappers() {
	// We recorded all public functions in m_modFuncs.
	// If for any given name only one function exists, we can use that function directly.
	// If multiple functions exist, we need to select the appropriate scope.
	for (FuncMmap::iterator it = m_modFuncs.begin(); it!=m_modFuncs.end(); ++it) {
	    string name = it->first;
	    AstCFunc* topFuncp = it->second;
	    FuncMmap::iterator nextIt1 = it; ++nextIt1;
	    bool moreOfSame1 =  (nextIt1!=m_modFuncs.end() && nextIt1->first == name);
	    if (moreOfSame1) {
		// Multiple functions under this name, need a wrapper function
		UINFO(6,"  Wrapping "<<name<<" multifuncs\n");
		AstCFunc* newfuncp = topFuncp->cloneTree(false);
		if (newfuncp->initsp())  newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
		if (newfuncp->stmtsp())  newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
		if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
		newfuncp->name(name);
		newfuncp->isStatic(false);
		newfuncp->addInitsp(
		    new AstCStmt(newfuncp->fileline(),
				 EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
		newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
		topFuncp->addNextHere(newfuncp);
		// In the body, call each function if it matches the given scope
		for (FuncMmap::iterator eachIt = it; eachIt!=m_modFuncs.end() && eachIt->first==name; ++eachIt) {
		    it = eachIt;
		    AstCFunc* funcp = eachIt->second;
		    FuncMmap::iterator nextIt2 = eachIt; ++nextIt2;
		    bool moreOfSame =  (nextIt2!=m_modFuncs.end() && nextIt2->first == name);
		    if (!funcp->scopep()) funcp->v3fatalSrc("Not scoped");

		    UINFO(6,"     Wrapping "<<name<<" "<<funcp<<endl);
		    UINFO(6,"  at "<<newfuncp->argTypes()<<" und "<<funcp->argTypes()<<endl);
		    funcp->declPrivate(true);
		    AstNode* argsp = NULL;
		    for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
			if (AstVar* portp = stmtp->castVar()) {
			    if (portp->isIO() && !portp->isFuncReturn()) {
				argsp = argsp->addNextNull(new AstVarRef(portp->fileline(), portp,
									 portp->isOutput()));
			    }
			}
		    }

		    AstNode* returnp = new AstCReturn (funcp->fileline(),
						       new AstCCall (funcp->fileline(),
								     funcp,
								     argsp));

		    if (moreOfSame) {
			AstIf* ifp = new AstIf (funcp->fileline(),
						new AstEq(funcp->fileline(),
							  new AstCMath(funcp->fileline(),
								       "this", 64),
							  new AstCMath(funcp->fileline(),
								       string("&(")
								       +funcp->scopep()->nameVlSym()
								       +")", 64)),
						returnp, NULL);
			newfuncp->addStmtsp(ifp);
		    } else {
			newfuncp->addStmtsp(returnp);
		    }
		}
		// Not really any way the user could do this, and we'd need to come up with some return value
		//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_DISPLAY,
		//				      string("%%Error: ")+name+"() called with bad scope", NULL));
		//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
		if (debug()>=9) newfuncp->dumpTree(cout,"   newfunc: ");
	    } else {
		// Only a single function under this name, we can simply rename it
		UINFO(6,"  Wrapping "<<name<<" just one "<<topFuncp<<endl);
		topFuncp->name(name);
	    }
	}
    }