Support --bbox-unsup parsing of nested foreach.
This commit is contained in:
parent
cef56c6fca
commit
6e57076726
|
|
@ -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(); }
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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*/ }
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue