Skip to content

Commit 423de3f

Browse files
authored
Merge pull request #829 from diffblue/verilog_lowering
Verilog: extract function for lowering expressions
2 parents aa9f070 + b70cff7 commit 423de3f

File tree

6 files changed

+328
-299
lines changed

6 files changed

+328
-299
lines changed

src/verilog/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SRC = aval_bval_encoding.cpp \
1010
verilog_interpreter.cpp \
1111
verilog_language.cpp \
1212
verilog_lex.yy.cpp \
13+
verilog_lowering.cpp \
1314
verilog_parameterize_module.cpp \
1415
verilog_parse_tree.cpp \
1516
verilog_parser.cpp \

src/verilog/verilog_lowering.cpp

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
/*******************************************************************\
2+
3+
Module: Verilog Lowering
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "verilog_lowering.h"
10+
11+
#include <util/arith_tools.h>
12+
#include <util/bitvector_expr.h>
13+
#include <util/c_types.h>
14+
15+
#include "aval_bval_encoding.h"
16+
#include "verilog_bits.h"
17+
#include "verilog_expr.h"
18+
19+
exprt extract(
20+
const exprt &src,
21+
const mp_integer &offset,
22+
const typet &dest_type)
23+
{
24+
auto src_width = to_bitvector_type(src.type()).get_width();
25+
auto dest_width = verilog_bits(dest_type);
26+
27+
// first add padding, if src is too small
28+
exprt padded_src;
29+
auto padding_width = dest_width + offset - src_width;
30+
31+
if(padding_width > 0)
32+
{
33+
auto padded_width_int =
34+
numeric_cast_v<std::size_t>(src_width + padding_width);
35+
padded_src = concatenation_exprt{
36+
{unsignedbv_typet{numeric_cast_v<std::size_t>(padding_width)}.zero_expr(),
37+
src},
38+
bv_typet{padded_width_int}};
39+
}
40+
else // large enough
41+
padded_src = src;
42+
43+
// now extract
44+
if(dest_type.id() == ID_bool)
45+
{
46+
return extractbit_exprt{padded_src, from_integer(offset, integer_typet{})};
47+
}
48+
else
49+
{
50+
return extractbits_exprt{
51+
padded_src, from_integer(offset, integer_typet{}), dest_type};
52+
}
53+
}
54+
55+
exprt from_bitvector(
56+
const exprt &src,
57+
const mp_integer &offset,
58+
const typet &dest)
59+
{
60+
if(dest.id() == ID_struct)
61+
{
62+
const auto &struct_type = to_struct_type(dest);
63+
exprt::operandst field_values;
64+
field_values.reserve(struct_type.components().size());
65+
66+
// start from the top; the first field is the most significant
67+
mp_integer component_offset = verilog_bits(dest);
68+
69+
for(auto &component : struct_type.components())
70+
{
71+
auto width = verilog_bits(component.type());
72+
component_offset -= width;
73+
// rec. call
74+
field_values.push_back(
75+
from_bitvector(src, offset + component_offset, component.type()));
76+
}
77+
78+
return struct_exprt{std::move(field_values), struct_type};
79+
}
80+
else if(dest.id() == ID_union)
81+
{
82+
// We use the first field of the union.
83+
// All fields of a SystemVerilog packed union must have the same width.
84+
const auto &union_type = to_union_type(dest);
85+
DATA_INVARIANT(
86+
!union_type.components().empty(),
87+
"union type must have at least one field");
88+
auto &field = union_type.components().front();
89+
90+
// rec. call
91+
auto field_value = from_bitvector(src, offset, field.type());
92+
93+
return union_exprt{field.get_name(), std::move(field_value), union_type};
94+
}
95+
else
96+
{
97+
return extract(src, offset, dest);
98+
}
99+
}
100+
101+
exprt to_bitvector(const exprt &src)
102+
{
103+
const auto &src_type = src.type();
104+
105+
if(src_type.id() == ID_struct)
106+
{
107+
const auto &struct_type = to_struct_type(src_type);
108+
exprt::operandst field_values;
109+
field_values.reserve(struct_type.components().size());
110+
111+
// the first struct member is the most significant
112+
for(auto &component : struct_type.components())
113+
{
114+
auto member = member_exprt{src, component};
115+
auto field_value = to_bitvector(member); // rec. call
116+
field_values.push_back(std::move(field_value));
117+
}
118+
119+
auto width_int = numeric_cast_v<std::size_t>(verilog_bits(src));
120+
return concatenation_exprt{std::move(field_values), bv_typet{width_int}};
121+
}
122+
else if(src_type.id() == ID_union)
123+
{
124+
const auto &union_type = to_union_type(src_type);
125+
DATA_INVARIANT(
126+
!union_type.components().empty(),
127+
"union type must have at least one field");
128+
auto &field = union_type.components().front();
129+
auto member = member_exprt{src, field};
130+
return to_bitvector(member); // rec. call
131+
}
132+
else
133+
{
134+
return src;
135+
}
136+
}
137+
138+
exprt verilog_lowering(exprt expr)
139+
{
140+
if(expr.id() == ID_verilog_inside)
141+
{
142+
// The lowering uses wildcard equality, which needs to be further lowered
143+
auto &inside = to_verilog_inside_expr(expr);
144+
expr = inside.lower();
145+
}
146+
147+
// Do the operands recursively
148+
for(auto &op : expr.operands())
149+
op = verilog_lowering(op);
150+
151+
if(expr.id() == ID_constant)
152+
{
153+
// encode into aval/bval
154+
if(
155+
expr.type().id() == ID_verilog_unsignedbv ||
156+
expr.type().id() == ID_verilog_signedbv)
157+
{
158+
return lower_to_aval_bval(to_constant_expr(expr));
159+
}
160+
161+
return expr;
162+
}
163+
else if(expr.id() == ID_concatenation)
164+
{
165+
if(
166+
expr.type().id() == ID_verilog_unsignedbv ||
167+
expr.type().id() == ID_verilog_signedbv)
168+
{
169+
return aval_bval_concatenation(
170+
to_concatenation_expr(expr).operands(),
171+
lower_to_aval_bval(expr.type()));
172+
}
173+
174+
return expr;
175+
}
176+
else if(expr.id() == ID_power)
177+
{
178+
auto &power_expr = to_power_expr(expr);
179+
180+
// encode into aval/bval
181+
if(is_four_valued(expr.type()))
182+
return aval_bval(power_expr);
183+
else
184+
{
185+
DATA_INVARIANT(
186+
power_expr.lhs().type() == power_expr.type(),
187+
"power expression type consistency");
188+
189+
auto rhs_int = numeric_cast<std::size_t>(power_expr.rhs());
190+
if(rhs_int.has_value())
191+
{
192+
if(*rhs_int == 0)
193+
return from_integer(1, expr.type());
194+
else if(*rhs_int == 1)
195+
return power_expr.lhs();
196+
else // >= 2
197+
{
198+
auto factors = exprt::operandst{rhs_int.value(), power_expr.lhs()};
199+
// would prefer appropriate mult_exprt constructor
200+
return multi_ary_exprt{ID_mult, factors, expr.type()};
201+
}
202+
}
203+
else
204+
return expr;
205+
}
206+
}
207+
else if(expr.id() == ID_typecast)
208+
{
209+
auto &typecast_expr = to_typecast_expr(expr);
210+
211+
// When casting a four-valued scalar to bool,
212+
// 'true' is defined as a "nonzero known value" (1800-2017 12.4).
213+
if(is_aval_bval(typecast_expr.op()) && typecast_expr.type().id() == ID_bool)
214+
{
215+
return aval_bval(typecast_expr);
216+
}
217+
else
218+
{
219+
const auto &src_type = typecast_expr.op().type();
220+
const auto &dest_type = typecast_expr.type();
221+
222+
if(
223+
dest_type.id() == ID_verilog_unsignedbv ||
224+
dest_type.id() == ID_verilog_signedbv)
225+
{
226+
auto aval_bval_type = lower_to_aval_bval(dest_type);
227+
return aval_bval_conversion(typecast_expr.op(), aval_bval_type);
228+
}
229+
else if(dest_type.id() == ID_struct || dest_type.id() == ID_union)
230+
{
231+
return from_bitvector(typecast_expr.op(), 0, dest_type);
232+
}
233+
else
234+
{
235+
if(src_type.id() == ID_struct || src_type.id() == ID_union)
236+
{
237+
return extract(to_bitvector(typecast_expr.op()), 0, dest_type);
238+
}
239+
}
240+
}
241+
242+
return expr;
243+
}
244+
else if(
245+
expr.id() == ID_verilog_streaming_concatenation_left_to_right ||
246+
expr.id() == ID_verilog_streaming_concatenation_right_to_left)
247+
{
248+
auto &streaming_concatenation =
249+
to_verilog_streaming_concatenation_expr(expr);
250+
return streaming_concatenation.lower();
251+
}
252+
else if(expr.id() == ID_verilog_non_indexed_part_select)
253+
{
254+
auto &part_select = to_verilog_non_indexed_part_select_expr(expr);
255+
return part_select.lower();
256+
}
257+
else if(
258+
expr.id() == ID_verilog_indexed_part_select_plus ||
259+
expr.id() == ID_verilog_indexed_part_select_minus)
260+
{
261+
auto &part_select = to_verilog_indexed_part_select_plus_or_minus_expr(expr);
262+
return part_select.lower();
263+
}
264+
else if(expr.id() == ID_verilog_logical_equality)
265+
{
266+
return aval_bval(to_verilog_logical_equality_expr(expr));
267+
}
268+
else if(expr.id() == ID_verilog_logical_inequality)
269+
{
270+
return aval_bval(to_verilog_logical_inequality_expr(expr));
271+
}
272+
else if(expr.id() == ID_verilog_wildcard_equality)
273+
{
274+
return aval_bval(to_verilog_wildcard_equality_expr(expr));
275+
}
276+
else if(expr.id() == ID_verilog_wildcard_inequality)
277+
{
278+
return aval_bval(to_verilog_wildcard_inequality_expr(expr));
279+
}
280+
else if(expr.id() == ID_not)
281+
{
282+
auto &not_expr = to_not_expr(expr);
283+
284+
// encode into aval/bval
285+
if(is_four_valued(expr.type()))
286+
return aval_bval(not_expr);
287+
else
288+
return expr; // leave as is
289+
}
290+
else
291+
return expr; // leave as is
292+
293+
UNREACHABLE;
294+
}

src/verilog/verilog_lowering.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*******************************************************************\
2+
3+
Module: Verilog Lowering
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_VERILOG_LOWERING_H
10+
#define CPROVER_VERILOG_LOWERING_H
11+
12+
class exprt;
13+
14+
exprt verilog_lowering(exprt);
15+
16+
#endif

0 commit comments

Comments
 (0)