forked from github/verilator
Split procedures to better respect --output-split-cfuncs (#2942)
CFuncs only used to be split at procedure (always/initial/final block), which on occasion can still yield huge output files if they have large procedures. This patch make CFuncs split at statement boundaries within procedures. This has the potential to help a lot, but still does not help if there are huge statements within procedures.
This commit is contained in:
parent
1a6378291a
commit
1422c23434
1
Changes
1
Changes
@ -37,6 +37,7 @@ Verilator 4.202 2021-04-24
|
||||
* Support overlaps in priority case statements (#2864). [Rupert Swarbrick]
|
||||
* Support for null ports (#2875). [Udi Finkelstein]
|
||||
* Optimize large lookup tables to static data (#2925). [Geza Lore]
|
||||
* Split always blocks to better respect --output-split-cfuncs. [Geza Lore]
|
||||
* Fix class unpacked-array compile error (#2774). [Iru Cai]
|
||||
* Fix scope types in FST and VCD traces (#2805). [Alex Torregrosa]
|
||||
* Fix exceeding command-line ar limit (#2834). [Yinan Xu]
|
||||
|
@ -1723,40 +1723,60 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d
|
||||
AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp,
|
||||
AstCFunc*& newFuncpr, int& newStmtsr) {
|
||||
AstActive* activep = nullptr;
|
||||
AstScope* scopep = lvertexp->scopep();
|
||||
AstSenTree* domainp = lvertexp->domainp();
|
||||
AstScope* const scopep = lvertexp->scopep();
|
||||
AstSenTree* const domainp = lvertexp->domainp();
|
||||
AstNode* nodep = lvertexp->nodep();
|
||||
AstNodeModule* modp = VN_CAST(scopep->user1p(), NodeModule); // Stashed by visitor func
|
||||
AstNodeModule* const modp = VN_CAST(scopep->user1p(), NodeModule); // Stashed by visitor func
|
||||
UASSERT(modp, "nullptr");
|
||||
if (VN_IS(nodep, SenTree)) {
|
||||
// Just ignore sensitivities, we'll deal with them when we move statements that need them
|
||||
} else { // Normal logic
|
||||
// Move the logic into a CFunc
|
||||
nodep->unlinkFrBack();
|
||||
|
||||
// Process procedures per statement (unless profCFuncs), so we can split CFuncs within
|
||||
// procedures. Everything else is handled in one go
|
||||
AstNodeProcedure* const procp = VN_CAST(nodep, NodeProcedure);
|
||||
if (procp && !v3Global.opt.profCFuncs()) {
|
||||
nodep = procp->bodysp();
|
||||
pushDeletep(procp);
|
||||
}
|
||||
|
||||
while (nodep) {
|
||||
// Make or borrow a CFunc to contain the new statements
|
||||
if (v3Global.opt.profCFuncs()
|
||||
|| (v3Global.opt.outputSplitCFuncs()
|
||||
&& v3Global.opt.outputSplitCFuncs() < newStmtsr)) {
|
||||
// Put every statement into a unique function to ease profiling or reduce function size
|
||||
// Put every statement into a unique function to ease profiling or reduce function
|
||||
// size
|
||||
newFuncpr = nullptr;
|
||||
}
|
||||
if (!newFuncpr && domainp != m_deleteDomainp) {
|
||||
string name = cfuncName(modp, domainp, scopep, nodep);
|
||||
const string name = cfuncName(modp, domainp, scopep, nodep);
|
||||
newFuncpr = new AstCFunc(nodep->fileline(), name, scopep);
|
||||
newFuncpr->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
newFuncpr->symProlog(true);
|
||||
newStmtsr = 0;
|
||||
if (domainp->hasInitial() || domainp->hasSettle()) newFuncpr->slow(true);
|
||||
scopep->addActivep(newFuncpr);
|
||||
// Where will we be adding the call?
|
||||
activep = new AstActive(nodep->fileline(), name, domainp);
|
||||
// Add a top call to it
|
||||
AstCCall* callp = new AstCCall(nodep->fileline(), newFuncpr);
|
||||
// Create top call to it
|
||||
AstCCall* const callp = new AstCCall(nodep->fileline(), newFuncpr);
|
||||
callp->argTypes("vlSymsp");
|
||||
activep->addStmtsp(callp);
|
||||
// Where will we be adding the call?
|
||||
AstActive* const newActivep = new AstActive(nodep->fileline(), name, domainp);
|
||||
newActivep->addStmtsp(callp);
|
||||
if (!activep) {
|
||||
activep = newActivep;
|
||||
} else {
|
||||
activep->addNext(newActivep);
|
||||
}
|
||||
UINFO(6, " New " << newFuncpr << endl);
|
||||
}
|
||||
|
||||
// Move the logic to the function we're creating
|
||||
nodep->unlinkFrBack();
|
||||
AstNode* const nextp = nodep->nextp();
|
||||
// When processing statements in a procedure, unlink the current statement
|
||||
if (nodep->backp()) nodep->unlinkFrBack();
|
||||
|
||||
if (domainp == m_deleteDomainp) {
|
||||
UINFO(4, " Ordering deleting pre-settled " << nodep << endl);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
@ -1768,6 +1788,9 @@ AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp,
|
||||
newStmtsr += visitor.count();
|
||||
}
|
||||
}
|
||||
|
||||
nodep = nextp;
|
||||
}
|
||||
}
|
||||
return activep;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user