|
12 | 12 | #include "goto_convert_class.h"
|
13 | 13 |
|
14 | 14 | #include <util/arith_tools.h>
|
| 15 | +#include <util/bitvector_expr.h> |
| 16 | +#include <util/c_types.h> |
15 | 17 | #include <util/expr_util.h>
|
16 | 18 | #include <util/fresh_symbol.h>
|
17 | 19 | #include <util/mathematical_types.h>
|
18 | 20 | #include <util/std_expr.h>
|
19 | 21 | #include <util/symbol.h>
|
20 | 22 |
|
21 |
| -#include <util/c_types.h> |
22 |
| - |
23 | 23 | #include <ansi-c/c_expr.h>
|
24 | 24 |
|
25 | 25 | bool goto_convertt::has_function_call(const exprt &expr)
|
@@ -589,91 +589,65 @@ void goto_convertt::remove_overflow(
|
589 | 589 | const exprt &rhs = expr.rhs();
|
590 | 590 | const exprt &result = expr.result();
|
591 | 591 |
|
592 |
| - // actual logic implementing the operators: perform operations on signed |
593 |
| - // bitvector types of sufficiently large size to hold the result |
594 |
| - auto const make_operation = [&statement](exprt lhs, exprt rhs) -> exprt { |
595 |
| - std::size_t lhs_ssize = to_bitvector_type(lhs.type()).get_width(); |
596 |
| - if(lhs.type().id() == ID_unsignedbv) |
597 |
| - ++lhs_ssize; |
598 |
| - std::size_t rhs_ssize = to_bitvector_type(rhs.type()).get_width(); |
599 |
| - if(rhs.type().id() == ID_unsignedbv) |
600 |
| - ++rhs_ssize; |
601 |
| - |
602 |
| - if(statement == ID_overflow_plus) |
603 |
| - { |
604 |
| - std::size_t ssize = std::max(lhs_ssize, rhs_ssize) + 1; |
605 |
| - integer_bitvector_typet ssize_type{ID_signedbv, ssize}; |
606 |
| - return plus_exprt{typecast_exprt{lhs, ssize_type}, |
607 |
| - typecast_exprt{rhs, ssize_type}}; |
608 |
| - } |
609 |
| - else if(statement == ID_overflow_minus) |
| 592 | + if(result.type().id() != ID_pointer) |
| 593 | + { |
| 594 | + // result of the arithmetic operation is _not_ used, just evaluate side |
| 595 | + // effects |
| 596 | + exprt tmp = result; |
| 597 | + clean_expr(tmp, dest, mode, false); |
| 598 | + |
| 599 | + // the is-there-an-overflow result may be used |
| 600 | + if(result_is_used) |
610 | 601 | {
|
611 |
| - std::size_t ssize = std::max(lhs_ssize, rhs_ssize) + 1; |
612 |
| - integer_bitvector_typet ssize_type{ID_signedbv, ssize}; |
613 |
| - return minus_exprt{typecast_exprt{lhs, ssize_type}, |
614 |
| - typecast_exprt{rhs, ssize_type}}; |
| 602 | + binary_overflow_exprt overflow_check{ |
| 603 | + typecast_exprt::conditional_cast(lhs, result.type()), |
| 604 | + statement, |
| 605 | + typecast_exprt::conditional_cast(rhs, result.type())}; |
| 606 | + overflow_check.add_source_location() = expr.source_location(); |
| 607 | + expr.swap(overflow_check); |
615 | 608 | }
|
616 | 609 | else
|
617 |
| - { |
618 |
| - INVARIANT( |
619 |
| - statement == ID_overflow_mult, |
620 |
| - "the three overflow operations are add, sub and mul"); |
621 |
| - std::size_t ssize = lhs_ssize + rhs_ssize; |
622 |
| - integer_bitvector_typet ssize_type{ID_signedbv, ssize}; |
623 |
| - return mult_exprt{typecast_exprt{lhs, ssize_type}, |
624 |
| - typecast_exprt{rhs, ssize_type}}; |
625 |
| - } |
626 |
| - }; |
627 |
| - |
628 |
| - // Generating the following sequence of statements: |
629 |
| - // large_signedbv tmp = (large_signedbv)lhs OP (large_signedbv)rhs; |
630 |
| - // *result = (result_type)tmp; // only if result is a pointer |
631 |
| - // (large_signedbv)(result_type)tmp != tmp; |
632 |
| - // This performs the operation (+, -, *) on a signed bitvector type of |
633 |
| - // sufficiently large width to store the precise result, cast to result |
634 |
| - // type, check if the cast result is not equivalent to the full-length |
635 |
| - // result. |
636 |
| - auto operation = make_operation(lhs, rhs); |
637 |
| - // Disable overflow checks as the operation cannot overflow on the larger |
638 |
| - // type |
639 |
| - operation.add_source_location() = expr.source_location(); |
640 |
| - operation.add_source_location().add_pragma("disable:signed-overflow-check"); |
641 |
| - |
642 |
| - make_temp_symbol(operation, "large_bv", dest, mode); |
643 |
| - |
644 |
| - optionalt<typet> result_type; |
645 |
| - if(result.type().id() == ID_pointer) |
646 |
| - { |
647 |
| - result_type = to_pointer_type(result.type()).base_type(); |
648 |
| - code_assignt result_assignment{dereference_exprt{result}, |
649 |
| - typecast_exprt{operation, *result_type}, |
650 |
| - expr.source_location()}; |
651 |
| - convert_assign(result_assignment, dest, mode); |
| 610 | + expr.make_nil(); |
652 | 611 | }
|
653 | 612 | else
|
654 | 613 | {
|
655 |
| - result_type = result.type(); |
656 |
| - // evaluate side effects |
657 |
| - exprt tmp = result; |
658 |
| - clean_expr(tmp, dest, mode, false); // result _not_ used |
659 |
| - } |
660 |
| - |
661 |
| - if(result_is_used) |
662 |
| - { |
663 |
| - typecast_exprt inner_tc{operation, *result_type}; |
664 |
| - inner_tc.add_source_location() = expr.source_location(); |
665 |
| - inner_tc.add_source_location().add_pragma("disable:conversion-check"); |
666 |
| - typecast_exprt outer_tc{inner_tc, operation.type()}; |
667 |
| - outer_tc.add_source_location() = expr.source_location(); |
668 |
| - outer_tc.add_source_location().add_pragma("disable:conversion-check"); |
| 614 | + const typet &arith_type = to_pointer_type(result.type()).base_type(); |
| 615 | + irep_idt arithmetic_operation = |
| 616 | + statement == ID_overflow_plus |
| 617 | + ? ID_plus |
| 618 | + : statement == ID_overflow_minus |
| 619 | + ? ID_minus |
| 620 | + : statement == ID_overflow_mult ? ID_mult : ID_nil; |
| 621 | + CHECK_RETURN(arithmetic_operation != ID_nil); |
| 622 | + exprt overflow_with_result = overflow_result_exprt{ |
| 623 | + typecast_exprt::conditional_cast(lhs, arith_type), |
| 624 | + arithmetic_operation, |
| 625 | + typecast_exprt::conditional_cast(rhs, arith_type)}; |
| 626 | + overflow_with_result.add_source_location() = expr.source_location(); |
| 627 | + |
| 628 | + if(result_is_used) |
| 629 | + make_temp_symbol(overflow_with_result, "overflow_result", dest, mode); |
| 630 | + |
| 631 | + const struct_typet::componentst &result_comps = |
| 632 | + to_struct_type(overflow_with_result.type()).components(); |
| 633 | + CHECK_RETURN(result_comps.size() == 2); |
| 634 | + code_assignt result_assignment{ |
| 635 | + dereference_exprt{result}, |
| 636 | + typecast_exprt::conditional_cast( |
| 637 | + member_exprt{overflow_with_result, result_comps[0]}, arith_type), |
| 638 | + expr.source_location()}; |
| 639 | + convert_assign(result_assignment, dest, mode); |
669 | 640 |
|
670 |
| - notequal_exprt overflow_check{outer_tc, operation}; |
671 |
| - overflow_check.add_source_location() = expr.source_location(); |
| 641 | + if(result_is_used) |
| 642 | + { |
| 643 | + member_exprt overflow_check{overflow_with_result, result_comps[1]}; |
| 644 | + overflow_check.add_source_location() = expr.source_location(); |
672 | 645 |
|
673 |
| - expr.swap(overflow_check); |
| 646 | + expr.swap(overflow_check); |
| 647 | + } |
| 648 | + else |
| 649 | + expr.make_nil(); |
674 | 650 | }
|
675 |
| - else |
676 |
| - expr.make_nil(); |
677 | 651 | }
|
678 | 652 |
|
679 | 653 | void goto_convertt::remove_side_effect(
|
|
0 commit comments