Skip to content

Commit 6b0d346

Browse files
authored
Merge pull request #787 from diffblue/part-select-constant
Verilog: constant folding for indexed part select expressions
2 parents 4d01463 + 5724218 commit 6b0d346

File tree

5 files changed

+91
-48
lines changed

5 files changed

+91
-48
lines changed

regression/verilog/expressions/part-select-constant1.sv

+2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module main;
33
// part-select expressions yield constants
44
parameter p = 'b1010;
55
parameter q = p[3:1];
6+
parameter r = p[1 +: 3];
67

78
assert final (q == 'b101);
9+
assert final (r == 'b101);
810

911
endmodule

src/verilog/verilog_expr.cpp

+77
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,80 @@ exprt verilog_non_indexed_part_select_exprt::lower() const
228228
{
229229
return ::lower(*this);
230230
}
231+
232+
static exprt
233+
lower(const verilog_indexed_part_select_plus_or_minus_exprt &part_select)
234+
{
235+
auto get_width = [](const typet &t) -> mp_integer
236+
{
237+
if(t.id() == ID_bool)
238+
return 1;
239+
240+
if(
241+
t.id() == ID_unsignedbv || t.id() == ID_signedbv ||
242+
t.id() == ID_verilog_signedbv || t.id() == ID_verilog_unsignedbv)
243+
{
244+
return to_bitvector_type(t).get_width();
245+
}
246+
247+
PRECONDITION(false);
248+
};
249+
250+
PRECONDITION(
251+
part_select.id() == ID_verilog_indexed_part_select_plus ||
252+
part_select.id() == ID_verilog_indexed_part_select_minus);
253+
254+
const exprt &src = part_select.src();
255+
256+
mp_integer src_width = get_width(src.type());
257+
mp_integer src_offset = string2integer(src.type().get_string(ID_C_offset));
258+
259+
// The width of the indexed part select must be an
260+
// elaboration-time constant.
261+
auto width =
262+
numeric_cast_v<mp_integer>(to_constant_expr(part_select.width()));
263+
264+
// The index need not be a constant.
265+
const exprt &index = part_select.index();
266+
267+
if(index.is_constant())
268+
{
269+
auto index_int = numeric_cast_v<mp_integer>(to_constant_expr(index));
270+
271+
// Construct the extractbits expression
272+
mp_integer bottom;
273+
274+
if(part_select.id() == ID_verilog_indexed_part_select_plus)
275+
{
276+
bottom = index_int - src_offset;
277+
}
278+
else // ID_verilog_indexed_part_select_minus
279+
{
280+
bottom = bottom - width + 1;
281+
}
282+
283+
return extractbits_exprt{
284+
std::move(src), from_integer(bottom, integer_typet{}), part_select.type()}
285+
.with_source_location(part_select);
286+
}
287+
else
288+
{
289+
// Index not constant.
290+
// Use logical right-shift followed by (constant) extractbits.
291+
auto index_adjusted =
292+
minus_exprt{index, from_integer(src_offset, index.type())};
293+
294+
auto src_shifted = lshr_exprt(src, index_adjusted);
295+
296+
return extractbits_exprt{
297+
std::move(src_shifted),
298+
from_integer(0, integer_typet{}),
299+
part_select.type()}
300+
.with_source_location(part_select);
301+
}
302+
}
303+
304+
exprt verilog_indexed_part_select_plus_or_minus_exprt::lower() const
305+
{
306+
return ::lower(*this);
307+
}

src/verilog/verilog_expr.h

+2
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,8 @@ class verilog_indexed_part_select_plus_or_minus_exprt : public ternary_exprt
24172417
{
24182418
return op2();
24192419
}
2420+
2421+
exprt lower() const;
24202422
};
24212423

24222424
inline const verilog_indexed_part_select_plus_or_minus_exprt &

src/verilog/verilog_synthesis.cpp

+1-48
Original file line numberDiff line numberDiff line change
@@ -358,54 +358,7 @@ exprt verilog_synthesist::synth_expr(exprt expr, symbol_statet symbol_state)
358358
expr.id() == ID_verilog_indexed_part_select_minus)
359359
{
360360
auto &part_select = to_verilog_indexed_part_select_plus_or_minus_expr(expr);
361-
exprt &src = part_select.src();
362-
363-
mp_integer src_width = get_width(src.type());
364-
mp_integer src_offset = string2integer(src.type().get_string(ID_C_offset));
365-
366-
// The width of the indexed part select must be an
367-
// elaboration-time constant.
368-
auto width =
369-
numeric_cast_v<mp_integer>(to_constant_expr(part_select.width()));
370-
371-
// The index need not be a constant.
372-
exprt &index = part_select.index();
373-
374-
if(index.is_constant())
375-
{
376-
auto index_int = numeric_cast_v<mp_integer>(to_constant_expr(index));
377-
378-
// Construct the extractbits expression
379-
mp_integer bottom, top;
380-
381-
if(part_select.id() == ID_verilog_indexed_part_select_plus)
382-
{
383-
bottom = index_int - src_offset;
384-
top = bottom + width - 1;
385-
}
386-
else // ID_verilog_indexed_part_select_minus
387-
{
388-
top = index_int - src_offset;
389-
bottom = bottom - width + 1;
390-
}
391-
392-
return extractbits_exprt{
393-
std::move(src), from_integer(bottom, integer_typet{}), expr.type()}
394-
.with_source_location(expr);
395-
}
396-
else
397-
{
398-
// Index not constant.
399-
// Use logical right-shift followed by (constant) extractbits.
400-
auto index_adjusted =
401-
minus_exprt{index, from_integer(src_offset, index.type())};
402-
403-
auto src_shifted = lshr_exprt(src, index_adjusted);
404-
405-
return extractbits_exprt{
406-
std::move(src_shifted), from_integer(0, integer_typet{}), expr.type()}
407-
.with_source_location(expr);
408-
}
361+
return part_select.lower();
409362
}
410363
else if(expr.id() == ID_verilog_logical_equality)
411364
{

src/verilog/verilog_typecheck_expr.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,15 @@ exprt verilog_typecheck_exprt::elaborate_constant_expression(exprt expr)
16601660
auto &part_select = to_verilog_non_indexed_part_select_expr(expr);
16611661
expr = part_select.lower();
16621662
}
1663+
else if(
1664+
expr.id() == ID_verilog_indexed_part_select_plus ||
1665+
expr.id() == ID_verilog_indexed_part_select_minus)
1666+
{
1667+
// Our simplifier does not know these, do lowering.
1668+
auto &part_select =
1669+
to_verilog_indexed_part_select_plus_or_minus_expr(expr);
1670+
expr = part_select.lower();
1671+
}
16631672
else if(expr.id() == ID_reduction_or)
16641673
{
16651674
// The simplifier doesn't know how to simplify reduction_or

0 commit comments

Comments
 (0)