Skip to content

Commit 6bc93f0

Browse files
committed
Simplify shifts of concatenations
We may be able to drop some of the operands of the concatenation and use all-zeros instead.
1 parent 6df204e commit 6bc93f0

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

src/util/simplify_expr_int.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,54 @@ simplify_exprt::simplify_shifts(const shift_exprt &expr)
10331033
if(*distance == 0)
10341034
return expr.op();
10351035

1036+
if(
1037+
expr.op().id() == ID_concatenation &&
1038+
(expr.id() == ID_lshr || expr.id() == ID_shl))
1039+
{
1040+
mp_integer offset = to_bitvector_type(expr.op().type()).get_width();
1041+
mp_integer bits_seen = 0;
1042+
for(std::size_t i = 0; i < expr.op().operands().size(); ++i)
1043+
{
1044+
if(expr.id() == ID_lshr && offset == *distance)
1045+
{
1046+
exprt::operandst new_operands;
1047+
new_operands.reserve(i + 1);
1048+
new_operands.push_back(
1049+
from_integer(0, bv_typet{numeric_cast_v<std::size_t>(*distance)}));
1050+
new_operands.insert(
1051+
new_operands.end(),
1052+
expr.op().operands().begin(),
1053+
expr.op().operands().begin() + i);
1054+
concatenation_exprt new_concat = to_concatenation_expr(expr.op());
1055+
new_concat.operands() = std::move(new_operands);
1056+
return changed(simplify_concatenation(new_concat));
1057+
}
1058+
1059+
auto op_width = pointer_offset_bits(expr.op().operands()[i].type(), ns);
1060+
1061+
if(!op_width.has_value() || *op_width <= 0)
1062+
return unchanged(expr);
1063+
1064+
offset -= *op_width;
1065+
bits_seen += *op_width;
1066+
1067+
if(expr.id() == ID_shl && bits_seen == *distance)
1068+
{
1069+
exprt::operandst new_operands;
1070+
new_operands.reserve(expr.op().operands().size() - i);
1071+
new_operands.insert(
1072+
new_operands.end(),
1073+
expr.op().operands().begin() + i + 1,
1074+
expr.op().operands().end());
1075+
new_operands.push_back(
1076+
from_integer(0, bv_typet{numeric_cast_v<std::size_t>(*distance)}));
1077+
concatenation_exprt new_concat = to_concatenation_expr(expr.op());
1078+
new_concat.operands() = std::move(new_operands);
1079+
return changed(simplify_concatenation(new_concat));
1080+
}
1081+
}
1082+
}
1083+
10361084
auto value = numeric_cast<mp_integer>(expr.op());
10371085

10381086
if(

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 lshr of concatenation", "[core][util]")
657+
{
658+
const symbol_tablet symbol_table;
659+
const namespacet ns{symbol_table};
660+
661+
const unsignedbv_typet u8{8};
662+
const unsignedbv_typet u16{16};
663+
const symbol_exprt a{"a", u8};
664+
const symbol_exprt b{"b", u8};
665+
const concatenation_exprt cat{{a, b}, u16};
666+
667+
// (concat(a, b)) >> 8 -> concat(0x00, a)
668+
const lshr_exprt lshr{cat, from_integer(8, u16)};
669+
const concatenation_exprt expected{{from_integer(0, bv_typet{8}), a}, u16};
670+
REQUIRE(simplify_expr(lshr, ns) == expected);
671+
}
672+
673+
TEST_CASE("Simplify shl of concatenation", "[core][util]")
674+
{
675+
const symbol_tablet symbol_table;
676+
const namespacet ns{symbol_table};
677+
678+
const unsignedbv_typet u8{8};
679+
const unsignedbv_typet u16{16};
680+
const symbol_exprt a{"a", u8};
681+
const symbol_exprt b{"b", u8};
682+
const concatenation_exprt cat{{a, b}, u16};
683+
684+
// (concat(a, b)) << 8 -> concat(b, 0x00)
685+
const shl_exprt shl{cat, from_integer(8, u16)};
686+
const concatenation_exprt expected{{b, from_integer(0, bv_typet{8})}, u16};
687+
REQUIRE(simplify_expr(shl, ns) == expected);
688+
}

0 commit comments

Comments
 (0)