@@ -346,39 +346,61 @@ optionalt<exprt> expr_initializer(
346
346
// / Builds an expression of the given output type with each of its bytes
347
347
// / initialized to the given initialization expression.
348
348
// / Integer bitvector types are currently supported.
349
- // / For unsupported types the initialization expression is casted to the
349
+ // / For unsupported `output_type` the initialization expression is casted to the
350
350
// / output type.
351
351
// / \param init_byte_expr The initialization expression
352
352
// / \param output_type The output type
353
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`
354
356
exprt duplicate_per_byte (const exprt &init_byte_expr, const typet &output_type)
355
357
{
356
- if (output_type.id () == ID_unsignedbv || output_type.id () == ID_signedbv)
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))
357
366
{
358
- const size_t size =
359
- to_bitvector_type (output_type).get_width () / config.ansi_c .char_width ;
367
+ const auto out_width = output_bv->get_width ();
368
+ // Replicate `init_byte_expr` enough times until it completely fills
369
+ // `output_type`.
360
370
361
371
// We've got a constant. So, precompute the value of the constant.
362
372
if (init_byte_expr.is_constant ())
363
373
{
364
- const mp_integer value =
365
- numeric_cast_v<mp_integer>(to_constant_expr (init_byte_expr));
366
- mp_integer duplicated_value = value;
367
- for (size_t i = 1 ; i < size; ++i)
368
- {
369
- duplicated_value =
370
- bitwise_or (duplicated_value << config.ansi_c .char_width , value);
371
- }
372
- return from_integer (duplicated_value, output_type);
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};
373
389
}
374
390
391
+ const size_t size =
392
+ (out_width + config.ansi_c .char_width - 1 ) / config.ansi_c .char_width ;
393
+
375
394
// We haven't got a constant. So, build the expression using shift-and-or.
376
395
exprt::operandst values;
377
- values.push_back (init_byte_expr);
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);
378
400
for (size_t i = 1 ; i < size; ++i)
379
401
{
380
402
values.push_back (shl_exprt (
381
- init_byte_expr ,
403
+ casted_init_byte_expr ,
382
404
from_integer (config.ansi_c .char_width * i, size_type ())));
383
405
}
384
406
if (values.size () == 1 )
0 commit comments