@@ -12,37 +12,41 @@ Author: Daniel Kroening, kroening@kroening.com
1212#include " expr_initializer.h"
1313
1414#include " arith_tools.h"
15+ #include " bitvector_expr.h"
1516#include " c_types.h"
17+ #include " config.h"
1618#include " magic.h"
1719#include " namespace.h" // IWYU pragma: keep
1820#include " std_code.h"
1921
20- template <bool nondet>
2122class expr_initializert
2223{
2324public:
2425 explicit expr_initializert (const namespacet &_ns) : ns(_ns)
2526 {
2627 }
2728
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)
3033 {
31- return expr_initializer_rec (type, source_location);
34+ return expr_initializer_rec (type, source_location, init_expr );
3235 }
3336
3437protected:
3538 const namespacet &ns;
3639
3740 optionalt<exprt> expr_initializer_rec (
3841 const typet &type,
39- const source_locationt &source_location);
42+ const source_locationt &source_location,
43+ const exprt &init_expr);
4044};
4145
42- template <bool nondet>
43- optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
46+ optionalt<exprt> expr_initializert::expr_initializer_rec (
4447 const typet &type,
45- const source_locationt &source_location)
48+ const source_locationt &source_location,
49+ const exprt &init_expr)
4650{
4751 const irep_idt &type_id=type.id ();
4852
@@ -57,10 +61,12 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
5761 type_id==ID_fixedbv)
5862 {
5963 exprt result;
60- if (nondet )
64+ if (init_expr. id () == ID_nondet )
6165 result = side_effect_expr_nondett (type, source_location);
62- else
66+ else if (init_expr. is_zero ())
6367 result = from_integer (0 , type);
68+ else
69+ result = duplicate_per_byte (init_expr, type);
6470
6571 result.add_source_location ()=source_location;
6672 return result;
@@ -69,10 +75,12 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
6975 type_id==ID_real)
7076 {
7177 exprt result;
72- if (nondet )
78+ if (init_expr. id () == ID_nondet )
7379 result = side_effect_expr_nondett (type, source_location);
74- else
80+ else if (init_expr. is_zero ())
7581 result = constant_exprt (ID_0, type);
82+ else
83+ result = duplicate_per_byte (init_expr, type);
7684
7785 result.add_source_location ()=source_location;
7886 return result;
@@ -81,33 +89,37 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
8189 type_id==ID_verilog_unsignedbv)
8290 {
8391 exprt result;
84- if (nondet )
92+ if (init_expr. id () == ID_nondet )
8593 result = side_effect_expr_nondett (type, source_location);
86- else
94+ else if (init_expr. is_zero ())
8795 {
8896 const std::size_t width = to_bitvector_type (type).get_width ();
8997 std::string value (width, ' 0' );
9098
9199 result = constant_exprt (value, type);
92100 }
101+ else
102+ result = duplicate_per_byte (init_expr, type);
93103
94104 result.add_source_location ()=source_location;
95105 return result;
96106 }
97107 else if (type_id==ID_complex)
98108 {
99109 exprt result;
100- if (nondet )
110+ if (init_expr. id () == ID_nondet )
101111 result = side_effect_expr_nondett (type, source_location);
102- else
112+ else if (init_expr. is_zero ())
103113 {
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 );
106116 if (!sub_zero.has_value ())
107117 return {};
108118
109119 result = complex_exprt (*sub_zero, *sub_zero, to_complex_type (type));
110120 }
121+ else
122+ result = duplicate_per_byte (init_expr, type);
111123
112124 result.add_source_location ()=source_location;
113125 return result;
@@ -127,8 +139,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
127139 }
128140 else
129141 {
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 );
132144 if (!tmpval.has_value ())
133145 return {};
134146
@@ -137,7 +149,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
137149 array_type.size ().id () == ID_infinity || !array_size.has_value () ||
138150 *array_size > MAX_FLATTENED_ARRAY_SIZE)
139151 {
140- if (nondet )
152+ if (init_expr. id () == ID_nondet )
141153 return side_effect_expr_nondett (type, source_location);
142154
143155 array_of_exprt value (*tmpval, array_type);
@@ -159,8 +171,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
159171 {
160172 const vector_typet &vector_type=to_vector_type (type);
161173
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 );
164176 if (!tmpval.has_value ())
165177 return {};
166178
@@ -190,7 +202,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
190202 DATA_INVARIANT (
191203 c.type ().id () != ID_code, " struct member must not be of code type" );
192204
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);
194207 if (!member.has_value ())
195208 return {};
196209
@@ -216,8 +229,8 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
216229 if (!widest_member.has_value ())
217230 return {};
218231
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 );
221234
222235 if (!component_value.has_value ())
223236 return {};
@@ -230,7 +243,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
230243 else if (type_id==ID_c_enum_tag)
231244 {
232245 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 );
234247
235248 if (!result.has_value ())
236249 return {};
@@ -243,7 +256,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
243256 else if (type_id==ID_struct_tag)
244257 {
245258 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 );
247260
248261 if (!result.has_value ())
249262 return {};
@@ -256,7 +269,7 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
256269 else if (type_id==ID_union_tag)
257270 {
258271 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 );
260273
261274 if (!result.has_value ())
262275 return {};
@@ -269,10 +282,12 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
269282 else if (type_id==ID_string)
270283 {
271284 exprt result;
272- if (nondet )
285+ if (init_expr. id () == ID_nondet )
273286 result = side_effect_expr_nondett (type, source_location);
274- else
287+ else if (init_expr. is_zero ())
275288 result = constant_exprt (irep_idt (), type);
289+ else
290+ result = duplicate_per_byte (init_expr, type);
276291
277292 result.add_source_location ()=source_location;
278293 return result;
@@ -292,7 +307,8 @@ optionalt<exprt> zero_initializer(
292307 const source_locationt &source_location,
293308 const namespacet &ns)
294309{
295- return expr_initializert<false >(ns)(type, source_location);
310+ return expr_initializert (ns)(
311+ type, source_location, constant_exprt (ID_0, char_type ()));
296312}
297313
298314// / Create a non-deterministic value for type `type`, with all subtypes
@@ -307,5 +323,91 @@ optionalt<exprt> nondet_initializer(
307323 const source_locationt &source_location,
308324 const namespacet &ns)
309325{
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);
311413}
0 commit comments