Skip to content

Commit 308845b

Browse files
authored
Merge pull request #1318 from diffblue/move-assignment-conversion
Verilog: move assignment conversion code
2 parents 2f46d49 + 48582cc commit 308845b

File tree

4 files changed

+173
-93
lines changed

4 files changed

+173
-93
lines changed

src/verilog/verilog_typecheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,7 @@ void verilog_typecheckt::convert_case_values(
14201420

14211421
// This works like a relational operator, not like an assignment
14221422
typet t=max_type(it->type(), case_operand.type());
1423-
propagate_type(*it, t);
1423+
downwards_type_propagation(*it, t);
14241424
}
14251425
}
14261426

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 170 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void verilog_typecheck_exprt::enter_named_block(const irep_idt &name)
8989

9090
/*******************************************************************\
9191
92-
Function: verilog_typecheck_exprt::propagate_type
92+
Function: verilog_typecheck_exprt::assignment_conversion
9393
9494
Inputs:
9595
@@ -99,125 +99,205 @@ Function: verilog_typecheck_exprt::propagate_type
9999
100100
\*******************************************************************/
101101

102-
void verilog_typecheck_exprt::propagate_type(
103-
exprt &expr,
104-
const typet &type)
102+
void verilog_typecheck_exprt::assignment_conversion(
103+
exprt &rhs,
104+
const typet &lhs_type)
105105
{
106-
auto &verilog_dest_type = type.get(ID_C_verilog_type);
106+
// 1800-2017 10.9
107+
if(rhs.type().id() == ID_verilog_assignment_pattern)
108+
{
109+
DATA_INVARIANT(
110+
rhs.id() == ID_verilog_assignment_pattern,
111+
"verilog_assignment_pattern expression expected");
112+
113+
if(lhs_type.id() == ID_struct)
114+
{
115+
auto &struct_type = to_struct_type(lhs_type);
116+
auto &components = struct_type.components();
117+
118+
if(
119+
!rhs.operands().empty() &&
120+
rhs.operands().front().id() == ID_member_initializer)
121+
{
122+
exprt::operandst initializers{components.size(), nil_exprt{}};
123+
124+
for(auto &op : rhs.operands())
125+
{
126+
PRECONDITION(op.id() == ID_member_initializer);
127+
auto member_name = op.get(ID_member_name);
128+
if(!struct_type.has_component(member_name))
129+
{
130+
throw errort().with_location(op.source_location())
131+
<< "struct does not have a member `" << member_name << "'";
132+
}
133+
auto nr = struct_type.component_number(member_name);
134+
auto value = to_unary_expr(op).op();
135+
// rec. call
136+
assignment_conversion(value, components[nr].type());
137+
initializers[nr] = std::move(value);
138+
}
139+
140+
// Is every member covered?
141+
for(std::size_t i = 0; i < components.size(); i++)
142+
if(initializers[i].is_nil())
143+
{
144+
throw errort().with_location(rhs.source_location())
145+
<< "assignment pattern does not assign member `"
146+
<< components[i].get_name() << "'";
147+
}
148+
149+
rhs = struct_exprt{std::move(initializers), struct_type}
150+
.with_source_location(rhs.source_location());
151+
}
152+
else
153+
{
154+
if(rhs.operands().size() != components.size())
155+
{
156+
throw errort().with_location(rhs.source_location())
157+
<< "number of expressions does not match number of struct members";
158+
}
159+
160+
for(std::size_t i = 0; i < components.size(); i++)
161+
{
162+
// rec. call
163+
assignment_conversion(rhs.operands()[i], components[i].type());
164+
}
165+
166+
// turn into struct expression
167+
rhs.id(ID_struct);
168+
rhs.type() = lhs_type;
169+
}
170+
171+
return;
172+
}
173+
else if(lhs_type.id() == ID_array)
174+
{
175+
auto &array_type = to_array_type(lhs_type);
176+
auto &element_type = array_type.element_type();
177+
auto array_size =
178+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
179+
180+
if(array_size != rhs.operands().size())
181+
{
182+
throw errort().with_location(rhs.source_location())
183+
<< "number of expressions does not match number of array elements";
184+
}
185+
186+
for(std::size_t i = 0; i < array_size; i++)
187+
{
188+
// rec. call
189+
assignment_conversion(rhs.operands()[i], element_type);
190+
}
191+
192+
// turn into array expression
193+
rhs.id(ID_array);
194+
rhs.type() = lhs_type;
195+
return;
196+
}
197+
else
198+
{
199+
throw errort().with_location(rhs.source_location())
200+
<< "cannot convert assignment pattern to '" << to_string(lhs_type)
201+
<< '\'';
202+
}
203+
}
204+
205+
auto original_rhs_type = rhs.type(); // copy
206+
207+
auto &verilog_dest_type = lhs_type.get(ID_C_verilog_type);
107208
if(verilog_dest_type == ID_verilog_enum)
108209
{
109210
// IEEE 1800-2017 6.19.3: "a variable of type enum cannot be directly
110211
// assigned a value that lies outside the enumeration set unless an
111212
// explicit cast is used"
112213
if(
113-
expr.type().get(ID_C_verilog_type) != ID_verilog_enum ||
114-
expr.type().get(ID_C_identifier) != type.get(ID_C_identifier))
214+
rhs.type().get(ID_C_verilog_type) != ID_verilog_enum ||
215+
rhs.type().get(ID_C_identifier) != lhs_type.get(ID_C_identifier))
115216
{
116-
throw errort().with_location(expr.source_location())
217+
throw errort().with_location(rhs.source_location())
117218
<< "assignment to enum requires enum of the same type, but got "
118-
<< to_string(expr.type());
219+
<< to_string(rhs.type());
119220
}
120221
}
121222

