diff --git a/elaborate.cc b/elaborate.cc index 6e9cc3cdc..695ddf5fd 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5379,9 +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); - ivl_assert(*this, dims.size() >= index_vars_.size()); - NetProc*sub; if (statement_) sub = statement_->elaborate(des, scope); @@ -5389,9 +5386,23 @@ 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 variables" + << "(" << 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]; + // 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()); @@ -5430,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/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/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..becb8e076 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -600,6 +600,10 @@ 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 sv_macro normal,-g2009 ivltests 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 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);