-
Notifications
You must be signed in to change notification settings - Fork 289
Expand file tree
/
Copy pathboolbv_byte_update.cpp
More file actions
119 lines (93 loc) · 3.7 KB
/
boolbv_byte_update.cpp
File metadata and controls
119 lines (93 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*******************************************************************\
Module:
Author: Daniel Kroening, kroening@kroening.com
\*******************************************************************/
#include "boolbv.h"
#include <util/arith_tools.h>
#include <util/byte_operators.h>
#include <util/invariant.h>
bvt boolbvt::convert_byte_update(const byte_update_exprt &expr)
{
// if we update (from) an unbounded array, lower the expression as the array
// logic does not handle byte operators
if(
is_unbounded_array(expr.op().type()) ||
is_unbounded_array(expr.value().type()))
{
return convert_bv(lower_byte_update(expr, ns));
}
const exprt &op = expr.op();
const exprt &offset_expr=expr.offset();
const exprt &value=expr.value();
PRECONDITION(
expr.id() == ID_byte_update_little_endian ||
expr.id() == ID_byte_update_big_endian);
const bool little_endian = expr.id() == ID_byte_update_little_endian;
bvt bv=convert_bv(op);
const bvt &value_bv=convert_bv(value);
std::size_t update_width=value_bv.size();
std::size_t byte_width = expr.get_bits_per_byte();
if(update_width>bv.size())
update_width=bv.size();
// When the update value is not a multiple of the byte width,
// lower_byte_update places the value at the high end of the last partial
// byte (concatenating {value, remaining_low_bits}). For little-endian the
// high end is at higher bit indices, so we shift the trailing partial
// byte's bits up. For big-endian the endianness map already places bit 0
// at the MSB, so no shift is needed.
const std::size_t tail_bits = update_width % byte_width;
const std::size_t tail_shift =
little_endian && tail_bits != 0 ? byte_width - tail_bits : 0;
// For a given bit index i (0-based within the update value), compute the
// additional offset to place trailing partial-byte bits at the high end.
auto bit_shift = [&](std::size_t i) -> std::size_t {
return (tail_shift != 0 && i >= update_width - tail_bits) ? tail_shift : 0;
};
// see if the byte number is constant
const auto index = numeric_cast<mp_integer>(offset_expr);
if(index.has_value())
{
// yes!
const mp_integer offset = *index * byte_width;
if(offset+update_width>mp_integer(bv.size()) || offset<0)
{
// out of bounds
}
else
{
endianness_mapt map_op = endianness_map(op.type(), little_endian);
endianness_mapt map_value = endianness_map(value.type(), little_endian);
const std::size_t offset_i = numeric_cast_v<std::size_t>(offset);
for(std::size_t i = 0; i < update_width; i++)
{
size_t index_op = map_op.map_bit(offset_i + bit_shift(i) + i);
size_t index_value = map_value.map_bit(i);
INVARIANT(
index_op < bv.size(), "bit vector index shall be within bounds");
INVARIANT(
index_value < value_bv.size(),
"bit vector index shall be within bounds");
bv[index_op] = value_bv[index_value];
}
}
return bv;
}
// byte_update with variable index
for(std::size_t offset=0; offset<bv.size(); offset+=byte_width)
{
// index condition
equal_exprt equality(
offset_expr, from_integer(offset / byte_width, offset_expr.type()));
literalt equal=convert(equality);
endianness_mapt map_op = endianness_map(op.type(), little_endian);
endianness_mapt map_value = endianness_map(value.type(), little_endian);
for(std::size_t bit=0; bit<update_width; bit++)
if(offset + bit_shift(bit) + bit < bv.size())
{
std::size_t bv_o = map_op.map_bit(offset + bit_shift(bit) + bit);
std::size_t value_bv_o=map_value.map_bit(bit);
bv[bv_o]=prop.lselect(equal, value_bv[value_bv_o], bv[bv_o]);
}
}
return bv;
}