Skip to content

Commit b4d939b

Browse files
authored
Merge pull request #5390 from tautschnig/fix-bitfield-byte-update
Byte-update lowering: handle sub-byte sized bit fields
2 parents 6d5e580 + e16b7db commit b4d939b

File tree

3 files changed

+76
-31
lines changed

3 files changed

+76
-31
lines changed

regression/cbmc/byte_update13/main.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
#include <string.h>
3+
4+
struct blob
5+
{
6+
unsigned dummy;
7+
unsigned bit : 1;
8+
};
9+
10+
int main()
11+
{
12+
struct blob b;
13+
struct blob b1 = b;
14+
15+
// Perform byte-wise updates of the struct, up to its full size. Constant
16+
// propagation made impossible, and thus the byte updates need to be handled
17+
// by the back-end.
18+
if(b.dummy <= sizeof(struct blob))
19+
memset(&b, 0, b.dummy);
20+
21+
// If we updated the complete struct, then the single-bit bit-field needs to
22+
// have been set to zero as well. This makes sure that the encoding of byte
23+
// update properly handles fields that are smaller than bytes.
24+
assert(b1.dummy != sizeof(struct blob) || b.bit == 0);
25+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/solvers/lowering/byte_operators.cpp

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,10 +2136,30 @@ static exprt lower_byte_update(
21362136
instantiate_byte_array(value_as_byte_array, 0, (type_bits + 7) / 8, ns);
21372137
}
21382138

2139+
const std::size_t update_size_bits = update_bytes.size() * 8;
2140+
const std::size_t bit_width = std::max(type_bits, update_size_bits);
2141+
2142+
const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2143+
2144+
exprt val_before =
2145+
typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2146+
if(bit_width > type_bits)
2147+
{
2148+
val_before =
2149+
concatenation_exprt{from_integer(0, bv_typet{bit_width - type_bits}),
2150+
val_before,
2151+
bv_typet{bit_width}};
2152+
2153+
if(!is_little_endian)
2154+
to_concatenation_expr(val_before)
2155+
.op0()
2156+
.swap(to_concatenation_expr(val_before).op1());
2157+
}
2158+
21392159
if(non_const_update_bound.has_value())
21402160
{
21412161
const exprt src_as_bytes = unpack_rec(
2142-
src.op(),
2162+
val_before,
21432163
src.id() == ID_byte_update_little_endian,
21442164
mp_integer{0},
21452165
mp_integer{update_bytes.size()},
@@ -2158,19 +2178,15 @@ static exprt lower_byte_update(
21582178
}
21592179
}
21602180

2161-
const std::size_t update_size = update_bytes.size();
2162-
const std::size_t width = std::max(type_bits, update_size * 8);
2163-
2164-
const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2165-
21662181
// build mask
21672182
exprt mask;
21682183
if(is_little_endian)
2169-
mask = from_integer(power(2, update_size * 8) - 1, bv_typet{width});
2184+
mask = from_integer(power(2, update_size_bits) - 1, bv_typet{bit_width});
21702185
else
21712186
{
21722187
mask = from_integer(
2173-
power(2, width) - power(2, width - update_size * 8), bv_typet{width});
2188+
power(2, bit_width) - power(2, bit_width - update_size_bits),
2189+
bv_typet{bit_width});
21742190
}
21752191

21762192
const typet &offset_type = src.offset().type();
@@ -2186,34 +2202,20 @@ static exprt lower_byte_update(
21862202
mask_shifted.true_case().swap(mask_shifted.false_case());
21872203

21882204
// original_bits &= ~mask
2189-
exprt val_before =
2190-
typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2191-
if(width > type_bits)
2192-
{
2193-
val_before =
2194-
concatenation_exprt{from_integer(0, bv_typet{width - type_bits}),
2195-
val_before,
2196-
bv_typet{width}};
2197-
2198-
if(!is_little_endian)
2199-
to_concatenation_expr(val_before)
2200-
.op0()
2201-
.swap(to_concatenation_expr(val_before).op1());
2202-
}
22032205
bitand_exprt bitand_expr{val_before, bitnot_exprt{mask_shifted}};
22042206

22052207
// concatenate and zero-extend the value
2206-
concatenation_exprt value{update_bytes, bv_typet{update_size * 8}};
2208+
concatenation_exprt value{update_bytes, bv_typet{update_size_bits}};
22072209
if(is_little_endian)
22082210
std::reverse(value.operands().begin(), value.operands().end());
22092211

22102212
exprt zero_extended;
2211-
if(width > update_size * 8)
2213+
if(bit_width > update_size_bits)
22122214
{
2213-
zero_extended =
2214-
concatenation_exprt{from_integer(0, bv_typet{width - update_size * 8}),
2215-
value,
2216-
bv_typet{width}};
2215+
zero_extended = concatenation_exprt{
2216+
from_integer(0, bv_typet{bit_width - update_size_bits}),
2217+
value,
2218+
bv_typet{bit_width}};
22172219

22182220
if(!is_little_endian)
22192221
to_concatenation_expr(zero_extended)
@@ -2233,12 +2235,22 @@ static exprt lower_byte_update(
22332235
// original_bits |= newvalue
22342236
bitor_exprt bitor_expr{bitand_expr, value_shifted};
22352237

2236-
if(!is_little_endian && width > type_bits)
2238+
if(!is_little_endian && bit_width > type_bits)
2239+
{
2240+
return simplify_expr(
2241+
typecast_exprt::conditional_cast(
2242+
extractbits_exprt{bitor_expr,
2243+
bit_width - 1,
2244+
bit_width - type_bits,
2245+
bv_typet{type_bits}},
2246+
src.type()),
2247+
ns);
2248+
}
2249+
else if(bit_width > type_bits)
22372250
{
22382251
return simplify_expr(
22392252
typecast_exprt::conditional_cast(
2240-
extractbits_exprt{
2241-
bitor_expr, width - 1, width - type_bits, bv_typet{type_bits}},
2253+
extractbits_exprt{bitor_expr, type_bits - 1, 0, bv_typet{type_bits}},
22422254
src.type()),
22432255
ns);
22442256
}

0 commit comments

Comments
 (0)