virtual void visit(AstCFunc* nodep) { iterateChildren(nodep); // Link to global function if (nodep->formCallTree()) { UINFO(4, " formCallTree "<<nodep<<endl); AstCCall* callp = new AstCCall(nodep->fileline(), nodep); callp->argTypes("vlSymsp"); m_finalFuncp->addStmtsp(callp); } }
void addTraceDecl(const VNumRange& arrayRange) { VNumRange bitRange; AstBasicDType* bdtypep = m_traValuep->dtypep()->basicp(); if (bdtypep) bitRange = bdtypep->nrange(); AstTraceDecl* declp = new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traValuep, bitRange, arrayRange); if (m_initSubStmts && v3Global.opt.outputSplitCTrace() && m_initSubStmts > v3Global.opt.outputSplitCTrace()) { m_initSubFuncp = newCFuncSub(m_initFuncp); m_initSubStmts = 0; } m_initSubFuncp->addStmtsp(declp); m_initSubStmts += EmitCBaseCounterVisitor(declp).count(); m_chgFuncp->addStmtsp(new AstTraceInc(m_traVscp->fileline(), declp, m_traValuep->cloneTree(true))); // The full version will get constructed in V3Trace }
virtual void visit(AstFinal* nodep, AstNUser*) { // Relink to CFUNC for the final UINFO(4," FINAL "<<nodep<<endl); if (!nodep->bodysp()) { // Empty, Kill it. nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); return; } ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL); if (!m_scopeFinalp) { m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(), m_namer.scopep()); m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar()); m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n")); m_scopeFinalp->dontCombine(true); m_scopeFinalp->formCallTree(true); m_scopeFinalp->slow(true); m_namer.scopep()->addActivep(m_scopeFinalp); } nodep->unlinkFrBack(); m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName())); m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext()); nodep->deleteTree(); VL_DANGLING(nodep); }
void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p, AstNode* last2p) { // Final node in linked list, maybe null if all statements to be grabbed // Make new function string oldname = m_funcp->name(); string::size_type pos; if ((pos=oldname.find("_common")) != string::npos) { oldname.erase(pos); } if ((pos=oldname.find("__")) != string::npos) { oldname.erase(pos); } AstCFunc* newfuncp = new AstCFunc(node1p->fileline(), oldname+"_common"+cvtToStr(++m_modNFuncs), NULL); m_modp->addStmtp(newfuncp); // Create calls AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp); AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp); // Grab statement bodies AstNRelinker relink1Handle; AstNRelinker relink2Handle; for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) { nextp = walkp->nextp(); if (walkp==node1p) walkp->unlinkFrBack(&relink1Handle); else { walkp->unlinkFrBack(); node1p->addNext(walkp); } if (walkp==last1p) break; } for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) { nextp = walkp->nextp(); if (walkp==node2p) walkp->unlinkFrBack(&relink2Handle); else { walkp->unlinkFrBack(); node2p->addNext(walkp); } if (walkp==last2p) break; } // Move node1 statements to new function newfuncp->addStmtsp(node1p); //newfuncp->dumpTree(cout," newfunctree: "); // Mark node2 statements as dead CombMarkVisitor visitor(node2p); pushDeletep(node2p); // Delete later // Link in new function relink1Handle.relink(call1p); relink2Handle.relink(call2p); // Hash the new function hashFunctions(newfuncp); m_call.addCall(call1p); m_call.addCall(call2p); // If either new statement makes a func with only a single call, replace // the above callers to call it directly replaceOnlyCallFunc(call1p); VL_DANGLING(call1p); replaceOnlyCallFunc(call2p); VL_DANGLING(call2p); }
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); } } }
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; }
virtual void visit(AstTopScope* nodep, AstNUser*) { UINFO(4," TS "<<nodep<<endl); // Clearing AstNode::user1ClearTree(); // Create the change detection function AstScope* scopep = nodep->scopep(); if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n"); m_scopetopp = scopep; // Create change detection function m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "IData"); m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar()); m_chgFuncp->symProlog(true); m_chgFuncp->declPrivate(true); m_scopetopp->addActivep(m_chgFuncp); // We need at least one change detect so we know to emit the correct code m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false)); // nodep->iterateChildren(*this); }
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); } } }
void addToInitial(AstNode* stmtsp) { m_initFuncp->addStmtsp(stmtsp); // add to top level function }
void addToSettleLoop(AstNode* stmtsp) { m_settleFuncp->addStmtsp(stmtsp); // add to top level function }
void addToEvalLoop(AstNode* stmtsp) { m_evalFuncp->addStmtsp(stmtsp); // add to top level function }
void addIgnore(const char* why) { ++m_statIgnSigs; m_initSubFuncp->addStmtsp( new AstComment(m_traVscp->fileline(), "Tracing: "+m_traShowname+" // Ignored: "+why)); }
void addToInitial(AstNode* stmtsp) { if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body else m_initFuncp->addStmtsp(stmtsp); // else add to top level function }
void addToSettleLoop(AstNode* stmtsp) { if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body else m_settleFuncp->addStmtsp(stmtsp); // else add to top level function }