Skip to content

Commit 4b183ec

Browse files
authored
Merge pull request #4227 from tautschnig/byte-op-conversion
Byte-operator lowering: do not generate type casts to compound types [blocks: #2068]
2 parents 2168964 + 131fda0 commit 4b183ec

File tree

3 files changed

+244
-6
lines changed

3 files changed

+244
-6
lines changed

regression/cbmc/Pointer_byte_extract3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33

44
^EXIT=0$

regression/cbmc/Pointer_byte_extract7/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33
--big-endian
44
^EXIT=0$

src/solvers/lowering/byte_operators.cpp

Lines changed: 242 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,241 @@ Author: Daniel Kroening, [email protected]
1919

2020
#include "flatten_byte_extract_exceptions.h"
2121

22+
static exprt bv_to_expr(
23+
const exprt &bitvector_expr,
24+
const typet &target_type,
25+
const namespacet &ns);
26+
27+
/// Convert a bitvector-typed expression \p bitvector_expr to a struct-typed
28+
/// expression. See \ref bv_to_expr for an overview.
29+
static struct_exprt bv_to_struct_expr(
30+
const exprt &bitvector_expr,
31+
const struct_typet &struct_type,
32+
const namespacet &ns)
33+
{
34+
const struct_typet::componentst &components = struct_type.components();
35+
36+
exprt::operandst operands;
37+
operands.reserve(components.size());
38+
std::size_t member_offset_bits = 0;
39+
for(const auto &comp : components)
40+
{
41+
const auto component_bits_opt = pointer_offset_bits(comp.type(), ns);
42+
std::size_t component_bits;
43+
if(component_bits_opt.has_value())
44+
component_bits = numeric_cast_v<std::size_t>(*component_bits_opt);
45+
else
46+
component_bits = to_bitvector_type(bitvector_expr.type()).get_width() -
47+
member_offset_bits;
48+
49+
if(component_bits == 0)
50+
{
51+
operands.push_back(constant_exprt{irep_idt{}, comp.type()});
52+
continue;
53+
}
54+
55+
bitvector_typet type{bitvector_expr.type().id(), component_bits};
56+
operands.push_back(bv_to_expr(
57+
extractbits_exprt{bitvector_expr,
58+
member_offset_bits + component_bits - 1,
59+
member_offset_bits,
60+
std::move(type)},
61+
comp.type(),
62+
ns));
63+
64+
if(component_bits_opt.has_value())
65+
member_offset_bits += component_bits;
66+
}
67+
68+
return struct_exprt{std::move(operands), struct_type};
69+
}
70+
71+
/// Convert a bitvector-typed expression \p bitvector_expr to an array-typed
72+
/// expression. See \ref bv_to_expr for an overview.
73+
static array_exprt bv_to_array_expr(
74+
const exprt &bitvector_expr,
75+
const array_typet &array_type,
76+
const namespacet &ns)
77+
{
78+
auto num_elements = numeric_cast<std::size_t>(array_type.size());
79+
auto subtype_bits = pointer_offset_bits(array_type.subtype(), ns);
80+
81+
const std::size_t total_bits =
82+
to_bitvector_type(bitvector_expr.type()).get_width();
83+
if(!num_elements.has_value())
84+
{
85+
if(!subtype_bits.has_value() || *subtype_bits == 0)
86+
num_elements = total_bits;
87+
else
88+
num_elements = total_bits / numeric_cast_v<std::size_t>(*subtype_bits);
89+
}
90+
DATA_INVARIANT(
91+
!num_elements.has_value() || !subtype_bits.has_value() ||
92+
*subtype_bits * *num_elements == total_bits,
93+
"subtype width times array size should be total bitvector width");
94+
95+
exprt::operandst operands;
96+
operands.reserve(*num_elements);
97+
for(std::size_t i = 0; i < *num_elements; ++i)
98+
{
99+
if(subtype_bits.has_value())
100+
{
101+
const std::size_t subtype_bits_int =
102+
numeric_cast_v<std::size_t>(*subtype_bits);
103+
bitvector_typet type{bitvector_expr.type().id(), subtype_bits_int};
104+
operands.push_back(bv_to_expr(
105+
extractbits_exprt{bitvector_expr,
106+
((i + 1) * subtype_bits_int) - 1,
107+
i * subtype_bits_int,
108+
std::move(type)},
109+
array_type.subtype(),
110+
ns));
111+
}
112+
else
113+
{
114+
operands.push_back(bv_to_expr(bitvector_expr, array_type.subtype(), ns));
115+
}
116+
}
117+
118+
return array_exprt{std::move(operands), array_type};
119+
}
120+
121+
/// Convert a bitvector-typed expression \p bitvector_expr to a vector-typed
122+
/// expression. See \ref bv_to_expr for an overview.
123+
static vector_exprt bv_to_vector_expr(
124+
const exprt &bitvector_expr,
125+
const vector_typet &vector_type,
126+
const namespacet &ns)
127+
{
128+
const std::size_t num_elements =
129+
numeric_cast_v<std::size_t>(vector_type.size());
130+
auto subtype_bits = pointer_offset_bits(vector_type.subtype(), ns);
131+
DATA_INVARIANT(
132+
!subtype_bits.has_value() ||
133+
*subtype_bits * num_elements ==
134+
to_bitvector_type(bitvector_expr.type()).get_width(),
135+
"subtype width times vector size should be total bitvector width");
136+
137+
exprt::operandst operands;
138+
operands.reserve(num_elements);
139+
for(std::size_t i = 0; i < num_elements; ++i)
140+
{
141+
if(subtype_bits.has_value())
142+
{
143+
const std::size_t subtype_bits_int =
144+
numeric_cast_v<std::size_t>(*subtype_bits);
145+
bitvector_typet type{bitvector_expr.type().id(), subtype_bits_int};
146+
operands.push_back(bv_to_expr(
147+
extractbits_exprt{bitvector_expr,
148+
((i + 1) * subtype_bits_int) - 1,
149+
i * subtype_bits_int,
150+
std::move(type)},
151+
vector_type.subtype(),
152+
ns));
153+
}
154+
else
155+
{
156+
operands.push_back(bv_to_expr(bitvector_expr, vector_type.subtype(), ns));
157+
}
158+
}
159+
160+
return vector_exprt{std::move(operands), vector_type};
161+
}
162+
163+
/// Convert a bitvector-typed expression \p bitvector_expr to a complex-typed
164+
/// expression. See \ref bv_to_expr for an overview.
165+
static complex_exprt bv_to_complex_expr(
166+
const exprt &bitvector_expr,
167+
const complex_typet &complex_type,
168+
const namespacet &ns)
169+
{
170+
const std::size_t total_bits =
171+
to_bitvector_type(bitvector_expr.type()).get_width();
172+
const auto subtype_bits_opt = pointer_offset_bits(complex_type.subtype(), ns);
173+
std::size_t subtype_bits;
174+
if(subtype_bits_opt.has_value())
175+
{
176+
subtype_bits = numeric_cast_v<std::size_t>(*subtype_bits_opt);
177+
DATA_INVARIANT(
178+
subtype_bits * 2 == total_bits,
179+
"subtype width should be half of the total bitvector width");
180+
}
181+
else
182+
subtype_bits = total_bits / 2;
183+
184+
const bitvector_typet type{bitvector_expr.type().id(), subtype_bits};
185+
186+
return complex_exprt{
187+
bv_to_expr(
188+
extractbits_exprt{bitvector_expr, subtype_bits - 1, 0, type},
189+
complex_type.subtype(),
190+
ns),
191+
bv_to_expr(
192+
extractbits_exprt{
193+
bitvector_expr, subtype_bits * 2 - 1, subtype_bits, type},
194+
complex_type.subtype(),
195+
ns),
196+
complex_type};
197+
}
198+
199+
/// Convert a bitvector-typed expression \p bitvector_expr to an expression of
200+
/// type \p target_type. If \p target_type is a bitvector type this may be a
201+
/// no-op or a typecast. For composite types such as structs, the bitvectors
202+
/// corresponding to the individual members are extracted and then a compound
203+
/// expression is built from those extracted members. When the size of a
204+
/// component isn't constant we fall back to computing its size based on the
205+
/// width of \p bitvector_expr.
206+
/// \param bitvector_expr: Bitvector-typed expression to extract from.
207+
/// \param target_type: Type of the expression to build.
208+
/// \param ns: Namespace to resolve tag types.
209+
/// \return Expression of type \p target_type constructed from sequences of bits
210+
/// from \p bitvector_expr.
211+
static exprt bv_to_expr(
212+
const exprt &bitvector_expr,
213+
const typet &target_type,
214+
const namespacet &ns)
215+
{
216+
PRECONDITION(can_cast_type<bitvector_typet>(bitvector_expr.type()));
217+
218+
if(
219+
can_cast_type<bitvector_typet>(target_type) ||
220+
target_type.id() == ID_c_enum || target_type.id() == ID_c_enum_tag ||
221+
target_type.id() == ID_string)
222+
{
223+
return simplify_expr(
224+
typecast_exprt::conditional_cast(bitvector_expr, target_type), ns);
225+
}
226+
227+
if(target_type.id() == ID_struct)
228+
{
229+
return bv_to_struct_expr(bitvector_expr, to_struct_type(target_type), ns);
230+
}
231+
else if(target_type.id() == ID_struct_tag)
232+
{
233+
struct_exprt result = bv_to_struct_expr(
234+
bitvector_expr, ns.follow_tag(to_struct_tag_type(target_type)), ns);
235+
result.type() = target_type;
236+
return std::move(result);
237+
}
238+
else if(target_type.id() == ID_array)
239+
{
240+
return bv_to_array_expr(bitvector_expr, to_array_type(target_type), ns);
241+
}
242+
else if(target_type.id() == ID_vector)
243+
{
244+
return bv_to_vector_expr(bitvector_expr, to_vector_type(target_type), ns);
245+
}
246+
else if(target_type.id() == ID_complex)
247+
{
248+
return bv_to_complex_expr(bitvector_expr, to_complex_type(target_type), ns);
249+
}
250+
else
251+
{
252+
PRECONDITION_WITH_DIAGNOSTICS(
253+
false, "bv_to_expr does not yet support ", target_type.id_string());
254+
}
255+
}
256+
22257
static exprt unpack_rec(
23258
const exprt &src,
24259
bool little_endian,
@@ -500,7 +735,7 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
500735

501736
plus_exprt new_offset(
502737
unpacked.offset(),
503-
typecast_exprt(
738+
typecast_exprt::conditional_cast(
504739
member_offset_expr(struct_type, comp.get_name(), ns),
505740
unpacked.offset().type()));
506741

@@ -606,13 +841,16 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
606841
}
607842

608843
if(width_bytes==1)
609-
return simplify_expr(typecast_exprt(op.front(), src.type()), ns);
844+
{
845+
return simplify_expr(
846+
typecast_exprt::conditional_cast(op.front(), src.type()), ns);
847+
}
610848
else // width_bytes>=2
611849
{
612850
concatenation_exprt concatenation(
613851
std::move(op), bitvector_typet(subtype->id(), width_bytes * 8));
614-
return simplify_expr(
615-
typecast_exprt(std::move(concatenation), src.type()), ns);
852+
853+
return bv_to_expr(concatenation, src.type(), ns);
616854
}
617855
}
618856

0 commit comments

Comments
 (0)