Skip to content

Commit 477fcdc

Browse files
committed
Simplify bitwise operations over concatenation and a constant
Perform point-wise application of the bitwise operation and concatenate the result: if some of the operands of the concatenation were constants the bitwise operation will yield modified constants.
1 parent 6df204e commit 477fcdc

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

src/util/simplify_expr_int.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,48 @@ simplify_exprt::simplify_bitwise(const multi_ary_exprt &expr)
832832
if(new_expr.operands().size() == 1)
833833
return new_expr.op0();
834834

835+
if(
836+
new_expr.operands().size() == 2 &&
837+
(new_expr.operands().front().is_constant() ||
838+
new_expr.operands().back().is_constant()) &&
839+
(new_expr.operands().front().id() == ID_concatenation ||
840+
new_expr.operands().back().id() == ID_concatenation))
841+
{
842+
const exprt &constant = new_expr.operands().front().is_constant()
843+
? new_expr.operands().front()
844+
: new_expr.operands().back();
845+
const auto svalue = expr2bits(constant, true, ns);
846+
CHECK_RETURN(svalue.has_value());
847+
CHECK_RETURN(svalue->size() == width);
848+
849+
concatenation_exprt new_concat =
850+
new_expr.operands().front().id() == ID_concatenation
851+
? to_concatenation_expr(new_expr.operands().front())
852+
: to_concatenation_expr(new_expr.operands().back());
853+
// the most-significant bit comes first in an concatenation_exprt, hence we
854+
// count down
855+
std::size_t offset = width;
856+
for(auto &op : new_concat.operands())
857+
{
858+
auto op_width = pointer_offset_bits(op.type(), ns);
859+
CHECK_RETURN(op_width.has_value());
860+
CHECK_RETURN(*op_width > 0);
861+
CHECK_RETURN(*op_width <= offset);
862+
std::size_t op_width_int = numeric_cast_v<std::size_t>(*op_width);
863+
864+
std::string extracted_value =
865+
svalue->substr(offset - op_width_int, op_width_int);
866+
867+
auto op_bits = bits2expr(extracted_value, op.type(), true, ns);
868+
CHECK_RETURN(op_bits.has_value());
869+
op = simplify_bitwise(multi_ary_exprt{op, expr.id(), *op_bits}).expr;
870+
871+
offset -= op_width_int;
872+
}
873+
874+
return changed(simplify_concatenation(new_concat));
875+
}
876+
835877
if(no_change)
836878
return unchanged(expr);
837879
else

unit/util/simplify_expr.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,3 +652,67 @@ TEST_CASE("Simplify quantifier", "[core][util]")
652652
REQUIRE(simplify_expr(forall_exprt{a, true_exprt{}}, ns) == true_exprt{});
653653
}
654654
}
655+
656+
657+
TEST_CASE("Simplify double typecast over bv types", "[core][util]")
658+
{
659+
const symbol_tablet symbol_table;
660+
const namespacet ns{symbol_table};
661+
662+
// (unsigned)(signed)x where x is unsigned and same width -> x
663+
const unsignedbv_typet u32{32};
664+
const signedbv_typet s32{32};
665+
const symbol_exprt x{"x", u32};
666+
const typecast_exprt inner{x, s32};
667+
const typecast_exprt outer{inner, u32};
668+
REQUIRE(simplify_expr(outer, ns) == x);
669+
}
670+
671+
672+
TEST_CASE("Simplify (x * n) % n", "[core][util]")
673+
{
674+
const symbol_tablet symbol_table;
675+
const namespacet ns{symbol_table};
676+
677+
const unsignedbv_typet u32{32};
678+
const symbol_exprt x{"x", u32};
679+
const constant_exprt n = from_integer(7, u32);
680+
const mult_exprt mul{x, n};
681+
const mod_exprt mod{mul, n};
682+
const auto result = simplify_expr(mod, ns);
683+
REQUIRE(result == from_integer(0, u32));
684+
}
685+
686+
687+
TEST_CASE("Simplify all-zero constant in bitand", "[core][util]")
688+
{
689+
const symbol_tablet symbol_table;
690+
const namespacet ns{symbol_table};
691+
692+
const bv_typet bv8{8};
693+
const symbol_exprt x{"x", bv8};
694+
const constant_exprt zero = bv8.all_zeros_expr();
695+
const bitand_exprt band{x, zero};
696+
const auto result = simplify_expr(band, ns);
697+
REQUIRE(result == zero);
698+
}
699+
700+
701+
TEST_CASE("Simplify bitand over concatenation and constant", "[core][util]")
702+
{
703+
const symbol_tablet symbol_table;
704+
const namespacet ns{symbol_table};
705+
706+
// (concat(a, b)) & 0x00FF -> concat(0x00, b & 0xFF)
707+
const bv_typet bv8{8};
708+
const bv_typet bv16{16};
709+
const symbol_exprt a{"a", bv8};
710+
const symbol_exprt b{"b", bv8};
711+
const concatenation_exprt cat{{a, b}, bv16};
712+
const constant_exprt mask = from_integer(0xFF, bv16);
713+
const bitand_exprt band{cat, mask};
714+
const auto result = simplify_expr(band, ns);
715+
// Result should not contain the original bitand over concatenation
716+
REQUIRE((result.id() != ID_bitand || result != band));
717+
}
718+

0 commit comments

Comments
 (0)