122-
if(expr.type()==type)
223+
if(lhs_type == rhs.type())
123224
return;
124225

125-
if(expr.type().id() == ID_verilog_sva_sequence)
126-
{
127-
throw errort{}.with_location(expr.source_location())
128-
<< "cannot use SVA sequence as an expression";
129-
}
130-
else if(expr.type().id() == ID_verilog_sva_property)
226+
// do enum, union and struct decay
227+
enum_decay(rhs);
228+
struct_decay(rhs);
229+
union_decay(rhs);
230+
231+
if(rhs.type().id() == ID_struct || rhs.type().id() == ID_union)
131232
{
132-
throw errort{}.with_location(expr.source_location())
133-
<< "cannot use SVA property as an expression";
233+
// not decayed, not equal
234+
throw errort().with_location(rhs.source_location())
235+
<< "failed to convert `" << to_string(original_rhs_type) << "' to `"
236+
<< to_string(lhs_type) << "'";
134237
}
135238

136-
vtypet vt_from=vtypet(expr.type());
137-
vtypet vt_to =vtypet(type);
239+
// Implements 1800-2017 10.7 and 1800-2017 11.8.3.
138240

139-
if(!vt_from.is_other() && !vt_to.is_other() &&
140-
expr.has_operands())
241+
if(
242+
lhs_type.id() == ID_verilog_real || lhs_type.id() == ID_verilog_shortreal ||
243+
lhs_type.id() == ID_verilog_realtime ||
244+
rhs.type().id() == ID_verilog_real ||
245+
rhs.type().id() == ID_verilog_shortreal)
141246
{
142-
// arithmetic
247+
// from/to real is just a cast
248+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
249+
return;
250+
}
143251

252+
if(rhs.type().id() == ID_verilog_null)
253+
{
144254
if(
145-
expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult ||
146-
expr.id() == ID_div || expr.id() == ID_unary_minus ||
147-
expr.id() == ID_unary_plus)
255+
lhs_type.id() == ID_verilog_chandle ||
256+
lhs_type.id() == ID_verilog_class_type ||
257+
lhs_type.id() == ID_verilog_event)
148258
{
149-
if(type.id()!=ID_bool)
150-
{
151-
Forall_operands(it, expr)
152-
propagate_type(*it, type);
153-
154-
expr.type()=type;
155-
156-
return;
157-
}
259+
rhs = typecast_exprt{rhs, lhs_type};
260+
return;
158261
}
159-
else if(expr.id()==ID_bitand ||
160-
expr.id()==ID_bitor ||
161-
expr.id()==ID_bitnand ||
162-
expr.id()==ID_bitnor ||
163-
expr.id()==ID_bitxor ||
164-
expr.id()==ID_bitxnor ||
165-
expr.id()==ID_bitnot)
166-
{
167-
Forall_operands(it, expr)
168-
propagate_type(*it, type);
262+
}
169263

