@@ -599,48 +599,89 @@ void goto_convertt::remove_overflow(
599599 const irep_idt &statement = expr.get_statement ();
600600 const exprt &lhs = expr.lhs ();
601601 const exprt &rhs = expr.rhs ();
602- const exprt &result_ptr = expr.result ();
602+ const exprt &result = expr.result ();
603603
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
605606 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+
606614 if (statement == ID_overflow_plus)
607615 {
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}};
609620 }
610621 else if (statement == ID_overflow_minus)
611622 {
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}};
613627 }
614628 else
615629 {
616630 INVARIANT (
617631 statement == ID_overflow_mult,
618632 " 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}};
620637 }
621638 };
622639
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; // only if result is a pointer
643+ // (large_signedbv)(result_type)tmp != 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+ optionalt<typet> result_type;
657+ if (result.type ().id () == ID_pointer)
658+ {
659+ result_type = to_pointer_type (result.type ()).subtype ();
660+ code_assignt result_assignment{dereference_exprt{result},
661+ typecast_exprt{operation, *result_type},
662+ expr.source_location ()};
663+ convert_assign (result_assignment, dest, mode);
664+ }
665+ else
666+ {
667+ result_type = result.type ();
668+ // evaluate side effects
669+ exprt tmp = result;
670+ clean_expr (tmp, dest, mode, false ); // result _not_ used
671+ }
638672
639673 if (result_is_used)
640674 {
641- notequal_exprt overflow_check{
642- typecast_exprt{dereference_exprt{result_ptr}, integer_typet{}},
643- operation};
675+ typecast_exprt inner_tc{operation, *result_type};
676+ inner_tc.add_source_location () = expr.source_location ();
677+ inner_tc.add_source_location ().add_pragma (" disable:conversion-check" );
678+ typecast_exprt outer_tc{inner_tc, operation.type ()};
679+ outer_tc.add_source_location () = expr.source_location ();
680+ outer_tc.add_source_location ().add_pragma (" disable:conversion-check" );
681+
682+ notequal_exprt overflow_check{outer_tc, operation};
683+ overflow_check.add_source_location () = expr.source_location ();
684+
644685 expr.swap (overflow_check);
645686 }
646687 else
0 commit comments