Skip to content

Commit 3418989

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 3418989

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

src/util/simplify_expr_int.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,17 @@ simplify_exprt::simplify_bitwise(const multi_ary_exprt &expr)
813813
else
814814
it++;
815815
}
816+
817+
// x & 0 -> 0
818+
for(const auto &op : new_expr.operands())
819+
{
820+
if(
821+
op.is_constant() &&
822+
bvrep2integer(to_constant_expr(op).get_value(), width, false) == 0)
823+
{
824+
return constant_exprt(integer2bvrep(0, width), new_expr.type());
825+
}
826+
}
816827
}
817828

818829
// two operands that are syntactically the same
@@ -832,6 +843,48 @@ simplify_exprt::simplify_bitwise(const multi_ary_exprt &expr)
832843
if(new_expr.operands().size() == 1)
833844
return new_expr.op0();
834845

846+
if(
847+
new_expr.operands().size() == 2 &&
848+
(new_expr.operands().front().is_constant() ||
849+
new_expr.operands().back().is_constant()) &&
850+
(new_expr.operands().front().id() == ID_concatenation ||
851+
new_expr.operands().back().id() == ID_concatenation))
852+
{
853+
const exprt &constant = new_expr.operands().front().is_constant()
854+
? new_expr.operands().front()
855+
: new_expr.operands().back();
856+
const auto svalue = expr2bits(constant, true, ns);
857+
CHECK_RETURN(svalue.has_value());
858+
CHECK_RETURN(svalue->size() == width);
859+
860+
concatenation_exprt new_concat =
861+
new_expr.operands().front().id() == ID_concatenation
862+
? to_concatenation_expr(new_expr.operands().front())
863+
: to_concatenation_expr(new_expr.operands().back());
864+
// the most-significant bit comes first in an concatenation_exprt, hence we
865+
// count down
866+
std::size_t offset = width;
867+
for(auto &op : new_concat.operands())
868+
{
869+
auto op_width = pointer_offset_bits(op.type(), ns);
870+
CHECK_RETURN(op_width.has_value());
871+
CHECK_RETURN(*op_width > 0);
872+
CHECK_RETURN(*op_width <= offset);
873+
std::size_t op_width_int = numeric_cast_v<std::size_t>(*op_width);
874+
875+
std::string extracted_value =
876+
svalue->substr(offset - op_width_int, op_width_int);
877+
878+
auto op_bits = bits2expr(extracted_value, op.type(), true, ns);
879+
CHECK_RETURN(op_bits.has_value());
880+
op = simplify_bitwise(multi_ary_exprt{op, expr.id(), *op_bits}).expr;
881+
882+
offset -= op_width_int;
883+
}
884+
885+
return changed(simplify_concatenation(new_concat));
886+
}
887+
835888
if(no_change)
836889
return unchanged(expr);
837890
else

unit/util/simplify_expr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,3 +652,37 @@ TEST_CASE("Simplify quantifier", "[core][util]")
652652
REQUIRE(simplify_expr(forall_exprt{a, true_exprt{}}, ns) == true_exprt{});
653653
}
654654
}
655+
656+
TEST_CASE("Simplify all-zero constant in bitand", "[core][util]")
657+
{
658+
const symbol_tablet symbol_table;
659+
const namespacet ns{symbol_table};
660+
661+
const unsignedbv_typet u8{8};
662+
const symbol_exprt x{"x", u8};
663+
const constant_exprt zero = from_integer(0, u8);
664+
const bitand_exprt band{x, zero};
665+
const auto result = simplify_expr(band, ns);
666+
REQUIRE(result == zero);
667+
}
668+
669+
TEST_CASE("Simplify bitand over concatenation and constant", "[core][util]")
670+
{
671+
const symbol_tablet symbol_table;
672+
const namespacet ns{symbol_table};
673+
674+
// (concat(a, b)) & 0x00FF -> concat(0x00, b & 0xFF)
675+
const unsignedbv_typet u8{8};
676+
const unsignedbv_typet u16{16};
677+
const symbol_exprt a{"a", u8};
678+
const symbol_exprt b{"b", u8};
679+
const concatenation_exprt cat{{a, b}, u16};
680+
const constant_exprt mask = from_integer(0xFF, u16);
681+
const bitand_exprt band{cat, mask};
682+
const auto result = simplify_expr(band, ns);
683+
684+
// Expect concat(0x00, b) because a & 0x00 -> 0x00 and b & 0xFF -> b
685+
const constant_exprt zero8 = from_integer(0, u8);
686+
const concatenation_exprt expected{{zero8, b}, u16};
687+
REQUIRE(result == expected);
688+
}

0 commit comments

Comments
 (0)