Fix jump handling in do while loops (#3731)

This commit is contained in:
Ryszard Rozak 2022-11-09 02:01:08 +01:00 committed by GitHub
parent 2a3eabff73
commit a29d9469da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 298 additions and 13 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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); }
//

View 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

View 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;

View 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

View 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;

View 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