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