Skip to content

Commit 9a0bc60

Browse files
committed
Simplify more cases of extractbits over concatenation
We may be able to drop some of the operands of a concatenation.
1 parent 6df204e commit 9a0bc60

2 files changed

Lines changed: 77 additions & 11 deletions

File tree

src/util/simplify_expr_int.cpp

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,30 +1205,64 @@ simplify_exprt::simplify_extractbits(const extractbits_exprt &expr)
12051205

12061206
return std::move(*result);
12071207
}
1208+
else if(*end == 0 && *start + 1 == *width)
1209+
{
1210+
typecast_exprt tc{expr.src(), expr.type()};
1211+
return changed(simplify_typecast(tc));
1212+
}
12081213
else if(expr.src().id() == ID_concatenation)
12091214
{
12101215
// the most-significant bit comes first in an concatenation_exprt, hence we
12111216
// count down
12121217
mp_integer offset = *width;
12131218

1219+
exprt::operandst new_operands;
1220+
new_operands.reserve(expr.src().operands().size());
1221+
mp_integer new_index = *end;
1222+
mp_integer new_concat_width = 0;
1223+
12141224
for(const auto &op : expr.src().operands())
12151225
{
12161226
auto op_width = pointer_offset_bits(op.type(), ns);
12171227

12181228
if(!op_width.has_value() || *op_width <= 0)
12191229
return unchanged(expr);
12201230

1221-
if(*start < offset && offset <= *end + *op_width)
1231+
// current value of offset is the index (within the concatenated
1232+
// expression) of the most-significant bit of op plus 1
1233+
if(*end >= offset)
1234+
{
1235+
// Operand is entirely below the extracted range.
1236+
// Adjust new_index to account for the removed operand.
1237+
new_index -= *op_width;
1238+
}
1239+
else if(offset - *op_width <= *start)
12221240
{
1223-
extractbits_exprt result = expr;
1224-
result.src() = op;
1225-
result.index() =
1226-
from_integer(*end - (offset - *op_width), expr.index().type());
1227-
return changed(simplify_extractbits(result));
1241+
new_operands.push_back(op);
1242+
new_concat_width += *op_width;
12281243
}
12291244

12301245
offset -= *op_width;
12311246
}
1247+
1248+
if(new_operands.size() == 1)
1249+
{
1250+
extractbits_exprt result = expr;
1251+
result.src() = new_operands.front();
1252+
result.index() = from_integer(new_index, expr.index().type());
1253+
return changed(simplify_extractbits(result));
1254+
}
1255+
else if(
1256+
!new_operands.empty() &&
1257+
new_operands.size() < expr.src().operands().size())
1258+
{
1259+
extractbits_exprt result = expr;
1260+
result.src().operands() = new_operands;
1261+
to_bitvector_type(result.src().type())
1262+
.set_width(numeric_cast_v<std::size_t>(new_concat_width));
1263+
result.index() = from_integer(new_index, expr.index().type());
1264+
return changed(simplify_extractbits(result));
1265+
}
12321266
}
12331267
else if(auto eb_src = expr_try_dynamic_cast<extractbits_exprt>(expr.src()))
12341268
{
@@ -1242,11 +1276,6 @@ simplify_exprt::simplify_extractbits(const extractbits_exprt &expr)
12421276
return changed(simplify_extractbits(result));
12431277
}
12441278
}
1245-
else if(*end == 0 && *start + 1 == *width)
1246-
{
1247-
typecast_exprt tc{expr.src(), expr.type()};
1248-
return changed(simplify_typecast(tc));
1249-
}
12501279

12511280
return unchanged(expr);
12521281
}

unit/util/simplify_expr.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,3 +652,40 @@ 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 extractbits over concatenation", "[core][util]")
657+
{
658+
const symbol_tablet symbol_table;
659+
const namespacet ns{symbol_table};
660+
661+
// extractbits(concat(a, b), 0, u8) where a,b are 8-bit -> b
662+
const unsignedbv_typet u8{8};
663+
const unsignedbv_typet u16{16};
664+
const symbol_exprt a{"a", u8};
665+
const symbol_exprt b{"b", u8};
666+
const concatenation_exprt cat{{a, b}, u16};
667+
const extractbits_exprt extract{cat, from_integer(0, u16), u8};
668+
const auto result = simplify_expr(extract, ns);
669+
REQUIRE(result == b);
670+
}
671+
672+
TEST_CASE("Simplify extractbits dropping trailing operand", "[core][util]")
673+
{
674+
const symbol_tablet symbol_table;
675+
const namespacet ns{symbol_table};
676+
677+
// extractbits(concat(a, b, c), start=23, end=8) where a,b,c are 8-bit
678+
// should drop c and simplify to concat(a, b) or equivalent
679+
const unsignedbv_typet u8{8};
680+
const unsignedbv_typet u16{16};
681+
const unsignedbv_typet u24{24};
682+
const symbol_exprt a{"a", u8};
683+
const symbol_exprt b{"b", u8};
684+
const symbol_exprt c{"c", u8};
685+
const concatenation_exprt cat{{a, b, c}, u24};
686+
const extractbits_exprt extract{cat, from_integer(8, u24), u16};
687+
const auto result = simplify_expr(extract, ns);
688+
// c is entirely below the extracted range and should be dropped
689+
const concatenation_exprt expected{{a, b}, u16};
690+
REQUIRE(result == expected);
691+
}

0 commit comments

Comments
 (0)