Support --bbox-unsup parsing of nested foreach.

This commit is contained in:
Wilson Snyder 2020-06-09 22:05:06 -04:00
parent cef56c6fca
commit 6e57076726
7 changed files with 176 additions and 30 deletions

View File

@ -1560,6 +1560,25 @@ public:
virtual bool same(const AstNode* samep) const { return true; }
};
class AstSelLoopVars : public AstNode {
// Parser only concept "[id, id, id]" for a foreach statement
// Unlike normal selects elements is a list
public:
AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp)
: ASTGEN_SUPER(fl) {
setOp1p(fromp);
addNOp2p(elementsp);
}
ASTNODE_NODE_FUNCS(SelLoopVars)
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
virtual bool maybePointedTo() const { return false; }
AstNode* fromp() const { return op1p(); }
AstNode* elementsp() const { return op2p(); }
};
class AstSelExtract : public AstNodePreSel {
// Range extraction, gets replaced with AstSel
public:
@ -4224,15 +4243,13 @@ public:
class AstForeach : public AstNodeStmt {
public:
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* varsp, AstNode* bodysp)
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
setOp1p(arrayp);
addNOp2p(varsp);
addNOp4p(bodysp);
}
ASTNODE_NODE_FUNCS(Foreach)
AstNode* arrayp() const { return op1p(); } // op1 = array
AstNode* varsp() const { return op2p(); } // op2 = variable index list
AstNode* arrayp() const { return op1p(); } // op1 = array and index vars
AstNode* bodysp() const { return op4p(); } // op4 = body of loop
virtual bool isGateOptimizable() const { return false; }
virtual int instrCount() const { return instrCountBranch(); }

View File

@ -385,11 +385,50 @@ private:
// FOREACH(array,loopvars,body)
// -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body))
// nodep->dumpTree(cout, "-foreach-old:");
AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext();
AstNode* arrayp = nodep->arrayp();
int dimension = 1;
UINFO(9, "FOREACH " << nodep << endl);
// nodep->dumpTree(cout, "-foreach-in:");
AstNode* newp = nodep->bodysp();
if (newp) newp->unlinkFrBackWithNext();
// Separate iteration vars from base from variable
// Input:
// v--- arrayp
// 1. DOT(DOT(first, second), ASTSELLOOPVARS(third, var0..var1))
// Separated:
// bracketp = ASTSELLOOPVARS(...)
// arrayp = DOT(DOT(first, second), third)
// firstVarp = var0..var1
// Other examples
// 2. ASTSELBIT(first, var0))
// 3. ASTSELLOOPVARS(first, var0..var1))
// 4. DOT(DOT(first, second), ASTSELBIT(third, var0))
AstNode* bracketp = nodep->arrayp();
AstNode* firstVarsp = NULL;
while (AstDot* dotp = VN_CAST(bracketp, Dot)) { bracketp = dotp->rhsp(); }
if (AstSelBit* selp = VN_CAST(bracketp, SelBit)) {
firstVarsp = selp->rhsp()->unlinkFrBackWithNext();
selp->replaceWith(selp->fromp()->unlinkFrBack());
VL_DO_DANGLING(selp->deleteTree(), selp);
} else if (AstSelLoopVars* selp = VN_CAST(bracketp, SelLoopVars)) {
firstVarsp = selp->elementsp()->unlinkFrBackWithNext();
selp->replaceWith(selp->fromp()->unlinkFrBack());
VL_DO_DANGLING(selp->deleteTree(), selp);
} else {
nodep->v3error(
"Syntax error; foreach missing bracketed index variable (IEEE 1800-2017 12.7.3)");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
AstNode* arrayp = nodep->arrayp(); // Maybe different node since bracketp looked
if (!VN_IS(arrayp, ParseRef)) {
// Code below needs to use other then attributes to figure out the bounds
// Also need to deal with queues, etc
arrayp->v3warn(E_UNSUPPORTED, "Unsupported: foreach on non-simple variable reference");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
// Split into for loop
// Must do innermost (last) variable first
AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext();
int dimension = 1;
AstNode* lastVarsp = firstVarsp;
while (lastVarsp->nextp()) {
lastVarsp = lastVarsp->nextp();

View File

@ -3062,7 +3062,7 @@ statement_item<nodep>: // IEEE: statement_item
}
else $$ = new AstWhile($1,$5,NULL); }
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
| yFOREACH '(' idClassForeach '[' loop_variables ']' ')' stmtBlock { $$ = new AstForeach($1,$3,$5,$8); }
| yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); }
//
// // IEEE: jump_statement
| yRETURN ';' { $$ = new AstReturn($1); }
@ -4735,48 +4735,67 @@ idClassSel<nodep>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged va
| packageClassScope idDotted { $$ = $2; BBUNSUP($2, "Unsupported: package scoped id"); }
;
idClassSelForeach<nodep>:
idDottedForeach { $$ = $1; }
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
| yTHIS '.' idDottedForeach { $$ = $3; BBUNSUP($1, "Unsupported: this"); }
| ySUPER '.' idDottedForeach { $$ = $3; BBUNSUP($1, "Unsupported: super"); }
| yTHIS '.' ySUPER '.' idDottedForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); }
// // Expanded: package_scope idForeach
| packageClassScope idDottedForeach { $$ = $2; BBUNSUP($2, "Unsupported: package/class scoped id"); }
;
idDotted<nodep>:
yD_ROOT '.' idDottedMore
{ $$ = new AstDot($2, false, new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "$root"), $3); }
| idDottedMore { $$ = $1; }
;
idDottedForeach<nodep>:
yD_ROOT '.' idDottedMoreForeach
{ $$ = new AstDot($2, false, new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "$root"), $3); }
| idDottedMoreForeach { $$ = $1; }
;
idDottedMore<nodep>:
idArrayed { $$ = $1; }
| idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); }
;
idDottedMoreForeach<nodep>:
idArrayedForeach { $$ = $1; }
| idDottedMoreForeach '.' idArrayedForeach { $$ = new AstDot($2, false, $1, $3); }
;
// Single component of dotted path, maybe [#].
// Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part),
// we'll assume so and cleanup later.
// id below includes:
// enum_identifier
idArrayed<nodep>: // IEEE: id + select
id { $$ = new AstParseRef($<fl>1,VParseRefExp::PX_TEXT,*$1,NULL,NULL); }
id { $$ = new AstParseRef($<fl>1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); }
// // IEEE: id + part_select_range/constant_part_select_range
| idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet.
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); }
| idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet.
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); }
// // IEEE: id + indexed_range/constant_indexed_range
| idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); }
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); }
| idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); }
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); }
;
idClassForeach<nodep>:
idForeach { $$ = $1; }
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
| yTHIS '.' idForeach { $$ = $3; BBUNSUP($1, "Unsupported: this"); }
| ySUPER '.' idForeach { $$ = $3; BBUNSUP($1, "Unsupported: super"); }
| yTHIS '.' ySUPER '.' idForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); }
// // Expanded: package_scope idForeach
| packageClassScope idForeach { $$ = $2; BBUNSUP($2, "Unsupported: package/class scoped id"); }
idArrayedForeach<nodep>: // IEEE: id + select (under foreach expression)
id { $$ = new AstParseRef($<fl>1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); }
// // IEEE: id + part_select_range/constant_part_select_range
| idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet.
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); }
// // IEEE: id + indexed_range/constant_indexed_range
| idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); }
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); }
// // IEEE: loop_variables (under foreach expression)
// // To avoid conflicts we allow expr as first element, must post-check
| idArrayed '[' expr ',' loop_variables ']'
{ $3 = AstNode::addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); }
;
idForeach<nodep>:
varRefBase { $$ = $1; }
| idForeach '.' varRefBase { $$ = new AstDot($2, false, $1, $3); }
;
// VarRef without any dots or vectorizaion
varRefBase<varrefp>:
id { $$ = new AstVarRef($<fl>1,*$1,false);}
@ -6079,7 +6098,7 @@ constraint_expression<nodep>: // ==IEEE: constraint_expression
| yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { $$ = NULL; /*UNSUP*/ }
| yIF '(' expr ')' constraint_set yELSE constraint_set { $$ = NULL; /*UNSUP*/ }
// // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009
| yFOREACH '(' idClassForeach '[' loop_variables ']' ')' constraint_set { $$ = NULL; /*UNSUP*/ }
| yFOREACH '(' idClassSelForeach ')' constraint_set { $$ = NULL; /*UNSUP*/ }
// // soft is 1800-2012
| yDISABLE ySOFT expr/*constraint_primary*/ ';' { $$ = NULL; /*UNSUP*/ }
;

