From 13f6c5a9346737d986eeedfe9f407ff3456aede8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 17 Nov 2008 17:13:57 -0500 Subject: [PATCH] Fix --output-split-cfuncs to also split trace code. --- Changes | 2 + src/V3Ast.h | 9 +++- src/V3EmitC.cpp | 102 +++++++++++++++++++++++++------------------- src/V3EmitCBase.h | 2 +- src/V3Options.cpp | 9 ++++ src/V3Options.h | 2 + src/V3Trace.cpp | 83 +++++++++++++++++++++++++++++++---- src/V3TraceDecl.cpp | 84 ++++++++++++++++++++++-------------- test_sp/Makefile | 6 ++- 9 files changed, 213 insertions(+), 86 deletions(-) diff --git a/Changes b/Changes index acf4b4fa0..4a59529d9 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Optimize two-level shift and and/or trees, +23% on one test. +**** Fix --output-split-cfuncs to also split trace code. [Niranjan Prabhu] + **** Fix 'bad select range' warning missing some cases, bug43. [Lane Brooks] * Verilator 3.681 2008/11/12 diff --git a/src/V3Ast.h b/src/V3Ast.h index 73a036f2b..06dd2196c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -79,14 +79,21 @@ public: enum en { NORMAL, TRACE_INIT, + TRACE_INIT_SUB, TRACE_FULL, - TRACE_CHANGE + TRACE_FULL_SUB, + TRACE_CHANGE, + TRACE_CHANGE_SUB }; enum en m_e; inline AstCFuncType () {}; inline AstCFuncType (en _e) : m_e(_e) {}; explicit inline AstCFuncType (int _e) : m_e(static_cast(_e)) {}; operator en () const { return m_e; }; + // METHODS + bool isTrace() const { return (m_e==TRACE_INIT || m_e==TRACE_INIT_SUB + || m_e==TRACE_FULL || m_e==TRACE_FULL_SUB + || m_e==TRACE_CHANGE || m_e==TRACE_CHANGE_SUB); } }; inline bool operator== (AstCFuncType lhs, AstCFuncType rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator== (AstCFuncType lhs, AstCFuncType::en rhs) { return (lhs.m_e == rhs); } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index b3fb40cbe..8406bf6f7 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -72,11 +72,21 @@ private: bool m_suppressSemi; AstVarRef* m_wideTempRefp; // Variable that _WW macros should be setting vector m_ctorVarsVec; // All variables in constructor order + int m_splitSize; // # of cfunc nodes placed into output file + int m_splitFilenum; // File number being created, 0 = primary public: EmitCoverIds m_coverIds; // Coverage ID remapping public: //int debug() { return 9; } + // ACCESSORS + int splitFilenum() { return m_splitFilenum; } + int splitFilenumInc() { m_splitSize = 0; return ++m_splitFilenum; } + int splitSize() { return m_splitSize; } + void splitSizeInc(AstNode* nodep) { m_splitSize += EmitCBaseCounterVisitor(nodep).count(); } + bool splitNeeded() { return (splitSize() && v3Global.opt.outputSplit() > 1 + && v3Global.opt.outputSplit() < splitSize()); } + // METHODS void displayNode(AstNode* nodep, const string& vformat, AstNode* exprsp, bool isScan); void displayEmit(AstNode* nodep, bool isScan); @@ -542,6 +552,8 @@ public: EmitCStmts() { m_suppressSemi = false; m_wideTempRefp = NULL; + m_splitSize = 0; + m_splitFilenum = 0; } virtual ~EmitCStmts() {} }; @@ -555,8 +567,6 @@ class EmitCImp : EmitCStmts { vector m_blkChangeDetVec; // All encountered changes in block bool m_slow; // Creating __Slow file bool m_fast; // Creating non __Slow file (or both) - int m_splitSize; // # of cfunc nodes placed into output file - int m_splitFilenum; // File number being created, 0 = primary //--------------------------------------- // METHODS @@ -628,16 +638,14 @@ class EmitCImp : EmitCStmts { //--------------------------------------- // VISITORS virtual void visit(AstCFunc* nodep, AstNUser*) { - if (nodep->funcType() == AstCFuncType::TRACE_INIT - || nodep->funcType() == AstCFuncType::TRACE_FULL - || nodep->funcType() == AstCFuncType::TRACE_CHANGE) { - return; // Handled specially + if (nodep->funcType().isTrace()) { + return; // TRACE_* handled specially } if (!(nodep->slow() ? m_slow : m_fast)) return; m_blkChangeDetVec.clear(); - m_splitSize += EmitCBaseCounterVisitor(nodep).count(); + splitSizeInc(nodep); puts("\n"); puts(nodep->rtnTypeVoid()); puts(" "); @@ -739,7 +747,6 @@ class EmitCImp : EmitCStmts { void emitIntFuncDecls(AstModule* modp); // High level void emitImp(AstModule* modp); - void emitImpBottom(AstModule* modp); void emitStaticDecl(AstModule* modp); void emitWrapEval(AstModule* modp); void emitInt(AstModule* modp); @@ -748,15 +755,12 @@ class EmitCImp : EmitCStmts { public: EmitCImp() { m_modp = NULL; - m_splitSize = 0; - m_splitFilenum = 0; } virtual ~EmitCImp() {} void main(AstModule* modp, bool slow, bool fast); void mainDoFunc(AstCFunc* nodep) { nodep->accept(*this); } - int splitSize() { return m_splitSize; } }; //###################################################################### @@ -1646,25 +1650,25 @@ void EmitCImp::emitImp(AstModule* modp) { // Us puts("#include \""+ symClassName() +".h\"\n"); - if (optSystemPerl() && (m_splitFilenum || !m_fast)) { + if (optSystemPerl() && (splitFilenum() || !m_fast)) { puts("\n"); puts("SP_MODULE_CONTINUED("+modClassName(modp)+");\n"); } emitTextSection(AstType::SCIMPHDR); - if (m_slow && m_splitFilenum==0) { + if (m_slow && splitFilenum()==0) { puts("\n//--------------------\n"); puts("// STATIC VARIABLES\n\n"); emitVarList(modp->stmtsp(), EVL_ALL, modClassName(modp)); } - if (m_fast && m_splitFilenum==0) { + if (m_fast && splitFilenum()==0) { emitTextSection(AstType::SCIMP); emitStaticDecl(modp); } - if (m_slow && m_splitFilenum==0) { + if (m_slow && splitFilenum()==0) { puts("\n//--------------------\n"); emitCtorImp(modp); emitConfigureImp(modp); @@ -1672,7 +1676,7 @@ void EmitCImp::emitImp(AstModule* modp) { emitCoverageImp(modp); } - if (m_fast && m_splitFilenum==0) { + if (m_fast && splitFilenum()==0) { if (modp->isTop()) { emitStaticDecl(modp); puts("\n//--------------------\n"); @@ -1681,7 +1685,7 @@ void EmitCImp::emitImp(AstModule* modp) { } } - if (m_fast && m_splitFilenum==0) { + if (m_fast && splitFilenum()==0) { if (v3Global.opt.trace() && optSystemPerl() && m_modp->isTop()) { puts("\n"); puts("\n/*AUTOTRACE(__MODULE__,recurse,activity,exists)*/\n\n"); @@ -1693,9 +1697,6 @@ void EmitCImp::emitImp(AstModule* modp) { puts("// Internal Methods\n"); } -void EmitCImp::emitImpBottom(AstModule* modp) { -} - //###################################################################### void EmitCImp::main(AstModule* modp, bool slow, bool fast) { @@ -1741,22 +1742,17 @@ void EmitCImp::main(AstModule* modp, bool slow, bool fast) { for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (AstCFunc* funcp = nodep->castCFunc()) { - if (v3Global.opt.outputSplit() > 1 && splitSize() - && v3Global.opt.outputSplit() < splitSize()) { + if (splitNeeded()) { // Close old file - emitImpBottom (modp); delete m_ofp; m_ofp=NULL; - // Open a new file - m_splitSize = 0; - m_ofp = newOutCFile (modp, !m_fast, true/*source*/, ++m_splitFilenum); + m_ofp = newOutCFile (modp, !m_fast, true/*source*/, splitFilenumInc()); emitImp (modp); } mainDoFunc(funcp); } } - emitImpBottom (modp); delete m_ofp; m_ofp=NULL; } @@ -1766,7 +1762,24 @@ void EmitCImp::main(AstModule* modp, bool slow, bool fast) { class EmitCTrace : EmitCStmts { AstCFunc* m_funcp; // Function we're in now bool m_slow; // Making slow file + // METHODS + void newOutCFile(int filenum) { + string filename = (v3Global.opt.makeDir()+"/"+ topClassName() + + (m_slow?"__Trace__Slow":"__Trace")); + if (filenum) filename += "__"+cvtToStr(filenum); + filename += ".cpp"; + + AstCFile* cfilep = newCFile(filename, m_slow, true/*source*/); + cfilep->support(true); + + if (m_ofp) v3fatalSrc("Previous file not closed"); + m_ofp = new V3OutCFile (filename); + m_ofp->putsHeader(); + + emitTraceHeader(); + } + void emitTraceHeader() { // Includes if (optSystemPerl()) { @@ -1857,7 +1870,9 @@ class EmitCTrace : EmitCStmts { void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) { nodep->precondsp()->iterateAndNext(*this); - string full = (m_funcp->funcType() == AstCFuncType::TRACE_FULL) ? "full":"chg"; + string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL + || m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB) + ? "full":"chg"); if (nodep->isWide() || emitTraceIsScWide(nodep)) { puts("vcdp->"+full+"Array"); } else if (nodep->isQuad()) { @@ -1908,11 +1923,18 @@ class EmitCTrace : EmitCStmts { } virtual void visit(AstCFunc* nodep, AstNUser*) { if (nodep->slow() != m_slow) return; - if (nodep->funcType() == AstCFuncType::TRACE_INIT - || nodep->funcType() == AstCFuncType::TRACE_FULL - || nodep->funcType() == AstCFuncType::TRACE_CHANGE) { + if (nodep->funcType().isTrace()) { // TRACE_* m_funcp = nodep; + if (splitNeeded()) { + // Close old file + delete m_ofp; m_ofp=NULL; + // Open a new file + newOutCFile (splitFilenumInc()); + } + + splitSizeInc(nodep); + puts("\n"); puts(nodep->rtnTypeVoid()); puts(" "); puts(topClassName()+"::"+nodep->name() @@ -1924,8 +1946,11 @@ class EmitCTrace : EmitCStmts { puts("if (0 && vcdp && c) {} // Prevent unused\n"); if (nodep->funcType() == AstCFuncType::TRACE_INIT) { puts("vcdp->module(vlSymsp->name()); // Setup signal names\n"); + } else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) { } else if (nodep->funcType() == AstCFuncType::TRACE_FULL) { + } else if (nodep->funcType() == AstCFuncType::TRACE_FULL_SUB) { } else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE) { + } else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) { } else nodep->v3fatalSrc("Bad Case"); if (nodep->initsp()) puts("// Variables\n"); @@ -1935,8 +1960,6 @@ class EmitCTrace : EmitCStmts { puts("// Body\n"); puts("{\n"); - // Do the statements Note not from this node, but the TRACE_INIT's. - // That saved us from having 3 copies of all of the TRACEs nodep->stmtsp()->iterateAndNext(*this); puts("}\n"); if (nodep->finalsp()) puts("// Final\n"); @@ -1978,23 +2001,14 @@ public: virtual ~EmitCTrace() {} void main() { // Put out the file - string filename = (v3Global.opt.makeDir()+"/"+ topClassName() - + (m_slow?"__Trace__Slow.cpp":"__Trace.cpp")); - AstCFile* cfilep = newCFile(filename, m_slow, true/*source*/); - cfilep->support(true); - - V3OutCFile of (filename); - of.putsHeader(); - m_ofp = &of; - - emitTraceHeader(); + newOutCFile(0); if (m_slow) emitTraceSlow(); else emitTraceFast(); v3Global.rootp()->accept(*this); - m_ofp = NULL; + delete m_ofp; m_ofp=NULL; } }; diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 55aeb323a..fea68e139 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -137,7 +137,7 @@ public: }; //###################################################################### -// Fileize state, as a visitor of each AstNode +// Count operations under the given node, as a visitor of each AstNode class EmitCBaseCounterVisitor : public AstNVisitor { private: diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 496cc0f57..efdede325 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -568,6 +568,14 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) { else if ( !strcmp (sw, "-output-split-cfuncs") ) { shift; m_outputSplitCFuncs = atoi(argv[i]); + if (m_outputSplitCFuncs && (!m_outputSplitCTrace + || m_outputSplitCTrace>m_outputSplitCFuncs)) { + m_outputSplitCTrace = m_outputSplitCFuncs; + } + } + else if ( !strcmp (sw, "-output-split-ctrace") ) { // Undocumented optimization tweak + shift; + m_outputSplitCTrace = atoi(argv[i]); } else if ( !strcmp (sw, "-trace-depth") ) { shift; @@ -873,6 +881,7 @@ V3Options::V3Options() { m_inlineMult = 2000; m_outputSplit = 0; m_outputSplitCFuncs = 0; + m_outputSplitCTrace = 0; m_traceDepth = 0; m_unrollCount = 64; m_unrollStmts = 20; diff --git a/src/V3Options.h b/src/V3Options.h index 5cb20933e..892246ade 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -114,6 +114,7 @@ class V3Options { int m_inlineMult; // main switch: --inline-mult int m_outputSplit; // main switch: --output-split int m_outputSplitCFuncs;// main switch: --output-split-cfuncs + int m_outputSplitCTrace;// main switch: --output-split-ctrace int m_traceDepth; // main switch: --trace-depth int m_unrollCount; // main switch: --unroll-count int m_unrollStmts; // main switch: --unroll-stmts @@ -209,6 +210,7 @@ class V3Options { int inlineMult() const { return m_inlineMult; } int outputSplit() const { return m_outputSplit; } int outputSplitCFuncs() const { return m_outputSplitCFuncs; } + int outputSplitCTrace() const { return m_outputSplitCTrace; } int traceDepth() const { return m_traceDepth; } int unrollCount() const { return m_unrollCount; } int unrollStmts() const { return m_unrollStmts; } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index f7079ca2a..405229de9 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -168,16 +168,23 @@ private: AstTraceInc* m_tracep; // Trace function adding to graph AstCFunc* m_initFuncp; // Trace function we add statements to AstCFunc* m_fullFuncp; // Trace function we add statements to + AstCFunc* m_fullSubFuncp; // Trace function we add statements to (under full) + int m_fullSubStmts; // Statements under function being built AstCFunc* m_chgFuncp; // Trace function we add statements to + AstCFunc* m_chgSubFuncp; // Trace function we add statements to (under full) + AstNode* m_chgSubParentp;// Which node has call to m_chgSubFuncp + int m_chgSubStmts; // Statements under function being built AstVarScope* m_activityVscp; // Activity variable uint32_t m_code; // Trace ident code# being assigned V3Graph m_graph; // Var/CFunc tracking TraceActivityVertex* m_alwaysVtxp; // "Always trace" vertex bool m_finding; // Pass one of algorithm? + int m_funcNum; // Function number being built V3Double0 m_statChgSigs; // Statistic tracking V3Double0 m_statUniqSigs; // Statistic tracking V3Double0 m_statUniqCodes;// Statistic tracking + //int debug() { return 9; } // METHODS @@ -321,6 +328,50 @@ private: } } + AstCFunc* newCFunc(AstCFuncType type, const string& name, AstCFunc* basep) { + AstCFunc* funcp = new AstCFunc(basep->fileline(), name, basep->scopep()); + funcp->slow(basep->slow()); + funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); + funcp->funcType(type); + funcp->symProlog(true); + basep->addNext(funcp); + UINFO(5," Newfunc "<name()+"__"+cvtToStr(++m_funcNum); + AstCFunc* funcp = NULL; + if (basep->funcType()==AstCFuncType::TRACE_FULL) { + funcp = newCFunc(AstCFuncType::TRACE_FULL_SUB, name, basep); + } else if (basep->funcType()==AstCFuncType::TRACE_CHANGE) { + funcp = newCFunc(AstCFuncType::TRACE_CHANGE_SUB, name, basep); + } else { + basep->v3fatalSrc("Strange base function type"); + } + AstCCall* callp = new AstCCall(funcp->fileline(), funcp); + callp->argTypes("vlSymsp, vcdp, code"); + if (callfromp->castCFunc()) { + callfromp->castCFunc()->addStmtsp(callp); + } else if (callfromp->castIf()) { + callfromp->castIf()->addIfsp(callp); + } else { + callfromp->v3fatalSrc("Unknown caller node type"); // Where to add it?? + } + return funcp; + } + void addToChgSub(AstNode* underp, AstNode* stmtsp) { + if (!m_chgSubFuncp + || (m_chgSubParentp != underp) + || (m_chgSubStmts && v3Global.opt.outputSplitCTrace() + && m_chgSubStmts > v3Global.opt.outputSplitCTrace())) { + m_chgSubFuncp = newCFuncSub(m_chgFuncp, underp); + m_chgSubParentp = underp; + m_chgSubStmts = 0; + } + m_chgSubFuncp->addStmtsp(stmtsp); + m_chgSubStmts += EmitCBaseCounterVisitor(stmtsp).count(); + } + void putTracesIntoTree() { // Form a sorted list of the traces we are interested in UINFO(9,"Making trees\n"); @@ -365,7 +416,7 @@ private: // Put TRACEs back into the tree const ActCodeSet* lastactp = NULL; - AstNode* lastnodep = NULL; + AstNode* ifnodep = NULL; for (TraceVec::iterator it = traces.begin(); it!=traces.end(); ++it) { const ActCodeSet& actset = it->first; TraceTraceVertex* vvertexp = it->second; @@ -381,11 +432,10 @@ private: vvertexp->nodep()->v3fatalSrc("If never, needChg=0 and shouldn't need to add."); } else if (actset.find(TraceActivityVertex::ACTIVITY_ALWAYS) != actset.end()) { // Must always set it; add to base of function - m_chgFuncp->addStmtsp(addp); - } else if (lastactp && actset == *lastactp && lastnodep) { + addToChgSub(m_chgFuncp, addp); + } else if (lastactp && actset == *lastactp && ifnodep) { // Add to last statement we built - lastnodep->addNext(addp); - lastnodep = addp; + addToChgSub(ifnodep, addp); } else { // Build a new IF statement FileLine* fl = addp->fileline(); @@ -398,11 +448,13 @@ private: if (condp) condp = new AstOr (fl, condp, selp); else condp = selp; } - AstIf* ifp = new AstIf (fl, condp, addp, NULL); + AstIf* ifp = new AstIf (fl, condp, NULL, NULL); ifp->branchPred(AstBranchPred::UNLIKELY); m_chgFuncp->addStmtsp(ifp); lastactp = &actset; - lastnodep = addp; + ifnodep = ifp; + + addToChgSub(ifnodep, addp); } } } @@ -459,7 +511,16 @@ private: m_statChgSigs++; incAddp = nodep->cloneTree(true); } - m_fullFuncp->addStmtsp(nodep); + + if (!m_fullSubFuncp + || (m_fullSubStmts && v3Global.opt.outputSplitCTrace() + && m_fullSubStmts > v3Global.opt.outputSplitCTrace())) { + m_fullSubFuncp = newCFuncSub(m_fullFuncp, m_fullFuncp); + m_fullSubStmts = 0; + } + + m_fullSubFuncp->addStmtsp(nodep); + m_fullSubStmts += EmitCBaseCounterVisitor(nodep).count(); } else { // Duplicates don't need a TraceInc pushDeletep(nodep); nodep=NULL; @@ -622,7 +683,13 @@ public: m_alwaysVtxp = NULL; m_initFuncp = NULL; m_fullFuncp = NULL; + m_fullSubFuncp = NULL; + m_fullSubStmts = 0; m_chgFuncp = NULL; + m_chgSubFuncp = NULL; + m_chgSubParentp = NULL; + m_chgSubStmts = 0; + m_funcNum = 0; nodep->accept(*this); } virtual ~TraceVisitor() { diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 4b0345f6b..af44c73d3 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -47,8 +47,12 @@ private: AstModule* m_modp; // Current module AstScope* m_scopetopp; // Current top scope AstCFunc* m_initFuncp; // Trace function being built + AstCFunc* m_initSubFuncp; // Trace function being built (under m_init) + int m_initSubStmts; // Number of statements in function AstCFunc* m_fullFuncp; // Trace function being built AstCFunc* m_chgFuncp; // Trace function being built + int m_funcNum; // Function number being built + V3Double0 m_statSigs; // Statistic tracking V3Double0 m_statIgnSigs; // Statistic tracking //int debug() { return 9; } @@ -69,37 +73,43 @@ private: return NULL; } + AstCFunc* newCFunc(AstCFuncType type, const string& name, bool slow) { + AstCFunc* funcp = new AstCFunc(m_scopetopp->fileline(), name, m_scopetopp); + funcp->slow(slow); + funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); + funcp->funcType(type); + funcp->symProlog(true); + m_scopetopp->addActivep(funcp); + UINFO(5," Newfunc "<name()+"__"+cvtToStr(++m_funcNum); + AstCFunc* funcp = NULL; + if (basep->funcType()==AstCFuncType::TRACE_INIT) { + funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow()); + } else { + basep->v3fatalSrc("Strange base function type"); + } + AstCCall* callp = new AstCCall(funcp->fileline(), funcp); + callp->argTypes("vlSymsp, vcdp, code"); + basep->addStmtsp(callp); + return funcp; + } + void addCFuncStmt(AstCFunc* basep, AstNode* nodep) { + basep->addStmtsp(nodep); + } + // VISITORS virtual void visit(AstTopScope* nodep, AstNUser*) { m_scopetopp = nodep->scopep(); - // The container for m_traceFuncp must be made first - { - AstCFunc* funcp = new AstCFunc(nodep->fileline(), "traceInitThis", m_scopetopp); - funcp->slow(true); - funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); - funcp->funcType(AstCFuncType::TRACE_INIT); - funcp->symProlog(true); - m_scopetopp->addActivep(funcp); - m_initFuncp = funcp; - UINFO(5," Newfunc "<fileline(), "traceFullThis", m_scopetopp); - funcp->slow(true); - funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); - funcp->funcType(AstCFuncType::TRACE_FULL); - funcp->symProlog(true); - m_scopetopp->addActivep(funcp); - m_fullFuncp = funcp; - } - { - AstCFunc* funcp = new AstCFunc(nodep->fileline(), "traceChgThis", m_scopetopp); - funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); - funcp->funcType(AstCFuncType::TRACE_CHANGE); - funcp->symProlog(true); - m_scopetopp->addActivep(funcp); - m_chgFuncp = funcp; - } + // Make containers for TRACEDECLs first + m_initFuncp = newCFunc(AstCFuncType::TRACE_INIT, "traceInitThis", true); + m_fullFuncp = newCFunc(AstCFuncType::TRACE_FULL, "traceFullThis", true); + m_chgFuncp = newCFunc(AstCFuncType::TRACE_CHANGE, "traceChgThis", false); + // + m_initSubFuncp = newCFuncSub(m_initFuncp); + // And find variables nodep->iterateChildren(*this); } virtual void visit(AstVarScope* nodep, AstNUser*) { @@ -111,10 +121,10 @@ private: // Compute show name string showname = scopep->prettyName() + "." + varp->prettyName(); if (showname.substr(0,4) == "TOP.") showname.replace(0,4,""); - if (!m_initFuncp) nodep->v3fatalSrc("NULL"); + if (!m_initSubFuncp) nodep->v3fatalSrc("NULL"); if (varIgnoreTrace(varp)) { m_statIgnSigs++; - m_initFuncp->addStmtsp( + m_initSubFuncp->addStmtsp( new AstComment(nodep->fileline(), "Tracing: "+showname+" // Ignored: "+varIgnoreTrace(varp))); } else { @@ -123,7 +133,16 @@ private: if (nodep->valuep()) valuep=nodep->valuep()->cloneTree(true); else valuep = new AstVarRef(nodep->fileline(), nodep, false); AstTraceDecl* declp = new AstTraceDecl(nodep->fileline(), showname, varp); - m_initFuncp->addStmtsp(declp); + + 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(nodep->fileline(), declp, valuep)); // The full version will get constructed in V3Trace } @@ -139,8 +158,11 @@ public: TraceDeclVisitor(AstNetlist* nodep) { m_scopetopp = NULL; m_initFuncp = NULL; + m_initSubFuncp = NULL; + m_initSubStmts = 0; m_fullFuncp = NULL; m_chgFuncp = NULL; + m_funcNum = 0; nodep->accept(*this); } virtual ~TraceDeclVisitor() { diff --git a/test_sp/Makefile b/test_sp/Makefile index 1a0fae296..e422fed6e 100644 --- a/test_sp/Makefile +++ b/test_sp/Makefile @@ -28,7 +28,11 @@ test_debug: prep_dbg preproc compile_dbg run coverage test_nopublic: prep_dbg_np preproc compile_dbg run coverage V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc -VERILATOR_FLAGS = --public --sp --coverage --stats --trace $(V_FLAGS) top.v + +# Note the --public --output-split-cfunc is here for testing only, +# Avoid using these settings in real application Makefiles! +VERILATOR_FLAGS = --public --output-split-cfuncs 100 --output-split 100 \ + --sp --coverage --stats --trace $(V_FLAGS) top.v prep: $(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)