Skip to content

Commit 356a7f8

Browse files
committed
Verilog: fix assignment context semantics
1 parent 4240ae8 commit 356a7f8

File tree

2 files changed

+138
-12
lines changed

2 files changed

+138
-12
lines changed
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
KNOWNBUG
1+
CORE
22
assignment-context1.sv
33

44
^EXIT=0$
55
^SIGNAL=0$
66
--
77
^warning: ignoring
88
--
9-
The variants that enlarge give a wrong answer.

src/verilog/verilog_typecheck.cpp

Lines changed: 137 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,143 @@ void verilog_typecheckt::assignment_conversion(
4141
exprt &rhs,
4242
const typet &lhs_type)
4343
{
44-
// Implements 1800-2017 10.7
45-
// If the RHS is smaller than the LHS:
46-
// * if the RHS is unsigned, it is zero-padded
47-
// * if the RHS is signed, it is sign-extended
48-
// If the RHS is larger than the LHS, it is truncated.
49-
50-
// This matches our typecast, but differs from the steps taken
51-
// when evaluating binary expressions (11.8.2), where sign
52-
// extension only happens when the propagated type is signed.
53-
implicit_typecast(rhs, lhs_type);
44+
if(rhs.type().id() == ID_verilog_assignment_pattern)
45+
{
46+
DATA_INVARIANT(
47+
rhs.id() == ID_verilog_assignment_pattern,
48+
"verilog_assignment_pattern expression expected");
49+
50+
if(lhs_type.id() == ID_struct)
51+
{
52+
auto &struct_type = to_struct_type(lhs_type);
53+
auto &components = struct_type.components();
54+
55+
if(
56+
!rhs.operands().empty() &&
57+
rhs.operands().front().id() == ID_member_initializer)
58+
{
59+
exprt::operandst initializers{components.size(), nil_exprt{}};
60+
61+
for(auto &op : rhs.operands())
62+
{
63+
PRECONDITION(op.id() == ID_member_initializer);
64+
auto member_name = op.get(ID_member_name);
65+
if(!struct_type.has_component(member_name))
66+
{
67+
throw errort().with_location(op.source_location())
68+
<< "struct does not have a member `" << member_name << "'";
69+
}
70+
auto nr = struct_type.component_number(member_name);
71+
auto value = to_unary_expr(op).op();
72+
// rec. call
73+
assignment_conversion(value, components[nr].type());
74+
initializers[nr] = std::move(value);
75+
}
76+
77+
// Is every member covered?
78+
for(std::size_t i = 0; i < components.size(); i++)
79+
if(initializers[i].is_nil())
80+
{
81+
throw errort().with_location(rhs.source_location())
82+
<< "assignment pattern does not assign member `"
83+
<< components[i].get_name() << "'";
84+
}
85+
86+
rhs = struct_exprt{std::move(initializers), struct_type}
87+
.with_source_location(rhs.source_location());
88+
}
89+
else
90+
{
91+
if(rhs.operands().size() != components.size())
92+
{
93+
throw errort().with_location(rhs.source_location())
94+
<< "number of expressions does not match number of struct members";
95+
}
96+
97+
for(std::size_t i = 0; i < components.size(); i++)
98+
{
99+
// rec. call
100+
assignment_conversion(rhs.operands()[i], components[i].type());
101+
}
102+
103+
// turn into struct expression
104+
rhs.id(ID_struct);
105+
rhs.type() = lhs_type;
106+
}
107+
108+
return;
109+
}
110+
else if(lhs_type.id() == ID_array)
111+
{
112+
auto &array_type = to_array_type(lhs_type);
113+
auto &element_type = array_type.element_type();
114+
auto array_size =
115+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
116+
117+
if(array_size != rhs.operands().size())
118+
{
119+
throw errort().with_location(rhs.source_location())
120+
<< "number of expressions does not match number of array elements";
121+
}
122+
123+
for(std::size_t i = 0; i < array_size; i++)
124+
{
125+
// rec. call
126+
assignment_conversion(rhs.operands()[i], element_type);
127+
}
128+
129+
// turn into array expression
130+
rhs.id(ID_array);
131+
rhs.type() = lhs_type;
132+
return;
133+
}
134+
else
135+
{
136+
throw errort().with_location(rhs.source_location())
137+
<< "cannot convert assignment pattern to '" << to_string(lhs_type)
138+
<< '\'';
139+
}
140+
}
141+
142+
// Implements 1800-2017 10.7 and 1800-2017 11.8.3.
143+
//
144+
// "The size of the left-hand side of an assignment forms
145+
// the context for the right-hand expression."
146+
147+
// Get the width of LHS and RHS
148+
auto lhs_width = get_width(lhs_type);
149+
auto rhs_width = get_width(rhs.type());
150+
151+
if(lhs_width > rhs_width)
152+
{
153+
// Need to enlarge the RHS.
154+
//
155+
// "If needed, extend the size of the right-hand side,
156+
// performing sign extension if, and only if, the type
157+
// of the right-hand side is signed.
158+
if(
159+
(rhs.type().id() == ID_signedbv ||
160+
rhs.type().id() == ID_verilog_signedbv) &&
161+
(lhs_type.id() == ID_unsignedbv ||
162+
lhs_type.id() == ID_verilog_unsignedbv))
163+
{
164+
// LHS is unsigned, RHS is signed. Must sign-extend.
165+
auto new_rhs_type = to_bitvector_type(rhs.type());
166+
new_rhs_type.set_width(numeric_cast_v<std::size_t>(lhs_width));
167+
168+
downwards_type_propagation(rhs, new_rhs_type);
169+
170+
// then cast
171+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
172+
}
173+
else
174+
downwards_type_propagation(rhs, lhs_type);
175+
}
176+
else
177+
{
178+
// no need to enlarge
179+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
180+
}
54181
}
55182

56183
/*******************************************************************\

0 commit comments

Comments
 (0)