mirror of
https://github.com/verilator/verilator.git
synced 2025-07-31 07:56:10 +00:00
Fix jump handling in do while loops (#3731)
This commit is contained in:
parent
2a3eabff73
commit
a29d9469da
@ -1874,7 +1874,6 @@ public:
|
||||
return static_cast<T_NodeResult*>(addNext<AstNode, AstNode>(nodep, newp));
|
||||
}
|
||||
inline AstNode* addNext(AstNode* newp);
|
||||
inline void addPrev(AstNode* newp);
|
||||
void addNextHere(AstNode* newp); // Insert newp at this->nextp
|
||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||
@ -2207,10 +2206,6 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp);
|
||||
|
||||
// Inline method implementations
|
||||
AstNode* AstNode::addNext(AstNode* newp) { return addNext(this, newp); }
|
||||
void AstNode::addPrev(AstNode* newp) {
|
||||
replaceWith(newp);
|
||||
newp->addNext(this);
|
||||
}
|
||||
|
||||
// Specialisations of privateTypeTest
|
||||
#include "V3Ast__gen_type_tests.h" // From ./astgen
|
||||
|
@ -2725,6 +2725,26 @@ public:
|
||||
// * = Add a newline for $display
|
||||
bool addNewline() const { return displayType().addNewline(); }
|
||||
};
|
||||
class AstDoWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNode
|
||||
// @astgen op3 := stmtsp : List[AstNode]
|
||||
// @astgen op4 := incsp : List[AstNode]
|
||||
public:
|
||||
AstDoWhile(FileLine* fl, AstNode* conditionp, AstNode* stmtsp = nullptr,
|
||||
AstNode* incsp = nullptr)
|
||||
: ASTGEN_SUPER_DoWhile(fl) {
|
||||
condp(conditionp);
|
||||
addStmtsp(stmtsp);
|
||||
addIncsp(incsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstDoWhile;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
// Stop statement searchback here
|
||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
};
|
||||
class AstDumpCtl final : public AstNodeStmt {
|
||||
// $dumpon etc
|
||||
// Parents: expr
|
||||
|
@ -83,6 +83,14 @@ private:
|
||||
underp = nodep;
|
||||
under_and_next = false; // IE we skip the entire while
|
||||
}
|
||||
} else if (AstDoWhile* const dowhilep = VN_CAST(nodep, DoWhile)) {
|
||||
// Handle it the same as AstWhile, because it will be converted to it
|
||||
if (endOfIter) {
|
||||
underp = dowhilep->stmtsp();
|
||||
} else {
|
||||
underp = nodep;
|
||||
under_and_next = false;
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
||||
return nullptr;
|
||||
@ -113,7 +121,7 @@ private:
|
||||
// Keep any AstVars under the function not under the new JumpLabel
|
||||
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
||||
nextp = varp->nextp();
|
||||
if (VN_IS(varp, Var)) blockp->addPrev(varp->unlinkFrBack());
|
||||
if (VN_IS(varp, Var)) blockp->addHereThisAsNext(varp->unlinkFrBack());
|
||||
}
|
||||
// Label goes last
|
||||
blockp->addEndStmtsp(labelp);
|
||||
@ -189,6 +197,27 @@ private:
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
}
|
||||
}
|
||||
void visit(AstDoWhile* nodep) override {
|
||||
// It is converted to AstWhile in this visit method
|
||||
VL_RESTORER(m_loopp);
|
||||
VL_RESTORER(m_loopInc);
|
||||
{
|
||||
m_loopp = nodep;
|
||||
m_loopInc = false;
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
m_loopInc = true;
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
}
|
||||
AstNode* const condp = nodep->condp() ? nodep->condp()->unlinkFrBack() : nullptr;
|
||||
AstNode* const bodyp = nodep->stmtsp() ? nodep->stmtsp()->unlinkFrBack() : nullptr;
|
||||
AstNode* const incsp = nodep->incsp() ? nodep->incsp()->unlinkFrBack() : nullptr;
|
||||
AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp, incsp};
|
||||
nodep->replaceWith(whilep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (bodyp) whilep->addHereThisAsNext(bodyp->cloneTree(false));
|
||||
}
|
||||
void visit(AstForeach* nodep) override {
|
||||
VL_RESTORER(m_loopp);
|
||||
{
|
||||
@ -212,14 +241,14 @@ private:
|
||||
} else {
|
||||
if (funcp && nodep->lhsp()) {
|
||||
// Set output variable to return value
|
||||
nodep->addPrev(new AstAssign(
|
||||
nodep->addHereThisAsNext(new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), VN_AS(funcp->fvarp(), Var), VAccess::WRITE),
|
||||
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||
}
|
||||
// Jump to the end of the function call
|
||||
AstJumpLabel* const labelp = findAddLabel(m_ftaskp, false);
|
||||
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
|
||||
nodep->addHereThisAsNext(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
@ -3324,11 +3324,7 @@ statement_item<nodep>: // IEEE: statement_item
|
||||
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile{$1, $3, $5}; }
|
||||
// // for's first ';' is in for_initialization
|
||||
| statementFor { $$ = $1; }
|
||||
| yDO stmtBlock yWHILE '(' expr ')' ';' { if ($2) {
|
||||
$$ = $2->cloneTree(true);
|
||||
$$->addNext(new AstWhile($1,$5,$2));
|
||||
}
|
||||
else $$ = new AstWhile($1,$5); }
|
||||
| yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = new AstDoWhile{$1, $5, $2}; }
|
||||
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
|
||||
| yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); }
|
||||
//
|
||||
|
6
test_regress/t/t_continue_do_while_bad.out
Normal file
6
test_regress/t/t_continue_do_while_bad.out
Normal file
@ -0,0 +1,6 @@
|
||||
%Warning-INFINITELOOP: t/t_continue_do_while_bad.v:14:7: Infinite loop (condition always true)
|
||||
14 | do begin
|
||||
| ^~
|
||||
... For warning description see https://verilator.org/warn/INFINITELOOP?v=latest
|
||||
... Use "/* verilator lint_off INFINITELOOP */" and lint_on around source to disable this message.
|
||||
%Error: Exiting due to
|
20
test_regress/t/t_continue_do_while_bad.pl
Executable file
20
test_regress/t/t_continue_do_while_bad.pl
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2022 by Antmicro Ltd. 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
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
compile(
|
||||
expect_filename=>$Self->{golden_filename},
|
||||
verilator_flags2=> ['--assert'],
|
||||
fails => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
24
test_regress/t/t_continue_do_while_bad.v
Normal file
24
test_regress/t/t_continue_do_while_bad.v
Normal file
@ -0,0 +1,24 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
function void infinite_loop;
|
||||
do begin
|
||||
continue;
|
||||
end
|
||||
while (1);
|
||||
endfunction
|
||||
|
||||
always @(posedge clk) begin
|
||||
infinite_loop();
|
||||
$stop;
|
||||
end
|
||||
endmodule
|
22
test_regress/t/t_jumps_do_while.pl
Executable file
22
test_regress/t/t_jumps_do_while.pl
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2022 by Antmicro Ltd. 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--assert'],
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
173
test_regress/t/t_jumps_do_while.v
Normal file
173
test_regress/t/t_jumps_do_while.v
Normal file
@ -0,0 +1,173 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
function bit test_1;
|
||||
int iterations = 0;
|
||||
do begin
|
||||
iterations++;
|
||||
break;
|
||||
end
|
||||
while (1);
|
||||
return iterations == 1;
|
||||
endfunction
|
||||
|
||||
function bit test_2;
|
||||
int iterations = 0;
|
||||
do begin
|
||||
break;
|
||||
iterations++;
|
||||
end
|
||||
while (1);
|
||||
return iterations == 0;
|
||||
endfunction
|
||||
|
||||
function bit test_3;
|
||||
do
|
||||
break;
|
||||
while (1);
|
||||
return 1'b1;
|
||||
endfunction
|
||||
|
||||
function bit test_4;
|
||||
int incr = 0;
|
||||
do begin
|
||||
incr++;
|
||||
break;
|
||||
incr++;
|
||||
end
|
||||
while (1);
|
||||
return incr == 1;
|
||||
endfunction
|
||||
|
||||
function bit test_5;
|
||||
int incr = 0;
|
||||
do begin
|
||||
do
|
||||
incr++;
|
||||
while (incr < 9);
|
||||
incr++;
|
||||
break;
|
||||
incr++;
|
||||
end
|
||||
while (1);
|
||||
return incr == 10;
|
||||
endfunction
|
||||
|
||||
function bit test_6;
|
||||
int incr = 0;
|
||||
do begin
|
||||
do begin
|
||||
incr += 1;
|
||||
incr += 2;
|
||||
end
|
||||
while (incr < 9);
|
||||
incr++;
|
||||
break;
|
||||
incr++;
|
||||
end
|
||||
while (1);
|
||||
return incr == 10;
|
||||
endfunction
|
||||
|
||||
function bit test_7;
|
||||
int incr = 0;
|
||||
do begin
|
||||
do begin
|
||||
incr += 1;
|
||||
break;
|
||||
incr += 2;
|
||||
end
|
||||
while (incr < 9);
|
||||
incr++;
|
||||
break;
|
||||
incr++;
|
||||
end
|
||||
while (1);
|
||||
return incr == 2;
|
||||
endfunction
|
||||
|
||||
function bit test_8;
|
||||
int incr = 0;
|
||||
do begin
|
||||
incr++;
|
||||
continue;
|
||||
incr++;
|
||||
end
|
||||
while (0);
|
||||
return incr == 1;
|
||||
endfunction
|
||||
|
||||
function bit test_9;
|
||||
int incr = 0;
|
||||
do begin
|
||||
incr++;
|
||||
continue;
|
||||
incr++;
|
||||
end
|
||||
while (incr < 5);
|
||||
return incr == 5;
|
||||
endfunction
|
||||
|
||||
function bit test_10;
|
||||
do begin
|
||||
continue;
|
||||
end
|
||||
while (0);
|
||||
return 1'b1;
|
||||
endfunction
|
||||
|
||||
function bit test_11;
|
||||
int incr = 0;
|
||||
do begin
|
||||
do
|
||||
incr++;
|
||||
while (0);
|
||||
incr++;
|
||||
continue;
|
||||
incr++;
|
||||
end
|
||||
while (incr < 11);
|
||||
return incr == 12;
|
||||
endfunction
|
||||
|
||||
function bit test_12;
|
||||
int incr = 0;
|
||||
do begin
|
||||
do begin
|
||||
incr++;
|
||||
continue;
|
||||
incr++;
|
||||
end
|
||||
while (0);
|
||||
incr++;
|
||||
continue;
|
||||
incr++;
|
||||
end
|
||||
while (incr < 11);
|
||||
return incr == 12;
|
||||
endfunction
|
||||
|
||||
always @(posedge clk) begin
|
||||
bit [11:0] results = {test_1(), test_2(), test_3(), test_4(), test_5(),
|
||||
test_6(), test_7(), test_8(), test_9(), test_10(),
|
||||
test_11(), test_12()};
|
||||
|
||||
if (results == '1) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else begin
|
||||
$write("Results: %b\n", results);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user