12
12
#include " expr_initializer.h"
13
13
14
14
#include " arith_tools.h"
15
+ #include " bitvector_expr.h"
15
16
#include " c_types.h"
17
+ #include " config.h"
16
18
#include " magic.h"
17
19
#include " namespace.h" // IWYU pragma: keep
18
20
#include " std_code.h"
19
21
20
- template <bool nondet>
21
22
class expr_initializert
22
23
{
23
24
public:
24
25
explicit expr_initializert (const namespacet &_ns) : ns(_ns)
25
26
{
26
27
}
27
28
28
- optionalt<exprt>
29
- operator ()(const typet &type, const source_locationt &source_location)
29
+ optionalt<exprt> operator ()(
30
+ const typet &type,
31
+ const source_locationt &source_location,
32
+ const exprt &init_expr)
30
33
{
31
- return expr_initializer_rec (type, source_location);
34
+ return expr_initializer_rec (type, source_location, init_expr );
32
35
}
33
36
34
37
protected:
35
38
const namespacet &ns;
36
39
37
40
optionalt<exprt> expr_initializer_rec (
38
41
const typet &type,
39
- const source_locationt &source_location);
42
+ const source_locationt &source_location,
43
+ const exprt &init_expr);
40
44
};
41
45
42
- template <bool nondet>
43
- optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
46
+ optionalt<exprt> expr_initializert::expr_initializer_rec (
44
47
const typet &type,
45
- const source_locationt &source_location)
48
+ const source_locationt &source_location,
49
+ const exprt &init_expr)
46
50
{
47
51
const irep_idt &type_id=type.id ();
48
52
@@ -57,10 +61,12 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
57
61
type_id==ID_fixedbv)
58
62
{
59
63
exprt result;
60
- if (nondet )
64
+ if (init_expr. id () == ID_nondet )
61
65
result = side_effect_expr_nondett (type, source_location);
62
- else
66
+ else if (init_expr. is_zero ())
63
67
result = from_integer (0 , type);
68
+ else
69
+ result = duplicate_per_byte (init_expr, type);
64
70
65
71
result.add_source_location ()=source_location;
66
72
return result;
@@ -69,10 +75,12 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
69
75
type_id==ID_real)
70
76
{
71
77
exprt result;
72
- if (nondet )
78
+ if (init_expr. id () == ID_nondet )
73
79
result = side_effect_expr_nondett (type, source_location);
74
- else
80
+ else if (init_expr. is_zero ())
75
81
result = constant_exprt (ID_0, type);
82
+ else
83
+ result = duplicate_per_byte (init_expr, type);
76
84
77
85
result.add_source_location ()=source_location;
78
86
return result;
@@ -81,33 +89,37 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
81
89
type_id==ID_verilog_unsignedbv)
82
90
{
83
91
exprt result;
84
- if (nondet )
92
+ if (init_expr. id () == ID_nondet )
85
93
result = side_effect_expr_nondett (type, source_location);
86
- else
94
+ else if (init_expr. is_zero ())
87
95
{
88
96
const std::size_t width = to_bitvector_type (type).get_width ();
89
97
std::string value (width, ' 0' );
90
98
91
99
result = constant_exprt (value, type);
92
100
}
101
+ else
102
+ result = duplicate_per_byte (init_expr, type);
93
103
94
104
result.add_source_location ()=source_location;
95
105
return result;
96
106
}
97
107
else if (type_id==ID_complex)
98
108
{
99
109
exprt result;
100
- if (nondet )
110
+ if (init_expr. id () == ID_nondet )
101
111
result = side_effect_expr_nondett (type, source_location);
102
- else
112
+ else if (init_expr. is_zero ())
103
113
{
104
- auto sub_zero =
105
- expr_initializer_rec ( to_complex_type (type).subtype (), source_location);
114
+ auto sub_zero = expr_initializer_rec (
115
+ to_complex_type (type).subtype (), source_location, init_expr );
106
116
if (!sub_zero.has_value ())
107
117
return {};
108
118
109
119
result = complex_exprt (*sub_zero, *sub_zero, to_complex_type (type));
110
120
}
121
+ else
122
+ result = duplicate_per_byte (init_expr, type);
111
123
112
124
result.add_source_location ()=source_location;
113
125
return result;
@@ -127,8 +139,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
127
139
}
128
140
else
129
141
{
130
- auto tmpval =
131
- expr_initializer_rec ( array_type.element_type (), source_location);
142
+ auto tmpval = expr_initializer_rec (
143
+ array_type.element_type (), source_location, init_expr );
132
144
if (!tmpval.has_value ())
133
145
return {};
134
146
@@ -137,7 +149,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
137
149
array_type.size ().id () == ID_infinity || !array_size.has_value () ||
138
150
*array_size > MAX_FLATTENED_ARRAY_SIZE)
139
151
{
140
- if (nondet )
152
+ if (init_expr. id () == ID_nondet )
141
153
return side_effect_expr_nondett (type, source_location);
142
154
143
155
array_of_exprt value (*tmpval, array_type);
@@ -159,8 +171,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
159
171
{
160
172
const vector_typet &vector_type=to_vector_type (type);
161
173
162
- auto tmpval =
163
- expr_initializer_rec ( vector_type.element_type (), source_location);
174
+ auto tmpval = expr_initializer_rec (
175
+ vector_type.element_type (), source_location, init_expr );
164
176
if (!tmpval.has_value ())
165
177
return {};
166
178
@@ -190,7 +202,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
190
202
DATA_INVARIANT (
191
203
c.type ().id () != ID_code, " struct member must not be of code type" );
192
204
193
- const auto member = expr_initializer_rec (c.type (), source_location);
205
+ const auto member =
206
+ expr_initializer_rec (c.type (), source_location, init_expr);
194
207
if (!member.has_value ())
195
208
return {};
196
209
@@ -216,8 +229,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
216
229
if (!widest_member.has_value ())
217
230
return {};
218
231
219
- auto component_value =
220
- expr_initializer_rec ( widest_member->first .type (), source_location);
232
+ auto component_value = expr_initializer_rec (
233
+ widest_member->first .type (), source_location, init_expr );
221
234
222
235
if (!component_value.has_value ())
223
236
return {};
@@ -230,7 +243,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
230
243
else if (type_id==ID_c_enum_tag)
231
244
{
232
245
auto result = expr_initializer_rec (
233
- ns.follow_tag (to_c_enum_tag_type (type)), source_location);
246
+ ns.follow_tag (to_c_enum_tag_type (type)), source_location, init_expr );
234
247
235
248
if (!result.has_value ())
236
249
return {};
@@ -243,7 +256,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
243
256
else if (type_id==ID_struct_tag)
244
257
{
245
258
auto result = expr_initializer_rec (
246
- ns.follow_tag (to_struct_tag_type (type)), source_location);
259
+ ns.follow_tag (to_struct_tag_type (type)), source_location, init_expr );
247
260
248
261
if (!result.has_value ())
249
262
return {};
@@ -256,7 +269,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
256
269
else if (type_id==ID_union_tag)
257
270
{
258
271
auto result = expr_initializer_rec (
259
- ns.follow_tag (to_union_tag_type (type)), source_location);
272
+ ns.follow_tag (to_union_tag_type (type)), source_location, init_expr );
260
273
261
274
if (!result.has_value ())
262
275
return {};
@@ -269,10 +282,12 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
269
282
else if (type_id==ID_string)
270
283
{
271
284
exprt result;
272
- if (nondet )
285
+ if (init_expr. id () == ID_nondet )
273
286
result = side_effect_expr_nondett (type, source_location);
274
- else
287
+ else if (init_expr. is_zero ())
275
288
result = constant_exprt (irep_idt (), type);
289
+ else
290
+ result = duplicate_per_byte (init_expr, type);
276
291
277
292
result.add_source_location ()=source_location;
278
293
return result;
@@ -292,7 +307,8 @@ optionalt<exprt> zero_initializer(
292
307
const source_locationt &source_location,
293
308
const namespacet &ns)
294
309
{
295
- return expr_initializert<false >(ns)(type, source_location);
310
+ return expr_initializert (ns)(
311
+ type, source_location, constant_exprt (ID_0, char_type ()));
296
312
}
297
313
298
314
// / Create a non-deterministic value for type `type`, with all subtypes
@@ -307,5 +323,91 @@ optionalt<exprt> nondet_initializer(
307
323
const source_locationt &source_location,
308
324
const namespacet &ns)
309
325
{
310
- return expr_initializert<true >(ns)(type, source_location);
326
+ return expr_initializert (ns)(type, source_location, exprt (ID_nondet));
327
+ }
328
+
329
+ // / Create a value for type `type`, with all subtype bytes
330
+ // / initialized to the given value.
331
+ // / \param type: Type of the target expression.
332
+ // / \param source_location: Location to record in all created sub-expressions.
333
+ // / \param ns: Namespace to perform type symbol/tag lookups.
334
+ // / \param init_byte_expr: Value to be used for initialization.
335
+ // / \return An expression if a byte-initialized expression of the input type
336
+ // / can be built.
337
+ optionalt<exprt> expr_initializer (
338
+ const typet &type,
339
+ const source_locationt &source_location,
340
+ const namespacet &ns,
341
+ const exprt &init_byte_expr)
342
+ {
343
+ return expr_initializert (ns)(type, source_location, init_byte_expr);
344
+ }
345
+
346
+ // / Builds an expression of the given output type with each of its bytes
347
+ // / initialized to the given initialization expression.
348
+ // / Integer bitvector types are currently supported.
349
+ // / For unsupported `output_type` the initialization expression is casted to the
350
+ // / output type.
351
+ // / \param init_byte_expr The initialization expression
352
+ // / \param output_type The output type
353
+ // / \return The built expression
354
+ // / \note `init_byte_expr` must be a boolean or a bitvector and must be of at
355
+ // / most `size <= config.ansi_c.char_width`
356
+ exprt duplicate_per_byte (const exprt &init_byte_expr, const typet &output_type)
357
+ {
358
+ const auto init_type_as_bitvector =
359
+ type_try_dynamic_cast<bitvector_typet>(init_byte_expr.type ());
360
+ // Fail if `init_byte_expr` is not a bitvector of maximum 8 bits or a boolean.
361
+ PRECONDITION (
362
+ (init_type_as_bitvector &&
363
+ init_type_as_bitvector->get_width () <= config.ansi_c .char_width ) ||
364
+ init_byte_expr.type ().id () == ID_bool);
365
+ if (const auto output_bv = type_try_dynamic_cast<bitvector_typet>(output_type))
366
+ {
367
+ const auto out_width = output_bv->get_width ();
368
+ // Replicate `init_byte_expr` enough times until it completely fills
369
+ // `output_type`.
370
+
371
+ // We've got a constant. So, precompute the value of the constant.
372
+ if (init_byte_expr.is_constant ())
373
+ {
374
+ const auto init_size = init_type_as_bitvector->get_width ();
375
+ const irep_idt init_value = to_constant_expr (init_byte_expr).get_value ();
376
+
377
+ // Create a new BV od `output_type` size with its representation being the
378
+ // replication of the init_byte_expr (padded with 0) enough times to fill.
379
+ const auto output_value =
380
+ make_bvrep (out_width, [&init_size, &init_value](std::size_t index ) {
381
+ // Index modded by 8 to access the i-th bit of init_value
382
+ const auto source_index = index % config.ansi_c .char_width ;
383
+ // If the modded i-th bit exists get it, otherwise add 0 padding.
384
+ return source_index < init_size &&
385
+ get_bvrep_bit (init_value, init_size, source_index);
386
+ });
387
+
388
+ return constant_exprt{output_value, output_type};
389
+ }
390
+
391
+ const size_t size =
392
+ (out_width + config.ansi_c .char_width - 1 ) / config.ansi_c .char_width ;
393
+
394
+ // We haven't got a constant. So, build the expression using shift-and-or.
395
+ exprt::operandst values;
396
+ // Let's cast init_byte_expr to output_type.
397
+ const exprt casted_init_byte_expr =
398
+ typecast_exprt::conditional_cast (init_byte_expr, output_type);
399
+ values.push_back (casted_init_byte_expr);
400
+ for (size_t i = 1 ; i < size; ++i)
401
+ {
402
+ values.push_back (shl_exprt (
403
+ casted_init_byte_expr,
404
+ from_integer (config.ansi_c .char_width * i, size_type ())));
405
+ }
406
+ if (values.size () == 1 )
407
+ return values[0 ];
408
+ return multi_ary_exprt (ID_bitor, values, output_type);
409
+ }
410
+
411
+ // Anything else. We don't know what to do with it. So, just cast.
412
+ return typecast_exprt::conditional_cast (init_byte_expr, output_type);
311
413
}
0 commit comments