170-
expr.type()=type;
264+
// "The size of the left-hand side of an assignment forms
265+
// the context for the right-hand expression."
171266

172-
if(type.id()==ID_bool)
173-
{
174-
if(expr.id()==ID_bitand)
175-
expr.id(ID_and);
176-
else if(expr.id()==ID_bitor)
177-
expr.id(ID_or);
178-
else if(expr.id()==ID_bitnand)
179-
expr.id(ID_nand);
180-
else if(expr.id()==ID_bitnor)
181-
expr.id(ID_nor);
182-
else if(expr.id()==ID_bitxor)
183-
expr.id(ID_xor);
184-
else if(expr.id()==ID_bitxnor)
185-
expr.id(ID_xnor);
186-
else if(expr.id()==ID_bitnot)
187-
expr.id(ID_not);
188-
}
267+
// Get the width of LHS and RHS
268+
auto lhs_width = get_width(lhs_type);
269+
auto rhs_width = get_width(rhs.type());
189270

190-
return;
191-
}
192-
else if(expr.id()==ID_if)
271+
if(lhs_width > rhs_width)
272+
{
273+
// Need to enlarge the RHS.
274+
//
275+
// "If needed, extend the size of the right-hand side,
276+
// performing sign extension if, and only if, the type
277+
// of the right-hand side is signed.
278+
if(
279+
(rhs.type().id() == ID_signedbv ||
280+
rhs.type().id() == ID_verilog_signedbv) &&
281+
(lhs_type.id() == ID_unsignedbv ||
282+
lhs_type.id() == ID_verilog_unsignedbv))
193283
{
194-
if(expr.operands().size()==3)
195-
{
196-
propagate_type(to_if_expr(expr).true_case(), type);
197-
propagate_type(to_if_expr(expr).false_case(), type);
284+
// LHS is unsigned, RHS is signed. Must sign-extend.
285+
auto new_rhs_type = to_bitvector_type(rhs.type());
286+
new_rhs_type.set_width(numeric_cast_v<std::size_t>(lhs_width));
198287

199-
expr.type()=type;
200-
return;
201-
}
202-
}
203-
else if(expr.id()==ID_shl) // does not work with shr
204-
{
205-
// does not work with boolean
206-
if(type.id()!=ID_bool)
207-
{
208-
if(expr.operands().size()==2)
209-
{
210-
propagate_type(to_binary_expr(expr).op0(), type);
211-
// not applicable to second operand
288+
downwards_type_propagation(rhs, new_rhs_type);
212289

213-
expr.type()=type;
214-
return;
215-
}
216-
}
290+
// then cast
291+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
217292
}
293+
else
294+
downwards_type_propagation(rhs, lhs_type);
295+
}
296+
else
297+
{
298+
// no need to enlarge
299+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
218300
}
219-
220-
implicit_typecast(expr, type);
221301
}
222302

223303
/*******************************************************************\
@@ -612,7 +692,7 @@ exprt verilog_typecheck_exprt::convert_expr_function_call(
612692
}
613693

614694
for(unsigned i=0; i<arguments.size(); i++)
615-
propagate_type(arguments[i], parameter_types[i].type());
695+
assignment_conversion(arguments[i], parameter_types[i].type());
616696

617697
return std::move(expr);
618698
}

src/verilog/verilog_typecheck_expr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset
6565

6666
void make_boolean(exprt &expr);
6767

68-
void propagate_type(exprt &expr, const typet &type);
68+
void assignment_conversion(exprt &expr, const typet &type);
6969
void downwards_type_propagation(exprt &, const typet &);
7070

7171
[[nodiscard]] typet elaborate_type(const typet &);

src/verilog/verilog_typecheck_sva.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr)
295295
{
296296
convert_expr(pattern);
297297
typet t = max_type(pattern.type(), case_expr.case_op().type());
298-
propagate_type(pattern, t);
298+
downwards_type_propagation(pattern, t);
299299
}
300300

301301
convert_sva(case_item.result());

0 commit comments

Comments
 (0)