Skip to content

Commit 70aec8f

Browse files
committed
introduce zero_extend expression
This introduces the zero_extend expression, which, given a bit-vector operand and a type, either a) pads the given operand with zeros from the left if the given type is wider than the type of the operand, or b) truncates the operand to the width of the given type if the given type is smaller than the operand, or c) casts the operand to the given type if the width of the type and the width of the operand match. This is easier to read and less prone to error than the current pattern, in which the operand is 1) converted to an unsigned type of the same width, and then 2) casted to an unsigned type of the wider width, and 3) finally casted to the target type.
1 parent cd513b5 commit 70aec8f

File tree

8 files changed

+78
-10
lines changed

8 files changed

+78
-10
lines changed

src/solvers/flattening/boolbv.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
165165
return convert_replication(to_replication_expr(expr));
166166
else if(expr.id()==ID_extractbits)
167167
return convert_extractbits(to_extractbits_expr(expr));
168+
else if(expr.id() == ID_zero_extend)
169+
return convert_bitvector(to_zero_extend_expr(expr).lower());
168170
else if(expr.id()==ID_bitnot || expr.id()==ID_bitand ||
169171
expr.id()==ID_bitor || expr.id()==ID_bitxor ||
170172
expr.id()==ID_bitxnor || expr.id()==ID_bitnor ||

src/solvers/floatbv/float_bv.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,8 +692,10 @@ exprt float_bvt::mul(
692692

693693
// zero-extend the fractions (unpacked fraction has the hidden bit)
694694
typet new_fraction_type=unsignedbv_typet((spec.f+1)*2);
695-
const exprt fraction1=typecast_exprt(unpacked1.fraction, new_fraction_type);
696-
const exprt fraction2=typecast_exprt(unpacked2.fraction, new_fraction_type);
695+
const exprt fraction1 =
696+
zero_extend_exprt{unpacked1.fraction, new_fraction_type};
697+
const exprt fraction2 =
698+
zero_extend_exprt{unpacked2.fraction, new_fraction_type};
697699

698700
// multiply the fractions
699701
unbiased_floatt result;
@@ -750,7 +752,7 @@ exprt float_bvt::div(
750752
unsignedbv_typet(div_width));
751753

752754
// zero-extend fraction2 to match fraction1
753-
const typecast_exprt fraction2(unpacked2.fraction, fraction1.type());
755+
const zero_extend_exprt fraction2{unpacked2.fraction, fraction1.type()};
754756

755757
// divide fractions
756758
unbiased_floatt result;

src/solvers/smt2/smt2_conv.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,6 +2456,10 @@ void smt2_convt::convert_expr(const exprt &expr)
24562456
{
24572457
convert_expr(simplify_expr(to_bitreverse_expr(expr).lower(), ns));
24582458
}
2459+
else if(expr.id() == ID_zero_extend)
2460+
{
2461+
convert_expr(to_zero_extend_expr(expr).lower());
2462+
}
24592463
else if(expr.id() == ID_function_application)
24602464
{
24612465
const auto &function_application_expr = to_function_application_expr(expr);

src/util/bitvector_expr.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ exprt update_bit_exprt::lower() const
5454
typecast_exprt(src(), src_bv_type), bitnot_exprt(mask_shifted));
5555

5656
// zero-extend the replacement bit to match src
57-
auto new_value_casted = typecast_exprt(
58-
typecast_exprt(new_value(), unsignedbv_typet(width)), src_bv_type);
57+
auto new_value_casted = zero_extend_exprt{new_value(), src_bv_type};
5958

6059
// shift the replacement bits
6160
auto new_value_shifted = shl_exprt(new_value_casted, index());
@@ -85,7 +84,7 @@ exprt update_bits_exprt::lower() const
8584
bitand_exprt(typecast_exprt(src(), src_bv_type), mask_shifted);
8685

8786
// zero-extend or shrink the replacement bits to match src
88-
auto new_value_casted = typecast_exprt(new_value(), src_bv_type);
87+
auto new_value_casted = zero_extend_exprt{new_value(), src_bv_type};
8988

9089
// shift the replacement bits
9190
auto new_value_shifted = shl_exprt(new_value_casted, index());
@@ -279,3 +278,21 @@ exprt find_first_set_exprt::lower() const
279278

280279
return typecast_exprt::conditional_cast(result, type());
281280
}
281+
282+
exprt zero_extend_exprt::lower() const
283+
{
284+
const auto old_width = to_bitvector_type(op().type()).get_width();
285+
const auto new_width = to_bitvector_type(type()).get_width();
286+
287+
if(new_width > old_width)
288+
{
289+
return concatenation_exprt{
290+
bv_typet{new_width - old_width}.all_zeros_expr(), op(), type()};
291+
}
292+
else if(new_width < old_width)
293+
{
294+
return extractbits_exprt{op(), integer_typet{}.zero_expr(), type()};
295+
}
296+
else // old_width == new_width
297+
return typecast_exprt::conditional_cast(op(), type());
298+
}

src/util/bitvector_expr.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,4 +1663,42 @@ inline find_first_set_exprt &to_find_first_set_expr(exprt &expr)
16631663
return ret;
16641664
}
16651665

