Skip to content

Commit 42deca8

Browse files
committed
Simplify (x * n) % n
Multiplying and then taking the modulus always yields zero.
1 parent 6df204e commit 42deca8

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

src/util/simplify_expr_int.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,24 @@ simplify_exprt::resultt<> simplify_exprt::simplify_mult(const mult_exprt &expr)
273273
}
274274
}
275275

276+
static std::optional<std::pair<exprt, mp_integer>>
277+
is_multiplication_by_constant(const exprt &expr)
278+
{
279+
if(expr.id() != ID_mult)
280+
return {};
281+
if(expr.operands().size() != 2)
282+
return {};
283+
const multi_ary_exprt &mul = to_multi_ary_expr(expr);
284+
if(mul.op0().is_constant())
285+
return {
286+
{mul.op1(), numeric_cast_v<mp_integer>(to_constant_expr(mul.op0()))}};
287+
else if(mul.op1().is_constant())
288+
return {
289+
{mul.op0(), numeric_cast_v<mp_integer>(to_constant_expr(mul.op1()))}};
290+
else
291+
return {};
292+
}
293+
276294
simplify_exprt::resultt<> simplify_exprt::simplify_div(const div_exprt &expr)
277295
{
278296
if(!is_number(expr.type()))
@@ -315,6 +333,16 @@ simplify_exprt::resultt<> simplify_exprt::simplify_div(const div_exprt &expr)
315333
mp_integer result = *int_value0 / *int_value1;
316334
return from_integer(result, expr_type);
317335
}
336+
337+
#if 0
338+
// (x * n) / n
339+
if(int_value1.has_value())
340+
{
341+
auto mul_by_int_opt = is_multiplication_by_constant(expr.op0());
342+
if(mul_by_int_opt.has_value() && mul_by_int_opt->second == *int_value1)
343+
return mul_by_int_opt->first;
344+
}
345+
#endif
318346
}
319347
else if(expr_type.id()==ID_rational)
320348
{
@@ -397,6 +425,14 @@ simplify_exprt::resultt<> simplify_exprt::simplify_mod(const mod_exprt &expr)
397425
mp_integer result = *int_value0 % *int_value1;
398426
return from_integer(result, expr.type());
399427
}
428+
429+
// (x * n) % n is zero
430+
if(int_value1.has_value())
431+
{
432+
auto mul_by_int_opt = is_multiplication_by_constant(expr.op0());
433+
if(mul_by_int_opt.has_value() && mul_by_int_opt->second == *int_value1)
434+
return from_integer(0, expr.type());
435+
}
400436
}
401437
}
402438

unit/util/simplify_expr.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,3 +652,34 @@ 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+

0 commit comments

Comments
 (0)