Skip to content

Commit 175c12c

Browse files
committed
Byte-operator lowering: do not generate type casts to compound types
These aren't fully supported by the back-ends. Instead, bit-extract the components and construct an expression.
1 parent d683a70 commit 175c12c

File tree

3 files changed

+169
-6
lines changed

3 files changed

+169
-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: 167 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,168 @@ 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+
if(
28+
can_cast_type<bitvector_typet>(target_type) ||
29+
target_type.id() == ID_c_enum || target_type.id() == ID_c_enum_tag)
30+
{
31+
return simplify_expr(
32+
typecast_exprt::conditional_cast(bitvector_expr, target_type), ns);
33+
}
34+
35+
if(target_type.id() == ID_struct || target_type.id() == ID_struct_tag)
36+
{
37+
const struct_typet &struct_type = to_struct_type(ns.follow(target_type));
38+
const struct_typet::componentst &components = struct_type.components();
39+
40+
exprt::operandst operands;
41+
operands.reserve(components.size());
42+
std::size_t offset = 0;
43+
for(const auto &comp : components)
44+
{
45+
auto component_bits = pointer_offset_bits(comp.type(), ns);
46+
std::size_t bits;
47+
if(component_bits.has_value())
48+
bits = numeric_cast_v<std::size_t>(*component_bits);
49+
else
50+
bits = to_bitvector_type(bitvector_expr.type()).get_width() - offset;
51+
52+
if(bits == 0)
53+
{
54+
operands.push_back(constant_exprt(irep_idt(), comp.type()));
55+
continue;
56+
}
57+
58+
bitvector_typet type(bitvector_expr.type().id(), bits);
59+
operands.push_back(bv_to_expr(
60+
extractbits_exprt(bitvector_expr, offset + bits - 1, offset, type),
61+
comp.type(),
62+
ns));
63+
64+
if(component_bits.has_value())
65+
offset += bits;
66+
}
67+
68+
return struct_exprt(std::move(operands), target_type);
69+
}
70+
else if(target_type.id() == ID_array)
71+
{
72+
const array_typet &array_type = to_array_type(target_type);
73+
auto num_elements = numeric_cast<std::size_t>(array_type.size());
74+
auto subtype_bits = pointer_offset_bits(array_type.subtype(), ns);
75+
76+
const std::size_t total_width =
77+
to_bitvector_type(bitvector_expr.type()).get_width();
78+
if(!num_elements.has_value())
79+
{
80+
if(!subtype_bits.has_value() || *subtype_bits == 0)
81+
num_elements = total_width;
82+
else
83+
num_elements = total_width / numeric_cast_v<std::size_t>(*subtype_bits);
84+
}
85+
86+
exprt::operandst operands;
87+
operands.reserve(*num_elements);
88+
for(std::size_t i = 0; i < *num_elements; ++i)
89+
{
90+
if(subtype_bits.has_value())
91+
{
92+
const std::size_t subtype_bits_int =
93+
numeric_cast_v<std::size_t>(*subtype_bits);
94+
bitvector_typet type(bitvector_expr.type().id(), subtype_bits_int);
95+
operands.push_back(bv_to_expr(
96+
extractbits_exprt(
97+
bitvector_expr,
98+
(i + 1) * subtype_bits_int - 1,
99+
i * subtype_bits_int,
100+
type),
101+
array_type.subtype(),
102+
ns));
103+
}
104+
else
105+
{
106+
operands.push_back(
107+
bv_to_expr(bitvector_expr, array_type.subtype(), ns));
108+
}
109+
}
110+
111+
return array_exprt(std::move(operands), array_type);
112+
}
113+
else if(target_type.id() == ID_vector)
114+
{
115+
const vector_typet &vector_type = to_vector_type(target_type);
116+
const std::size_t num_elements =
117+
numeric_cast_v<std::size_t>(vector_type.size());
118+
auto subtype_bits = pointer_offset_bits(vector_type.subtype(), ns);
119+
120+
exprt::operandst operands;
121+
operands.reserve(num_elements);
122+
for(std::size_t i = 0; i < num_elements; ++i)
123+
{
124+
if(subtype_bits.has_value())
125+
{
126+
const std::size_t subtype_bits_int =
127+
numeric_cast_v<std::size_t>(*subtype_bits);
128+
bitvector_typet type(bitvector_expr.type().id(), subtype_bits_int);
129+
operands.push_back(bv_to_expr(
130+
extractbits_exprt(
131+
bitvector_expr,
132+
(i + 1) * subtype_bits_int - 1,
133+
i * subtype_bits_int,
134+
type),
135+
vector_type.subtype(),
136+
ns));
137+
}
138+
else
139+
{
140+
operands.push_back(
141+
bv_to_expr(bitvector_expr, vector_type.subtype(), ns));
142+
}
143+
}
144+
145+
return vector_exprt(std::move(operands), vector_type);
146+
}
147+
else if(target_type.id() == ID_complex)
148+
{
149+
const complex_typet &complex_type = to_complex_type(target_type);
150+
auto subtype_bits = pointer_offset_bits(complex_type.subtype(), ns);
151+
std::size_t subtype_bits_int;
152+
if(subtype_bits.has_value())
153+
subtype_bits_int = numeric_cast_v<std::size_t>(*subtype_bits);
154+
else
155+
subtype_bits_int =
156+
to_bitvector_type(bitvector_expr.type()).get_width() / 2;
157+
158+
bitvector_typet type(bitvector_expr.type().id(), subtype_bits_int);
159+
160+
return complex_exprt(
161+
bv_to_expr(
162+
extractbits_exprt(bitvector_expr, subtype_bits_int - 1, 0, type),
163+
complex_type.subtype(),
164+
ns),
165+
bv_to_expr(
166+
extractbits_exprt(
167+
bitvector_expr, subtype_bits_int * 2 - 1, subtype_bits_int, type),
168+
complex_type.subtype(),
169+
ns),
170+
complex_type);
171+
}
172+
else if(target_type.id() == ID_string)
173+
{
174+
// this works, but is somewhat questionable
175+
return typecast_exprt(bitvector_expr, target_type);
176+
}
177+
else
178+
{
179+
PRECONDITION_WITH_DIAGNOSTICS(
180+
false, "bv_to_expr does not yet support ", target_type.id_string());
181+
}
182+
}
183+
22184
static exprt unpack_rec(
23185
const exprt &src,
24186
bool little_endian,
@@ -501,7 +663,7 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
501663

502664
plus_exprt new_offset(
503665
unpacked.offset(),
504-
typecast_exprt(
666+
typecast_exprt::conditional_cast(
505667
member_offset_expr(struct_type, comp.get_name(), ns),
506668
unpacked.offset().type()));
507669

@@ -607,13 +769,14 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
607769
}
608770

609771
if(width_bytes==1)
610-
return simplify_expr(typecast_exprt(op.front(), src.type()), ns);
772+
return simplify_expr(
773+
typecast_exprt::conditional_cast(op.front(), src.type()), ns);
611774
else // width_bytes>=2
612775
{
613776
concatenation_exprt concatenation(
614777
std::move(op), bitvector_typet(subtype->id(), width_bytes * 8));
615-
return simplify_expr(
616-
typecast_exprt(std::move(concatenation), src.type()), ns);
778+
779+
return bv_to_expr(concatenation, src.type(), ns);
617780
}
618781
}
619782

0 commit comments

Comments
 (0)