Fix splitting eval functions with --output-split-cfuncs (#2368).

This commit is contained in:
Wilson Snyder 2020-08-23 22:21:40 -04:00
parent 4003e01283
commit f7f3d3fd43
4 changed files with 126 additions and 8 deletions

View File

@ -19,6 +19,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix class constructor error on assignments to const.
**** Fix splitting eval functions with --output-split-cfuncs (#2368). [Geza Lore]
* Verilator 4.040 2020-08-15

View File

@ -160,6 +160,43 @@ private:
m_lastSenp = nullptr;
m_lastIfp = nullptr;
}
void splitCheck(AstCFunc* ofuncp) {
if (!v3Global.opt.outputSplitCFuncs() || !ofuncp->stmtsp()) return;
if (EmitCBaseCounterVisitor(ofuncp->stmtsp()).count() < v3Global.opt.outputSplitCFuncs())
return;
int funcnum = 0;
int func_stmts = 0;
AstCFunc* funcp = nullptr;
// Unlink all statements, then add item by item to new sub-functions
AstBegin* tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext()};
if (ofuncp->finalsp()) tempp->addStmtsp(ofuncp->finalsp()->unlinkFrBackWithNext());
while (tempp->stmtsp()) {
AstNode* itemp = tempp->stmtsp()->unlinkFrBack();
int stmts = EmitCBaseCounterVisitor(itemp).count();
if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) {
// Make a new function
funcp = new AstCFunc{ofuncp->fileline(), ofuncp->name() + cvtToStr(++funcnum),
m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->slow(ofuncp->slow());
m_topScopep->scopep()->addActivep(funcp);
//
AstCCall* callp = new AstCCall{funcp->fileline(), funcp};
callp->argTypes("vlSymsp");
ofuncp->addStmtsp(callp);
func_stmts = 0;
}
funcp->addStmtsp(itemp);
func_stmts += stmts;
}
VL_DO_DANGLING(tempp->deleteTree(), tempp);
}
// VISITORS
virtual void visit(AstTopScope* nodep) override {
@ -172,28 +209,29 @@ private:
AstNode::user1ClearTree();
// Make top functions
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval", m_scopep);
AstCFunc* funcp = new AstCFunc{nodep->fileline(), "_eval", m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_evalFuncp = funcp;
}
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_initial", m_scopep);
AstCFunc* funcp
= new AstCFunc{nodep->fileline(), "_eval_initial", m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->slow(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_initFuncp = funcp;
}
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "final", m_scopep);
AstCFunc* funcp = new AstCFunc{nodep->fileline(), "final", m_topScopep->scopep()};
funcp->skipDecl(true);
funcp->dontCombine(true);
funcp->slow(true);
@ -204,22 +242,29 @@ private:
+ " = this->__VlSymsp;\n"));
funcp->addInitsp(
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_finalFuncp = funcp;
}
{
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_settle", m_scopep);
AstCFunc* funcp
= new AstCFunc{nodep->fileline(), "_eval_settle", m_topScopep->scopep()};
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->dontCombine(true);
funcp->slow(true);
funcp->isStatic(true);
funcp->symProlog(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_topScopep->scopep()->addActivep(funcp);
m_settleFuncp = funcp;
}
// Process the activates
iterateChildren(nodep);
UINFO(4, " TOPSCOPE iter done " << nodep << endl);
// Split large functions
splitCheck(m_evalFuncp);
splitCheck(m_initFuncp);
splitCheck(m_finalFuncp);
splitCheck(m_settleFuncp);
// Done, clear so we can detect errors
UINFO(4, " TOPSCOPEDONE " << nodep << endl);
clearLastSen();

View File

@ -0,0 +1,40 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
sub check_evals {
my $got = 0;
foreach my $file (glob("$Self->{obj_dir}/*.cpp")) {
my $fh = IO::File->new("<$file");
local $/; undef $/;
my $wholefile = <$fh>;
if ($wholefile =~ /::_eval[0-9]+/) {
++$got;
}
}
$got >= 3 or error("Too few _eval functions found: $got");
}
scenarios(vlt_all => 1);
compile(
v_flags2 => ["--output-split 1 --output-split-cfuncs 1 --exe ../$Self->{main_filename}"],
# verilator_make_gmake => 0,
);
# Very slow to compile, so generally skip it
execute(
check_finished => 1,
);
check_evals();
ok(1);
1;

View File

@ -0,0 +1,31 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2005 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Outputs
cnt0, cnt1,
// Inputs
clk, clk1
);
input clk;
input clk1;
output int cnt0;
output int cnt1;
always @ (posedge clk) cnt0 <= cnt0 + 1;
always @ (posedge clk1) cnt1 <= cnt1 + 1;
final if (cnt0 == 0) $stop;
final if (cnt1 != 0) $stop;
always_comb begin
if (cnt0==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule