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));
|
return static_cast<T_NodeResult*>(addNext<AstNode, AstNode>(nodep, newp));
|
||||||
}
|
}
|
||||||
inline AstNode* addNext(AstNode* newp);
|
inline AstNode* addNext(AstNode* newp);
|
||||||
inline void addPrev(AstNode* newp);
|
|
||||||
void addNextHere(AstNode* newp); // Insert newp at this->nextp
|
void addNextHere(AstNode* newp); // Insert newp at this->nextp
|
||||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
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
|
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
|
// Inline method implementations
|
||||||
AstNode* AstNode::addNext(AstNode* newp) { return addNext(this, newp); }
|
AstNode* AstNode::addNext(AstNode* newp) { return addNext(this, newp); }
|
||||||
void AstNode::addPrev(AstNode* newp) {
|
|
||||||
replaceWith(newp);
|
|
||||||
newp->addNext(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specialisations of privateTypeTest
|
// Specialisations of privateTypeTest
|
||||||
#include "V3Ast__gen_type_tests.h" // From ./astgen
|
#include "V3Ast__gen_type_tests.h" // From ./astgen
|
||||||
|
|
|
||||||
|
|
@ -2725,6 +2725,26 @@ public:
|
||||||
// * = Add a newline for $display
|
// * = Add a newline for $display
|
||||||
bool addNewline() const { return displayType().addNewline(); }
|
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 {
|
class AstDumpCtl final : public AstNodeStmt {
|
||||||
// $dumpon etc
|
// $dumpon etc
|
||||||
// Parents: expr
|
// Parents: expr
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,14 @@ private:
|
||||||
underp = nodep;
|
underp = nodep;
|
||||||
under_and_next = false; // IE we skip the entire while
|
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 {
|
} else {
|
||||||
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -113,7 +121,7 @@ private:
|
||||||
// Keep any AstVars under the function not under the new JumpLabel
|
// Keep any AstVars under the function not under the new JumpLabel
|
||||||
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
||||||
nextp = 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
|
// Label goes last
|
||||||
blockp->addEndStmtsp(labelp);
|
blockp->addEndStmtsp(labelp);
|
||||||
|
|
@ -189,6 +197,27 @@ private:
|
||||||
iterateAndNextNull(nodep->incsp());
|
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 {
|
void visit(AstForeach* nodep) override {
|
||||||
VL_RESTORER(m_loopp);
|
VL_RESTORER(m_loopp);
|
||||||
{
|
{
|
||||||
|
|
@ -212,14 +241,14 @@ private:
|
||||||
} else {
|
} else {
|
||||||
if (funcp && nodep->lhsp()) {
|
if (funcp && nodep->lhsp()) {
|
||||||
// Set output variable to return value
|
// Set output variable to return value
|
||||||
nodep->addPrev(new AstAssign(
|
nodep->addHereThisAsNext(new AstAssign(
|
||||||
nodep->fileline(),
|
nodep->fileline(),
|
||||||
new AstVarRef(nodep->fileline(), VN_AS(funcp->fvarp(), Var), VAccess::WRITE),
|
new AstVarRef(nodep->fileline(), VN_AS(funcp->fvarp(), Var), VAccess::WRITE),
|
||||||
nodep->lhsp()->unlinkFrBackWithNext()));
|
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||||
}
|
}
|
||||||
// Jump to the end of the function call
|
// Jump to the end of the function call
|
||||||
AstJumpLabel* const labelp = findAddLabel(m_ftaskp, false);
|
AstJumpLabel* const labelp = findAddLabel(m_ftaskp, false);
|
||||||
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
|
nodep->addHereThisAsNext(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
}
|
}
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
|
|
||||||
|
|
@ -3324,11 +3324,7 @@ statement_item<nodep>: // IEEE: statement_item
|
||||||
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile{$1, $3, $5}; }
|
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile{$1, $3, $5}; }
|
||||||
// // for's first ';' is in for_initialization
|
// // for's first ';' is in for_initialization
|
||||||
| statementFor { $$ = $1; }
|
| statementFor { $$ = $1; }
|
||||||
| yDO stmtBlock yWHILE '(' expr ')' ';' { if ($2) {
|
| yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = new AstDoWhile{$1, $5, $2}; }
|
||||||
$$ = $2->cloneTree(true);
|
|
||||||
$$->addNext(new AstWhile($1,$5,$2));
|
|
||||||
}
|
|
||||||
else $$ = new AstWhile($1,$5); }
|
|
||||||
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
|
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
|
||||||
| yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); }
|
| yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); }
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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