@@ -346,39 +346,61 @@ optionalt<exprt> expr_initializer(
346346// / Builds an expression of the given output type with each of its bytes
347347// / initialized to the given initialization expression.
348348// / 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
350350// / output type.
351351// / \param init_byte_expr The initialization expression
352352// / \param output_type The output type
353353// / \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`
354356exprt duplicate_per_byte (const exprt &init_byte_expr, const typet &output_type)
355357{
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))
357366 {
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`.
360370
361371 // We've got a constant. So, precompute the value of the constant.
362372 if (init_byte_expr.is_constant ())
363373 {
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};
373389 }
374390
391+ const size_t size =
392+ (out_width + config.ansi_c .char_width - 1 ) / config.ansi_c .char_width ;
393+
375394 // We haven't got a constant. So, build the expression using shift-and-or.
376395 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);
378400 for (size_t i = 1 ; i < size; ++i)
379401 {
380402 values.push_back (shl_exprt (
381- init_byte_expr ,
403+ casted_init_byte_expr ,
382404 from_integer (config.ansi_c .char_width * i, size_type ())));
383405 }
384406 if (values.size () == 1 )
0 commit comments