1666+
/// \brief zero extension
1667+
/// The operand is converted to the given type by either
1668+
/// a) truncating if the new type is shorter, or
1669+
/// b) padding with most-significant zero bits if the new type is larger, or
1670+
/// c) casts the operand to the type if their widths match.
1671+
class zero_extend_exprt : public unary_exprt
1672+
{
1673+
public:
1674+
zero_extend_exprt(exprt _op, typet _type)
1675+
: unary_exprt(ID_zero_extend, std::move(_op), std::move(_type))
1676+
{
1677+
}
1678+
1679+
// a lowering to extraction or concatenation
1680+
exprt lower() const;
1681+
};
1682+
1683+
/// \brief Cast an exprt to a \ref zero_extend_exprt
1684+
///
1685+
/// \a expr must be known to be \ref zero_extend_exprt.
1686+
///
1687+
/// \param expr: Source expression
1688+
/// \return Object of type \ref zero_extend_exprt
1689+
inline const zero_extend_exprt &to_zero_extend_expr(const exprt &expr)
1690+
{
1691+
PRECONDITION(expr.id() == ID_zero_extend);
1692+
zero_extend_exprt::check(expr);
1693+
return static_cast<const zero_extend_exprt &>(expr);
1694+
}
1695+
1696+
/// \copydoc to_zero_extend_expr(const exprt &)
1697+
inline zero_extend_exprt &to_zero_extend_expr(exprt &expr)
1698+
{
1699+
PRECONDITION(expr.id() == ID_zero_extend);
1700+
zero_extend_exprt::check(expr);
1701+
return static_cast<zero_extend_exprt &>(expr);
1702+
}
1703+
16661704
#endif // CPROVER_UTIL_BITVECTOR_EXPR_H

src/util/format_expr.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,13 @@ void format_expr_configt::setup()
363363
<< format(expr.type()) << ')';
364364
};
365365

366+
expr_map[ID_zero_extend] =
367+
[](std::ostream &os, const exprt &expr) -> std::ostream &
368+
{
369+
return os << "zero_extend(" << format(to_zero_extend_expr(expr).op())
370+
<< ", " << format(expr.type()) << ')';
371+
};
372+
366373
expr_map[ID_floatbv_typecast] =
367374
[](std::ostream &os, const exprt &expr) -> std::ostream & {
368375
const auto &floatbv_typecast_expr = to_floatbv_typecast_expr(expr);

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ IREP_ID_ONE(extractbit)
188188
IREP_ID_ONE(extractbits)
189189
IREP_ID_ONE(update_bit)
190190
IREP_ID_ONE(update_bits)
191+
IREP_ID_ONE(zero_extend)
191192
IREP_ID_TWO(C_reference, #reference)
192193
IREP_ID_TWO(C_rvalue_reference, #rvalue_reference)
193194
IREP_ID_ONE(true)

src/util/lower_byte_operators.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2491,10 +2491,7 @@ static exprt lower_byte_update(
24912491
exprt zero_extended;
24922492
if(bit_width > update_size_bits)
24932493
{
2494-
zero_extended = concatenation_exprt{
2495-
bv_typet{bit_width - update_size_bits}.all_zeros_expr(),
2496-
value,
2497-
bv_typet{bit_width}};
2494+
zero_extended = zero_extend_exprt{value, bv_typet{bit_width}};
24982495

24992496
if(!is_little_endian)
25002497
to_concatenation_expr(zero_extended)

0 commit comments

Comments
 (0)