@@ -601,46 +601,71 @@ void goto_convertt::remove_overflow(
601
601
const exprt &rhs = expr.rhs ();
602
602
const exprt &result_ptr = expr.result ();
603
603
604
- // actual logic implementing the operators
604
+ // actual logic implementing the operators: perform operations on signed
605
+ // bitvector types of sufficiently large size to hold the result
605
606
auto const make_operation = [&statement](exprt lhs, exprt rhs) -> exprt {
607
+ std::size_t lhs_ssize = to_bitvector_type (lhs.type ()).get_width ();
608
+ if (lhs.type ().id () == ID_unsignedbv)
609
+ ++lhs_ssize;
610
+ std::size_t rhs_ssize = to_bitvector_type (rhs.type ()).get_width ();
611
+ if (rhs.type ().id () == ID_unsignedbv)
612
+ ++rhs_ssize;
613
+
606
614
if (statement == ID_overflow_plus)
607
615
{
608
- return plus_exprt{lhs, rhs};
616
+ std::size_t ssize = std::max (lhs_ssize, rhs_ssize) + 1 ;
617
+ integer_bitvector_typet ssize_type{ID_signedbv, ssize};
618
+ return plus_exprt{typecast_exprt{lhs, ssize_type},
619
+ typecast_exprt{rhs, ssize_type}};
609
620
}
610
621
else if (statement == ID_overflow_minus)
611
622
{
612
- return minus_exprt{lhs, rhs};
623
+ std::size_t ssize = std::max (lhs_ssize, rhs_ssize) + 1 ;
624
+ integer_bitvector_typet ssize_type{ID_signedbv, ssize};
625
+ return minus_exprt{typecast_exprt{lhs, ssize_type},
626
+ typecast_exprt{rhs, ssize_type}};
613
627
}
614
628
else
615
629
{
616
630
INVARIANT (
617
631
statement == ID_overflow_mult,
618
632
" the three overflow operations are add, sub and mul" );
619
- return mult_exprt{lhs, rhs};
633
+ std::size_t ssize = lhs_ssize + rhs_ssize;
634
+ integer_bitvector_typet ssize_type{ID_signedbv, ssize};
635
+ return mult_exprt{typecast_exprt{lhs, ssize_type},
636
+ typecast_exprt{rhs, ssize_type}};
620
637
}
621
638
};
622
639
623
- // we’re basically generating this expression
624
- // (*result = (result_type)((integer)lhs OP (integer)rhs)),
625
- // ((integer)result == (integer)lhs OP (integer)rhs)
626
- // i.e. perform the operation (+, -, *) on arbitrary length integer,
627
- // cast to result type, check if the casted result is still equivalent
628
- // to the arbitrary length result.
629
- auto operation = make_operation (
630
- typecast_exprt{lhs, integer_typet{}}, typecast_exprt{rhs, integer_typet{}});
631
-
632
- typecast_exprt operation_result{operation, result_ptr.type ().subtype ()};
633
-
634
- code_assignt assign{dereference_exprt{result_ptr},
635
- std::move (operation_result),
636
- expr.source_location ()};
637
- convert_assign (assign, dest, mode);
640
+ // Generating the following sequence of statements:
641
+ // large_signedbv tmp = (large_signedbv)lhs OP (large_signedbv)rhs;
642
+ // *result = (result_type)tmp;
643
+ // (large_signedbv)*result != tmp;
644
+ // This performs the operation (+, -, *) on a signed bitvector type of
645
+ // sufficiently large width to store the precise result, cast to result
646
+ // type, check if the cast result is not equivalent to the full-length
647
+ // result.
648
+ auto operation = make_operation (lhs, rhs);
649
+ // Disable overflow checks as the operation cannot overflow on the larger
650
+ // type
651
+ operation.add_source_location () = expr.source_location ();
652
+ operation.add_source_location ().add_pragma (" disable:signed-overflow-check" );
653
+
654
+ make_temp_symbol (operation, " large_bv" , dest, mode);
655
+
656
+ const auto &result_type = to_pointer_type (result_ptr.type ()).subtype ();
657
+ code_assignt result_assignment{dereference_exprt{result_ptr},
658
+ typecast_exprt{operation, result_type},
659
+ expr.source_location ()};
660
+ convert_assign (result_assignment, dest, mode);
638
661
639
662
if (result_is_used)
640
663
{
641
664
notequal_exprt overflow_check{
642
- typecast_exprt{dereference_exprt{result_ptr}, integer_typet{} },
665
+ typecast_exprt{dereference_exprt{result_ptr}, operation. type () },
643
666
operation};
667
+ overflow_check.add_source_location () = expr.source_location ();
668
+
644
669
expr.swap (overflow_check);
645
670
}
646
671
else
0 commit comments