@@ -2590,6 +2590,58 @@ simplify_exprt::simplify_overflow_result(const overflow_result_exprt &expr)
25902590 if (op_type_id != ID_signedbv && op_type_id != ID_unsignedbv)
25912591 return unchanged (expr);
25922592
2593+ // a special case of overflow-minus checking with operands (X + n) and X
2594+ if (expr.id () == ID_overflow_result_minus)
2595+ {
2596+ const exprt &tc_op0 = skip_typecast (expr.op0 ());
2597+ const exprt &tc_op1 = skip_typecast (expr.op1 ());
2598+
2599+ if (auto sum = expr_try_dynamic_cast<plus_exprt>(tc_op0))
2600+ {
2601+ if (skip_typecast (sum->op0 ()) == tc_op1 && sum->operands ().size () == 2 )
2602+ {
2603+ optionalt<exprt> offset;
2604+ if (sum->type ().id () == ID_pointer)
2605+ {
2606+ offset = std::move (simplify_pointer_offset (
2607+ pointer_offset_exprt{*sum, expr.op0 ().type ()})
2608+ .expr );
2609+ if (offset->id () == ID_pointer_offset)
2610+ return unchanged (expr);
2611+ }
2612+ else
2613+ offset = std::move (
2614+ simplify_typecast (typecast_exprt{sum->op1 (), expr.op0 ().type ()})
2615+ .expr );
2616+
2617+ exprt offset_op = skip_typecast (*offset);
2618+ if (
2619+ offset_op.type ().id () != ID_signedbv &&
2620+ offset_op.type ().id () != ID_unsignedbv)
2621+ {
2622+ return unchanged (expr);
2623+ }
2624+
2625+ const std::size_t width =
2626+ to_bitvector_type (expr.op0 ().type ()).get_width ();
2627+ const integer_bitvector_typet bv_type{op_type_id, width};
2628+
2629+ or_exprt not_representable{
2630+ binary_relation_exprt{
2631+ offset_op,
2632+ ID_lt,
2633+ from_integer (bv_type.smallest (), offset_op.type ())},
2634+ binary_relation_exprt{
2635+ offset_op,
2636+ ID_gt,
2637+ from_integer (bv_type.largest (), offset_op.type ())}};
2638+
2639+ return struct_exprt{
2640+ {*offset, simplify_rec (not_representable)}, expr.type ()};
2641+ }
2642+ }
2643+ }
2644+
25932645 if (!expr.op0 ().is_constant () || !expr.op1 ().is_constant ())
25942646 return unchanged (expr);
25952647
0 commit comments