From d746c592b24c970e8fe0c8a6a92a46b00dddeebc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 1 Jan 2022 10:58:18 +0100 Subject: [PATCH 1/3] tgt-vvp: Fix out-of-bounds compressed assignment to arrays If the index of an array access is known to be out-of-bounds during elaboration it is replaced with 'x. In the tgt-vvp backend that is handling compressed array assignments there is an assert() that triggers if the index is an undefined immediate. There is already an existing code path that is capable of handling out-of-bounds access. Remove the assert and set the index to ULONG_MAX to trigger taking the out-of-bound access path. On this out-of-bounds path the write to the array is skipped. But this leaves the result on the vector stack. Insert the `%pop/vec4` instruction to make sure it is removed. Signed-off-by: Lars-Peter Clausen --- tgt-vvp/stmt_assign.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index e240fd619..257b53aea 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -21,6 +21,7 @@ # include # include # include +# include /* * These functions handle the blocking assignment. Use the %set @@ -101,8 +102,10 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice it to select the word, and pay no further heed to the expression itself. */ if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) { - assert(! number_is_unknown(word_ix)); - use_word = get_number_immediate(word_ix); + if (number_is_unknown(word_ix)) + use_word = ULONG_MAX; // The largest valid index is ULONG_MAX - 1 + else + use_word = get_number_immediate(word_ix); word_ix = 0; } @@ -321,6 +324,7 @@ static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, clr_word(word_idx); } else { fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word); + fprintf(vvp_out," %%pop/vec4 1;\n"); } break; From d651aefd9224a3172009159468112fd032e93320 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 21 May 2022 21:22:28 +0200 Subject: [PATCH 2/3] tgt-vvp: Allow out-of-bounds assignment operator on arrays wider than 32 bits For an out-of-bounds assignment operator on an array element an assert is hit if the element width is great than 32. Remove the assert and make sure that this case is handled correctly by using the `%pad/s` instruction to extended the X value to the correct width. Signed-off-by: Lars-Peter Clausen --- tgt-vvp/stmt_assign.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 257b53aea..123b2d405 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -167,8 +167,12 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%load/vec4a v%p, 3;\n", sig); } else { - assert(wid <= 32); - fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, %u;\n", wid); + if (wid <= 32) { + fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, %u;\n", wid); + } else { + fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, 32;\n"); + fprintf(vvp_out, " %%pad/s %u;\n", wid); + } } } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) { From 12188f8d8380abab6b4abaa580273eab39bc8efc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 17 May 2022 11:04:25 +0200 Subject: [PATCH 3/3] Add regression test for out-of-bounds array assignment operator Check that an assignment operator on an out-of-bounds array element works as expected. The out-of-bounds access should leave the array unmodified, but the right-hand side must be evaluated regardless. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/assign_op_oob.v | 44 +++++++++++++++++++++++++++++++++ ivtest/regress-sv.list | 1 + ivtest/regress-vlog95.list | 1 + 3 files changed, 46 insertions(+) create mode 100644 ivtest/ivltests/assign_op_oob.v diff --git a/ivtest/ivltests/assign_op_oob.v b/ivtest/ivltests/assign_op_oob.v new file mode 100644 index 000000000..14897d930 --- /dev/null +++ b/ivtest/ivltests/assign_op_oob.v @@ -0,0 +1,44 @@ +// Check that the assignment operator is supported for out-of-bounds indices. +// The write should be skipped, but side effects of the right-hand side +// expression should still get evaluated. + +module test; + + // Check that wider than 32 works + logic [39:0] a[1:0]; + integer i; + logic [39:0] j = 0; + + function logic [39:0] f; + j++; + return j; + endfunction + + initial begin + a[0] = 23; + a[1] = 42; + + // Immediate out-of-bounds indices + a[-1] += f(); + a[2] += f(); + a['hx] += f(); + + // Variable out-of-bounds indices + i = -1; + a[i] += f(); + i = 2; + a[i] += f(); + i = 'hx; + a[i] += f(); + + // Check that the in-bounds elements do not get affected by out-of-bounds + // updates. Check that the left-hand side of the operator assignment gets + // evaluated. + if (a[0] == 23 && a[1] == 42 && j == 6) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 6c3afca56..bcc4f0047 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -99,6 +99,7 @@ array_packed normal,-g2005-sv ivltests assign_op_after_cmp1 normal,-g2009 ivltests assign_op_after_cmp2 normal,-g2009 ivltests assign_op_concat normal,-g2009 ivltests +assign_op_oob normal,-g2009 ivltests assign_op_type normal,-g2009 ivltests bitp1 normal,-g2005-sv ivltests bits normal,-g2005-sv ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index bde6fa422..5886acce3 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -792,6 +792,7 @@ writemem-invalid RE ivltests gold=writemem-invalid-vlog95.gold # For Verilog 95 signed is supported as an option (-pallowsigned=1). array6 normal,-pallowsigned=1 ivltests +assign_op_oob normal,-g2009,-pallowsigned=1 ivltests assign_op_type normal,-g2009,-pallowsigned=1 ivltests bitp1 normal,-g2009,-pallowsigned=1 ivltests bits normal,-g2009,-pallowsigned=1 ivltests