View File

@ -11,11 +11,20 @@ module t (/*AUTOARG*/);
// verilator lint_off LITENDIAN
// verilator lint_off WIDTH
reg [63:0] sum;
reg [63:0] sum; // Checked not in objects
reg [63:0] add;
reg [2:1] [4:3] array [5:6] [7:8];
reg [1:2] [3:4] larray [6:5] [8:7];
bit [31:0] depth1_array [0:0];
typedef struct packed {
reg [1:0] [63:0] subarray;
} str_t;
typedef struct packed {
str_t mid;
} mid_t;
mid_t strarray[3];
function [63:0] crc (input [63:0] sum, input [31:0] a, input [31:0] b, input [31:0] c, input [31:0] d);
crc = {sum[62:0],sum[63]} ^ {4'b0,a[7:0], 4'h0,b[7:0], 4'h0,c[7:0], 4'h0,d[7:0]};
endfunction
@ -87,6 +96,20 @@ module t (/*AUTOARG*/);
end
`checkh(sum, 64'h0020179aa7aa0aaa);
add = 0;
strarray[0].mid.subarray[0] = 1;
strarray[0].mid.subarray[1] = 2;
strarray[1].mid.subarray[0] = 4;
strarray[1].mid.subarray[1] = 5;
strarray[2].mid.subarray[0] = 6;
strarray[2].mid.subarray[1] = 7;
`ifndef VERILATOR // Unsupported
foreach (strarray[s])
foreach (strarray[s].mid.subarray[ss])
add += strarray[s].mid.subarray[ss];
`checkh(add, 'h19);
`endif
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -0,0 +1,7 @@
%Error: t/t_foreach_bad.v:14:7: Syntax error; foreach missing bracketed index variable (IEEE 1800-2017 12.7.3)
14 | foreach (array);
| ^~~~~~~
%Error-UNSUPPORTED: t/t_foreach_bad.v:16:21: Unsupported: foreach on non-simple variable reference
16 | foreach (array.array[a]);
| ^
%Error: Exiting due to

19
test_regress/t/t_foreach_bad.pl Executable file
View File

@ -0,0 +1,19 @@
#!/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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
integer a, b;
reg [2:0][2:0] array;
initial begin
foreach (array); // no index
foreach (array.array[a]); // not supported
$write("*-* All Finished *-*\n");
$finish;
end
endmodule