-
Notifications
You must be signed in to change notification settings - Fork 300
Expand file tree
/
Copy pathbitvector_expr.cpp
More file actions
342 lines (278 loc) · 10.3 KB
/
Copy pathbitvector_expr.cpp
File metadata and controls
342 lines (278 loc) · 10.3 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*******************************************************************\
Module: API to expression classes for bitvectors
Author: Daniel Kroening, kroening@kroening.com
\*******************************************************************/
#include "bitvector_expr.h"
#include "arith_tools.h"
#include "bitvector_types.h"
#include "mathematical_types.h"
shift_exprt::shift_exprt(
exprt _src,
const irep_idt &_id,
const std::size_t _distance)
: binary_exprt(std::move(_src), _id, from_integer(_distance, integer_typet()))
{
}
extractbit_exprt::extractbit_exprt(exprt _src, const std::size_t _index)
: binary_predicate_exprt(
std::move(_src),
ID_extractbit,
from_integer(_index, integer_typet()))
{
}
extractbits_exprt::extractbits_exprt(
exprt _src,
const std::size_t _index,
typet _type)
: expr_protectedt(ID_extractbits, std::move(_type))
{
add_to_operands(std::move(_src), from_integer(_index, integer_typet()));
}
update_bit_exprt::update_bit_exprt(
exprt _src,
const std::size_t _index,
exprt _new_value)
: update_bit_exprt(
std::move(_src),
from_integer(_index, integer_typet()),
std::move(_new_value))
{
}
exprt update_bit_exprt::lower() const
{
const auto width = to_bitvector_type(type()).get_width();
auto src_bv_type = bv_typet(width);
// build a mask 0...0 1
auto mask_bv =
make_bvrep(width, [](std::size_t index) { return index == 0; });
auto mask_expr = constant_exprt(mask_bv, src_bv_type);
// shift the mask by the index
auto mask_shifted = shl_exprt(mask_expr, index());
auto src_masked = bitand_exprt(
typecast_exprt(src(), src_bv_type), bitnot_exprt(mask_shifted));
// zero-extend the replacement bit to match src
auto new_value_bv = typecast_exprt{new_value(), bv_typet{1}};
auto new_value_casted = zero_extend_exprt{new_value_bv, src_bv_type};
// shift the replacement bits
auto new_value_shifted = shl_exprt(new_value_casted, index());
// or the masked src and the shifted replacement bits
return typecast_exprt(
bitor_exprt(src_masked, new_value_shifted), src().type());
}
exprt update_bits_exprt::lower() const
{
const auto width = to_bitvector_type(type()).get_width();
const auto new_value_width =
to_bitvector_type(new_value().type()).get_width();
auto src_bv_type = bv_typet(width);
// build a mask 1...1 0...0
auto mask_bv = make_bvrep(width, [new_value_width](std::size_t index) {
return index >= new_value_width;
});
auto mask_expr = constant_exprt(mask_bv, src_bv_type);
// shift the mask by the index
auto mask_shifted = shl_exprt(mask_expr, index());
auto src_masked =
bitand_exprt(typecast_exprt(src(), src_bv_type), mask_shifted);
// zero-extend or shrink the replacement bits to match src
auto new_value_casted = zero_extend_exprt{new_value(), src_bv_type};
// shift the replacement bits
auto new_value_shifted = shl_exprt(new_value_casted, index());
// or the masked src and the shifted replacement bits
return typecast_exprt(
bitor_exprt(src_masked, new_value_shifted), src().type());
}
exprt popcount_exprt::lower() const
{
// Hacker's Delight, variant pop0:
// x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
// x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
// x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
// x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
// etc.
// return x;
// http://www.hackersdelight.org/permissions.htm
// make sure the operand width is a power of two
exprt x = op();
const auto x_width = to_bitvector_type(x.type()).get_width();
CHECK_RETURN(x_width >= 1);
const std::size_t bits = address_bits(x_width);
const std::size_t new_width = numeric_cast_v<std::size_t>(power(2, bits));
const bool need_typecast =
new_width > x_width || x.type().id() != ID_unsignedbv;
if(need_typecast)
x = typecast_exprt(x, unsignedbv_typet(new_width));
// repeatedly compute x = (x & bitmask) + ((x >> shift) & bitmask)
for(std::size_t shift = 1; shift < new_width; shift <<= 1)
{
// x >> shift
lshr_exprt shifted_x(
x, from_integer(shift, unsignedbv_typet(address_bits(shift) + 1)));
// bitmask is a string of alternating shift-many bits starting from lsb set
// to 1
std::string bitstring;
bitstring.reserve(new_width);
for(std::size_t i = 0; i < new_width / (2 * shift); ++i)
bitstring += std::string(shift, '0') + std::string(shift, '1');
const mp_integer value = binary2integer(bitstring, false);
const constant_exprt bitmask(integer2bvrep(value, new_width), x.type());
// build the expression
x = plus_exprt(bitand_exprt(x, bitmask), bitand_exprt(shifted_x, bitmask));
}
// the result is restricted to the result type
return typecast_exprt::conditional_cast(x, type());
}
exprt count_leading_zeros_exprt::lower() const
{
// x = x | (x >> 1);
// x = x | (x >> 2);
// x = x | (x >> 4);
// x = x | (x >> 8);
// etc.
// return popcount(~x);
// make sure the operand width is a power of two
exprt x = op();
const auto x_width = to_bitvector_type(x.type()).get_width();
CHECK_RETURN(x_width >= 1);
const std::size_t bits = address_bits(x_width);
const std::size_t new_width = numeric_cast_v<std::size_t>(power(2, bits));
const bool need_typecast =
new_width > x_width || x.type().id() != ID_unsignedbv;
if(need_typecast)
x = typecast_exprt(x, unsignedbv_typet(new_width));
// repeatedly compute x = x | (x >> shift)
for(std::size_t shift = 1; shift < new_width; shift <<= 1)
{
// x >> shift
lshr_exprt shifted_x(
x, from_integer(shift, unsignedbv_typet(address_bits(shift) + 1)));
// build the expression
x = bitor_exprt{x, shifted_x};
}
// the result is restricted to the result type
return popcount_exprt{
bitnot_exprt{typecast_exprt::conditional_cast(x, op().type())}, type()}
.lower();
}
exprt count_trailing_zeros_exprt::lower() const
{
exprt x = op();
// popcount(~(x | (~x + 1)))
// compute -x using two's complement
plus_exprt minus_x{bitnot_exprt{x}, from_integer(1, x.type())};
bitor_exprt x_or_minus_x{x, std::move(minus_x)};
popcount_exprt popcount{bitnot_exprt{std::move(x_or_minus_x)}};
return typecast_exprt::conditional_cast(popcount.lower(), type());
}
exprt bitreverse_exprt::lower() const
{
const std::size_t int_width = to_bitvector_type(type()).get_width();
exprt::operandst result_bits;
result_bits.reserve(int_width);
const symbol_exprt to_reverse("to_reverse", op().type());
for(std::size_t i = 0; i < int_width; ++i)
result_bits.push_back(extractbit_exprt{to_reverse, i});
return let_exprt{to_reverse, op(), concatenation_exprt{result_bits, type()}};
}
exprt plus_overflow_exprt::lower() const
{
std::size_t lhs_ssize = to_bitvector_type(lhs().type()).get_width();
if(lhs().type().id() == ID_unsignedbv)
++lhs_ssize;
std::size_t rhs_ssize = to_bitvector_type(rhs().type()).get_width();
if(rhs().type().id() == ID_unsignedbv)
++rhs_ssize;
std::size_t ssize = std::max(lhs_ssize, rhs_ssize) + 1;
signedbv_typet ssize_type{ssize};
plus_exprt exact_result{
typecast_exprt{lhs(), ssize_type}, typecast_exprt{rhs(), ssize_type}};
return notequal_exprt{
typecast_exprt{typecast_exprt{exact_result, lhs().type()}, ssize_type},
exact_result};
}
exprt minus_overflow_exprt::lower() const
{
std::size_t lhs_ssize = to_bitvector_type(lhs().type()).get_width();
if(lhs().type().id() == ID_unsignedbv)
++lhs_ssize;
std::size_t rhs_ssize = to_bitvector_type(rhs().type()).get_width();
if(rhs().type().id() == ID_unsignedbv)
++rhs_ssize;
std::size_t ssize = std::max(lhs_ssize, rhs_ssize) + 1;
signedbv_typet ssize_type{ssize};
minus_exprt exact_result{
typecast_exprt{lhs(), ssize_type}, typecast_exprt{rhs(), ssize_type}};
return notequal_exprt{
typecast_exprt{typecast_exprt{exact_result, lhs().type()}, ssize_type},
exact_result};
}
exprt mult_overflow_exprt::lower() const
{
std::size_t lhs_ssize = to_bitvector_type(lhs().type()).get_width();
if(lhs().type().id() == ID_unsignedbv)
++lhs_ssize;
std::size_t rhs_ssize = to_bitvector_type(rhs().type()).get_width();
if(rhs().type().id() == ID_unsignedbv)
++rhs_ssize;
std::size_t ssize = lhs_ssize + rhs_ssize;
signedbv_typet ssize_type{ssize};
mult_exprt exact_result{
typecast_exprt{lhs(), ssize_type}, typecast_exprt{rhs(), ssize_type}};
return notequal_exprt{
typecast_exprt{typecast_exprt{exact_result, lhs().type()}, ssize_type},
exact_result};
}
exprt find_first_set_exprt::lower() const
{
exprt x = op();
const auto int_width = to_bitvector_type(x.type()).get_width();
CHECK_RETURN(int_width >= 1);
// bitwidth(x) - clz(x & ~((unsigned)x - 1));
const unsignedbv_typet ut{int_width};
minus_exprt minus_one{
typecast_exprt::conditional_cast(x, ut), from_integer(1, ut)};
count_leading_zeros_exprt clz{bitand_exprt{
x, bitnot_exprt{typecast_exprt::conditional_cast(minus_one, x.type())}}};
minus_exprt result{from_integer(int_width, x.type()), clz.lower()};
return typecast_exprt::conditional_cast(result, type());
}
exprt zero_extend_exprt::lower() const
{
const auto old_width = to_bitvector_type(op().type()).get_width();
const auto new_width = to_bitvector_type(type()).get_width();
if(new_width > old_width)
{
return concatenation_exprt{
bv_typet{new_width - old_width}.all_zeros_expr(), op(), type()};
}
else // new_width <= old_width
{
return extractbits_exprt{op(), 0, type()};
}
}
static exprt onehot_lowering(const exprt &expr)
{
exprt one_seen = false_exprt{};
const auto width = to_bitvector_type(expr.type()).get_width();
exprt::operandst more_than_one_seen_disjuncts;
more_than_one_seen_disjuncts.reserve(width);
for(std::size_t i = 0; i < width; i++)
{
auto bit = extractbit_exprt{expr, i};
more_than_one_seen_disjuncts.push_back(and_exprt{bit, one_seen});
one_seen = or_exprt{one_seen, bit};
}
auto more_than_one_seen = disjunction(more_than_one_seen_disjuncts);
return and_exprt{one_seen, not_exprt{more_than_one_seen}};
}
exprt onehot_exprt::lower() const
{
auto symbol = symbol_exprt{"onehot-op", op().type()};
return let_exprt{symbol, op(), onehot_lowering(symbol)};
}
exprt onehot0_exprt::lower() const
{
auto symbol = symbol_exprt{"onehot-op", op().type()};
// same as onehot, but on flipped operand bits
return let_exprt{symbol, bitnot_exprt{op()}, onehot_lowering(symbol)};
}