From eaea5e7939c44f920d8e147864a96cfb8d1b0ed6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Oct 2022 21:28:28 +0200 Subject: [PATCH 1/4] Print error if foreach loops variables exceed number of array dimensions Currently when the number of loop variables in a foreach loop is larger than the number of array dimensions an assertion is triggered. Turn this into a error message instead for graceful error reporting. Signed-off-by: Lars-Peter Clausen --- elaborate.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/elaborate.cc b/elaborate.cc index 6e9cc3cdc..1ea15f452 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5380,7 +5380,6 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, } ivl_assert(*this, index_vars_.size() > 0); - ivl_assert(*this, dims.size() >= index_vars_.size()); NetProc*sub; if (statement_) @@ -5389,6 +5388,15 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, sub = new NetBlock(NetBlock::SEQU, 0); NetForLoop*stmt = 0; + if (index_vars_.size() > dims.size()) { + delete sub; + cerr << get_fileline() << ": error: Number of foreach loop indices" + << "(" << index_vars_.size() << ") must not exceed number of " + << "array dimensions (" << dims.size() << ")." << endl; + des->errors++; + return nullptr; + } + for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) { const netrange_t&idx_range = dims[idx_idx]; From f8401095aa1bb786f5fa715985366a935a0268ae Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 4 Dec 2022 21:55:38 -0800 Subject: [PATCH 2/4] Add regression test for too many foreach loop indices Check that an error is reported if too many indices are specified in a foreach loop. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_foreach_fail1.v | 14 ++++++++++++++ ivtest/regress-sv.list | 1 + 2 files changed, 15 insertions(+) create mode 100644 ivtest/ivltests/sv_foreach_fail1.v diff --git a/ivtest/ivltests/sv_foreach_fail1.v b/ivtest/ivltests/sv_foreach_fail1.v new file mode 100644 index 000000000..e8429db19 --- /dev/null +++ b/ivtest/ivltests/sv_foreach_fail1.v @@ -0,0 +1,14 @@ +// Check that an error is reported if the number of loop indices exceeds the +// number of array dimensions in a foreach loop. + +module test; + + logic a[10]; + + initial begin + foreach(a[i,j]) begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index f9456c777..3442ede3b 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -600,6 +600,7 @@ sv_foreach2 normal,-g2009 ivltests sv_foreach3 normal,-g2009 ivltests sv_foreach4 normal,-g2009 ivltests sv_foreach5 normal,-g2009 ivltests +sv_foreach_fail1 CE,-g2009 ivltests sv_immediate_assert normal,-g2009 ivltests gold=sv_immediate_assert.gold sv_immediate_assume normal,-g2009 ivltests gold=sv_immediate_assume.gold sv_macro normal,-g2009 ivltests From e141aef82846bd52e1c48d294b68116c233955bc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Oct 2022 21:01:31 +0200 Subject: [PATCH 3/4] Allow to omit dimensions in foreach loop SystemVerilog allows to skip dimensions in a foreach loop by not specifying an identifier name for the dimensions. E.g. the following will iterate over the first and last dimensions, but skip the middle dimension. ``` int x[1][2][3]; foreach(x[a,,b]) ... ``` Add support for this to the parser as well as elaboration. Signed-off-by: Lars-Peter Clausen --- elaborate.cc | 17 +++++++++++++---- parse.y | 10 ++++++++++ pform.cc | 2 ++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 1ea15f452..695ddf5fd 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5379,8 +5379,6 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, << "Handle as array with static dimensions." << endl; } - ivl_assert(*this, index_vars_.size() > 0); - NetProc*sub; if (statement_) sub = statement_->elaborate(des, scope); @@ -5390,7 +5388,7 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, if (index_vars_.size() > dims.size()) { delete sub; - cerr << get_fileline() << ": error: Number of foreach loop indices" + cerr << get_fileline() << ": error: Number of foreach loop variables" << "(" << index_vars_.size() << ") must not exceed number of " << "array dimensions (" << dims.size() << ")." << endl; des->errors++; @@ -5400,6 +5398,11 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) { const netrange_t&idx_range = dims[idx_idx]; + // It is possible to skip dimensions by not providing a identifier + // name for it. E.g. `int x[1][2][3]; foreach(x[a,,b]) ...` + if (index_vars_[idx_idx].nil()) + continue; + // Get the $high and $low constant values for this slice // of the array. NetEConst*hig_expr = make_const_val_s(idx_range.get_msb()); @@ -5438,7 +5441,13 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, sub = stmt; } - return stmt? stmt : sub; + // If there are no loop variables elide the whole block + if (!stmt) { + delete sub; + return new NetBlock(NetBlock::SEQU, 0); + } + + return stmt; } /* diff --git a/parse.y b/parse.y index a4d427704..11de7ec7c 100644 --- a/parse.y +++ b/parse.y @@ -1799,12 +1799,22 @@ loop_variables /* IEEE1800-2005: A.6.8 */ delete[]$3; $$ = tmp; } + | loop_variables ',' + { std::list*tmp = $1; + tmp->push_back(perm_string()); + $$ = tmp; + } | IDENTIFIER { std::list*tmp = new std::list; tmp->push_back(lex_strings.make($1)); delete[]$1; $$ = tmp; } + | + { std::list*tmp = new std::list; + tmp->push_back(perm_string()); + $$ = tmp; + } ; method_qualifier /* IEEE1800-2005: A.1.8 */ diff --git a/pform.cc b/pform.cc index 7405a91c9..535145b05 100644 --- a/pform.cc +++ b/pform.cc @@ -994,6 +994,8 @@ void pform_make_foreach_declarations(const struct vlltype&loc, listassign_list; for (list::const_iterator cur = loop_vars->begin() ; cur != loop_vars->end() ; ++ cur) { + if (cur->nil()) + continue; decl_assignment_t*tmp_assign = new decl_assignment_t; tmp_assign->name = lex_strings.make(*cur); assign_list.push_back(tmp_assign); From 0e86e99358ee19b354bc1b35602fd000620122ba Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Oct 2022 21:37:53 +0200 Subject: [PATCH 4/4] Add regression tests for omitted foreach dimensions Check that it is possible to omit one or more dimensions in a foreach loop. Signed-off-by: Lars-Peter Clausen --- ivtest/gold/sv_foreach8.gold | 9 +++++++++ ivtest/ivltests/sv_foreach6.v | 21 +++++++++++++++++++++ ivtest/ivltests/sv_foreach7.v | 21 +++++++++++++++++++++ ivtest/ivltests/sv_foreach8.v | 22 ++++++++++++++++++++++ ivtest/regress-sv.list | 3 +++ ivtest/regress-vlog95.list | 3 +++ 6 files changed, 79 insertions(+) create mode 100644 ivtest/gold/sv_foreach8.gold create mode 100644 ivtest/ivltests/sv_foreach6.v create mode 100644 ivtest/ivltests/sv_foreach7.v create mode 100644 ivtest/ivltests/sv_foreach8.v diff --git a/ivtest/gold/sv_foreach8.gold b/ivtest/gold/sv_foreach8.gold new file mode 100644 index 000000000..f1c48b592 --- /dev/null +++ b/ivtest/gold/sv_foreach8.gold @@ -0,0 +1,9 @@ + 0 0 + 0 1 + 0 2 + 0 3 + 1 0 + 1 1 + 1 2 + 1 3 +PASSED diff --git a/ivtest/ivltests/sv_foreach6.v b/ivtest/ivltests/sv_foreach6.v new file mode 100644 index 000000000..0fc911bc7 --- /dev/null +++ b/ivtest/ivltests/sv_foreach6.v @@ -0,0 +1,21 @@ +// Check that foreach loops without an index list work as expected. This is not +// particularly useful, but it is legal code. + +module test; + + logic a[10]; + int i = 0; + + initial begin + foreach(a[]) begin + i++; + end + + if (i == 0) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_foreach7.v b/ivtest/ivltests/sv_foreach7.v new file mode 100644 index 000000000..60aab305b --- /dev/null +++ b/ivtest/ivltests/sv_foreach7.v @@ -0,0 +1,21 @@ +// Check that foreach loops with only empty indices works as expected. This is +// not particularly useful, but it is legal code. + +module test; + + logic a[2][3][4]; + int i = 0; + + initial begin + foreach(a[,,]) begin + i++; + end + + if (i == 0) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_foreach8.v b/ivtest/ivltests/sv_foreach8.v new file mode 100644 index 000000000..37a8b666c --- /dev/null +++ b/ivtest/ivltests/sv_foreach8.v @@ -0,0 +1,22 @@ +// Check that it is possible to omit a dimensions in a foreach loop by not +// specifying a loop identifiers for the dimension. + +module test; + + logic a[2][3][4]; + int k = 0; + + initial begin + foreach(a[i,,j]) begin + $display(i, j); + k++; + end + + if (k == 8) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 3442ede3b..becb8e076 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -600,6 +600,9 @@ sv_foreach2 normal,-g2009 ivltests sv_foreach3 normal,-g2009 ivltests sv_foreach4 normal,-g2009 ivltests sv_foreach5 normal,-g2009 ivltests +sv_foreach6 normal,-g2009 ivltests +sv_foreach7 normal,-g2009 ivltests +sv_foreach8 normal,-g2009 ivltests gold=sv_foreach8.gold sv_foreach_fail1 CE,-g2009 ivltests sv_immediate_assert normal,-g2009 ivltests gold=sv_immediate_assert.gold sv_immediate_assume normal,-g2009 ivltests gold=sv_immediate_assume.gold diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index e520e2de3..170c49b2b 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -954,6 +954,9 @@ struct_signed normal,-g2009,-pallowsigned=1 ivltests sv_for_variable normal,-g2009,-pallowsigned=1 ivltests sv_foreach1 normal,-g2009,-pallowsigned=1 ivltests sv_foreach5 normal,-g2009,-pallowsigned=1 ivltests +sv_foreach6 normal,-g2009,-pallowsigned=1 ivltests +sv_foreach7 normal,-g2009,-pallowsigned=1 ivltests +sv_foreach8 normal,-g2009,-pallowsigned=1 ivltests sv_package normal,-g2009,-pallowsigned=1 ivltests sv_package2 normal,-g2009,-pallowsigned=1 ivltests sv_package5 normal,-g2009,-pallowsigned=1 ivltests