Skip to content

Commit 54f891b

Browse files
committed
Verilog: fix assignment context semantics
This fixes the semantics of assignment contexts, by adding the downward width propagation pass.
1 parent 2ef7d0f commit 54f891b

File tree

2 files changed

+82
-11
lines changed

2 files changed

+82
-11
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: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void verilog_typecheckt::assignment_conversion(
4747
DATA_INVARIANT(
4848
rhs.id() == ID_verilog_assignment_pattern,
4949
"verilog_assignment_pattern expression expected");
50+
5051
if(lhs_type.id() == ID_struct)
5152
{
5253
auto &struct_type = to_struct_type(lhs_type);
@@ -139,16 +140,87 @@ void verilog_typecheckt::assignment_conversion(
139140
}
140141
}
141142

142-
// Implements 1800-2017 10.7
143-
// If the RHS is smaller than the LHS:
144-
// * if the RHS is unsigned, it is zero-padded
145-
// * if the RHS is signed, it is sign-extended
146-
// If the RHS is larger than the LHS, it is truncated.
143+
auto &verilog_dest_type = lhs_type.get(ID_C_verilog_type);
144+
if(verilog_dest_type == ID_verilog_enum)
145+
{
146+
// IEEE 1800-2017 6.19.3: "a variable of type enum cannot be directly
147+
// assigned a value that lies outside the enumeration set unless an
148+
// explicit cast is used"
149+
if(
150+
rhs.type().get(ID_C_verilog_type) != ID_verilog_enum ||
151+
rhs.type().get(ID_C_identifier) != lhs_type.get(ID_C_identifier))
152+
{
153+
throw errort().with_location(rhs.source_location())
154+
<< "assignment to enum requires enum of the same type, but got "
155+
<< to_string(rhs.type());
156+
}
157+
}
158+
159+
if(lhs_type == rhs.type())
160+
return;
161+
162+
// Implements 1800-2017 10.7 and 1800-2017 11.8.3.
163+
164+
if(
165+
lhs_type.id() == ID_verilog_real || lhs_type.id() == ID_verilog_shortreal ||
166+
lhs_type.id() == ID_verilog_realtime ||
167+
rhs.type().id() == ID_verilog_real ||
168+
rhs.type().id() == ID_verilog_shortreal)
169+
{
170+
// from/to real is just a cast
171+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
172+
return;
173+
}
174+
175+
if(rhs.type().id() == ID_verilog_null)
176+
{
177+
if(
178+
lhs_type.id() == ID_verilog_chandle ||
179+
lhs_type.id() == ID_verilog_class_type ||
180+
lhs_type.id() == ID_verilog_event)
181+
{
182+
rhs = typecast_exprt{rhs, lhs_type};
183+
return;
184+
}
185+
}
186+
187+
// "The size of the left-hand side of an assignment forms
188+
// the context for the right-hand expression."
147189

148-
// This matches our typecast, but differs from the steps taken
149-
// when evaluating binary expressions (11.8.2), where sign
150-
// extension only happens when the propagated type is signed.
151-
implicit_typecast(rhs, lhs_type);
190+
// Get the width of LHS and RHS
191+
auto lhs_width = get_width(lhs_type);
192+
auto rhs_width = get_width(rhs.type());
193+
194+
if(lhs_width > rhs_width)
195+
{
196+
// Need to enlarge the RHS.
197+
//
198+
// "If needed, extend the size of the right-hand side,
199+
// performing sign extension if, and only if, the type
200+
// of the right-hand side is signed.
201+
if(
202+
(rhs.type().id() == ID_signedbv ||
203+
rhs.type().id() == ID_verilog_signedbv) &&
204+
(lhs_type.id() == ID_unsignedbv ||
205+
lhs_type.id() == ID_verilog_unsignedbv))
206+
{
207+
// LHS is unsigned, RHS is signed. Must sign-extend.
208+
auto new_rhs_type = to_bitvector_type(rhs.type());
209+
new_rhs_type.set_width(numeric_cast_v<std::size_t>(lhs_width));
210+
211+
downwards_type_propagation(rhs, new_rhs_type);
212+
213+
// then cast
214+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
215+
}
216+
else
217+
downwards_type_propagation(rhs, lhs_type);
218+
}
219+
else
220+
{
221+
// no need to enlarge
222+
rhs = typecast_exprt::conditional_cast(rhs, lhs_type);
223+
}
152224
}
153225

154226
/*******************************************************************\

0 commit comments

Comments
 (0)