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,50 +1723,73 @@ 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
|
||||
// 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
|
||||
newFuncpr = nullptr;
|
||||
}
|
||||
if (!newFuncpr && domainp != m_deleteDomainp) {
|
||||
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);
|
||||
callp->argTypes("vlSymsp");
|
||||
activep->addStmtsp(callp);
|
||||
UINFO(6, " New " << newFuncpr << endl);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Move the logic to the function we're creating
|
||||
nodep->unlinkFrBack();
|
||||
if (domainp == m_deleteDomainp) {
|
||||
UINFO(4, " Ordering deleting pre-settled " << nodep << endl);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else {
|
||||
newFuncpr->addStmtsp(nodep);
|
||||
if (v3Global.opt.outputSplitCFuncs()) {
|
||||
// Add in the number of nodes we're adding
|
||||
EmitCBaseCounterVisitor visitor(nodep);
|
||||
newStmtsr += visitor.count();
|
||||
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
|
||||
newFuncpr = nullptr;
|
||||
}
|
||||
if (!newFuncpr && domainp != m_deleteDomainp) {
|
||||
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);
|
||||
// Create top call to it
|
||||
AstCCall* const callp = new AstCCall(nodep->fileline(), newFuncpr);
|
||||
callp->argTypes("vlSymsp");
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
newFuncpr->addStmtsp(nodep);
|
||||
if (v3Global.opt.outputSplitCFuncs()) {
|
||||
// Add in the number of nodes we're adding
|
||||
EmitCBaseCounterVisitor visitor(nodep);
|
||||
newStmtsr += visitor.count();
|
||||
}
|
||||
}
|
||||
|
||||
nodep = nextp;
|
||||
}
|
||||
}
|
||||
return activep;
|
||||
|
Loading…
Reference in New Issue
Block a user