Skip to content

Commit 2e9fef5

Browse files
author
Enrico Steffinlongo
committed
Improved checks and fixed duplicate_per_byte
Function `duplicate_per_byte` now has a PRECONDITION checking that the `init_byte_expr` is either a boolean or a bitvector of maximum size 8. Also the computation of the number of duplication correctly accounts the case when the destination is not divisible by 8. In this case the input is duplicated one extra (including the sign bit if any) time and then truncated to the output size.
1 parent fe6c7d7 commit 2e9fef5

File tree

1 file changed

+39
-15
lines changed

1 file changed

+39
-15
lines changed

src/util/expr_initializer.cpp

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -346,39 +346,63 @@ 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`
354356
exprt 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 = make_bvrep(
380+
out_width,
381+
[&init_size, &init_value](std::size_t index)
382+
{
383+
// Index modded by 8 to access the i-th bit of init_value
384+
const auto source_index = index % config.ansi_c.char_width;
385+
// If the modded i-th bit exists get it, otherwise add 0 padding.
386+
return source_index < init_size &&
387+
get_bvrep_bit(init_value, init_size, source_index);
388+
});
389+
390+
return constant_exprt{output_value, output_type};
373391
}
374392

393+
const size_t size =
394+
(out_width + config.ansi_c.char_width - 1) / config.ansi_c.char_width;
395+
375396
// We haven't got a constant. So, build the expression using shift-and-or.
376397
exprt::operandst values;
377-
values.push_back(init_byte_expr);
398+
// Let's cast init_byte_expr to output_type.
399+
const exprt casted_init_byte_expr =
400+
typecast_exprt::conditional_cast(init_byte_expr, output_type);
401+
values.push_back(casted_init_byte_expr);
378402
for(size_t i = 1; i < size; ++i)
379403
{
380404
values.push_back(shl_exprt(
381-
init_byte_expr,
405+
casted_init_byte_expr,
382406
from_integer(config.ansi_c.char_width * i, size_type())));
383407
}
384408
if(values.size() == 1)

0 commit comments

Comments
 (0)