Fix slow compilation of generated sampled value code (#6652)

For handling $past and similar functions, we used to collect sampled
values of variables at the beginning of the main _eval function. If we
have many of these, this can grow _eval very large which can make C++
compilation very slow. Apply usual fix of emitting the necessary code in
a separate function and then splitting it based on size.
This commit is contained in:
Geza Lore 2025-11-06 13:31:40 +00:00 committed by GitHub
parent 47b52800bf
commit f7e12e9219
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 17 deletions

View File

@ -24,6 +24,7 @@
#include "V3Clock.h"
#include "V3Const.h"
#include "V3Sched.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@ -62,7 +63,7 @@ class ClockVisitor final : public VNVisitor {
// NODE STATE
// STATE
AstCFunc* const m_evalp = nullptr; // The '_eval' function
AstCFunc* m_sampleCFuncp = nullptr; // The CFunc to populate with sampled value assignments
// VISITORS
void visit(AstCoverToggle* nodep) override {
@ -98,29 +99,36 @@ class ClockVisitor final : public VNVisitor {
//========== Move sampled assignments
void visit(AstVarScope* nodep) override {
AstVar* const varp = nodep->varp();
if (varp->valuep() && varp->name().substr(0, strlen("__Vsampled")) == "__Vsampled") {
if (!varp->valuep()) return;
if (!VString::startsWith(varp->name(), "__Vsampled")) return;
// Create the containing function on first encounter
if (!m_sampleCFuncp) {
m_sampleCFuncp = V3Sched::util::makeSubFunction(v3Global.rootp(), "_sample", false);
}
FileLine* const flp = nodep->fileline();
AstNodeExpr* const rhsp = VN_AS(varp->valuep()->unlinkFrBack(), NodeExpr);
AstVarRef* const lhsp = new AstVarRef{flp, nodep, VAccess::WRITE};
AstAssign* const assignp = new AstAssign{flp, lhsp, rhsp};
if (AstNode* const stmtsp = m_evalp->stmtsp()) {
stmtsp->addHereThisAsNext(assignp);
} else {
m_evalp->addStmtsp(assignp);
}
m_sampleCFuncp->addStmtsp(new AstAssign{flp, lhsp, rhsp});
varp->direction(VDirection::NONE); // Restore defaults
varp->primaryIO(false);
}
}
//--------------------
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ClockVisitor(AstNetlist* netlistp)
: m_evalp{netlistp->evalp()} {
explicit ClockVisitor(AstNetlist* netlistp) {
iterate(netlistp);
// If we need a sample function, call it at the begining of eval
if (m_sampleCFuncp) {
V3Sched::util::splitCheck(m_sampleCFuncp);
AstCCall* const callp = new AstCCall{m_sampleCFuncp->fileline(), m_sampleCFuncp};
callp->dtypeSetVoid();
netlistp->evalp()->stmtsp()->addHereThisAsNext(callp->makeStmt());
}
}
~ClockVisitor() override = default;
};

View File

@ -39,6 +39,7 @@ module t (/*AUTOARG*/
$write("[%0t] cyc==%0d sum=%x\n", $time, cyc, w[CNT]);
`endif
if (w[CNT] !== `EXPECTED_SUM) $stop;
$display("cyc: %0d $past(cyc): %0d", cyc, $past(cyc));
$write("*-* All Finished *-*\n");
$finish;
end
@ -55,7 +56,7 @@ module sub (input clk, input [31:0] i, output [31:0] z);
assign z = z_tmp;
always @(posedge z_tmp == 32'b11) begin
$display("%m z_tmp[0]: %0d", z_tmp);
$display("%m z_tmp: %0d, $past(z_tmp): $0d", z_tmp, $past(z_tmp));
end
endmodule

View File

@ -125,7 +125,7 @@ test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_clas
test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_2")
# Check combine count
test.file_grep(test.stats, r'Node count, CFILE + (\d+)', (219 if test.vltmt else 205))
test.file_grep(test.stats, r'Node count, CFILE + (\d+)', (239 if test.vltmt else 222))
test.file_grep(test.stats, r'Makefile targets, VM_CLASSES_FAST + (\d+)', 2)
test.file_grep(test.stats, r'Makefile targets, VM_CLASSES_SLOW + (\d+)', 2)