28
28
#include < util/prefix.h>
29
29
#include < util/simplify_expr.h>
30
30
#include < util/string_constant.h>
31
+ #include < util/suffix.h>
31
32
32
33
#include < goto-programs/adjust_float_expressions.h>
33
34
@@ -2813,7 +2814,10 @@ exprt c_typecheck_baset::do_special_functions(
2813
2814
else if (
2814
2815
identifier == " __builtin_add_overflow" ||
2815
2816
identifier == " __builtin_sub_overflow" ||
2816
- identifier == " __builtin_mul_overflow" )
2817
+ identifier == " __builtin_mul_overflow" ||
2818
+ identifier == " __builtin_add_overflow_p" ||
2819
+ identifier == " __builtin_sub_overflow_p" ||
2820
+ identifier == " __builtin_mul_overflow_p" )
2817
2821
{
2818
2822
// check function signature
2819
2823
if (expr.arguments ().size () != 3 )
@@ -2833,33 +2837,37 @@ exprt c_typecheck_baset::do_special_functions(
2833
2837
typecheck_expr (rhs);
2834
2838
typecheck_expr (result_ptr);
2835
2839
2840
+ const bool is__p_variant = has_suffix (id2string (identifier), " _p" );
2841
+
2836
2842
{
2837
2843
auto const raise_wrong_argument_error =
2838
- [this ,
2839
- identifier]( const exprt &wrong_argument, std::size_t argument_number) {
2844
+ [this , identifier](
2845
+ const exprt &wrong_argument, std::size_t argument_number, bool _p ) {
2840
2846
std::ostringstream error_message;
2841
2847
error_message << wrong_argument.source_location ().as_string () << " : "
2842
2848
<< identifier << " has signature " << identifier
2843
- << " (integral, integral, integral*), "
2849
+ << " (integral, integral, integral" << (_p ? " " : " *" )
2850
+ << " ), "
2844
2851
<< " but argument " << argument_number << " ("
2845
2852
<< expr2c (wrong_argument, *this ) << " ) has type `"
2846
2853
<< type2c (wrong_argument.type (), *this ) << ' `' ;
2847
2854
throw invalid_source_file_exceptiont{error_message.str ()};
2848
2855
};
2849
- for (auto const arg_index : { 0 , 1 } )
2856
+ for (int arg_index = 0 ; arg_index <= (!is__p_variant ? 1 : 2 ); ++arg_index )
2850
2857
{
2851
2858
auto const &argument = expr.arguments ()[arg_index];
2852
2859
2853
2860
if (!is_signed_or_unsigned_bitvector (argument.type ()))
2854
2861
{
2855
- raise_wrong_argument_error (argument, arg_index + 1 );
2862
+ raise_wrong_argument_error (argument, arg_index + 1 , is__p_variant );
2856
2863
}
2857
2864
}
2858
2865
if (
2859
- result_ptr.type ().id () != ID_pointer ||
2860
- !is_signed_or_unsigned_bitvector (result_ptr.type ().subtype ()))
2866
+ !is__p_variant &&
2867
+ (result_ptr.type ().id () != ID_pointer ||
2868
+ !is_signed_or_unsigned_bitvector (result_ptr.type ().subtype ())))
2861
2869
{
2862
- raise_wrong_argument_error (result_ptr, 3 );
2870
+ raise_wrong_argument_error (result_ptr, 3 , is__p_variant );
2863
2871
}
2864
2872
}
2865
2873
@@ -2873,14 +2881,14 @@ exprt c_typecheck_baset::do_special_functions(
2873
2881
if (rhs.type ().id () == ID_unsignedbv)
2874
2882
++rhs_ssize;
2875
2883
2876
- if (identifier == " __builtin_add_overflow" )
2884
+ if (has_prefix ( id2string ( identifier), " __builtin_add_overflow" ) )
2877
2885
{
2878
2886
std::size_t ssize = std::max (lhs_ssize, rhs_ssize) + 1 ;
2879
2887
integer_bitvector_typet ssize_type{ID_signedbv, ssize};
2880
2888
return plus_exprt{typecast_exprt{lhs, ssize_type},
2881
2889
typecast_exprt{rhs, ssize_type}};
2882
2890
}
2883
- else if (identifier == " __builtin_sub_overflow" )
2891
+ else if (has_prefix ( id2string ( identifier), " __builtin_sub_overflow" ) )
2884
2892
{
2885
2893
std::size_t ssize = std::max (lhs_ssize, rhs_ssize) + 1 ;
2886
2894
integer_bitvector_typet ssize_type{ID_signedbv, ssize};
@@ -2890,7 +2898,7 @@ exprt c_typecheck_baset::do_special_functions(
2890
2898
else
2891
2899
{
2892
2900
INVARIANT (
2893
- identifier == " __builtin_mul_overflow" ,
2901
+ has_prefix ( id2string ( identifier), " __builtin_mul_overflow" ) ,
2894
2902
" the three overflow operations are add, sub and mul" );
2895
2903
std::size_t ssize = lhs_ssize + rhs_ssize;
2896
2904
integer_bitvector_typet ssize_type{ID_signedbv, ssize};
@@ -2902,7 +2910,10 @@ exprt c_typecheck_baset::do_special_functions(
2902
2910
// Generating the following statement expression:
2903
2911
// ({ large_signedbv tmp = (large_signedbv)lhs OP (large_signedbv)rhs;
2904
2912
// *result = (result_type)large_signedbv;
2905
- // (large_signedbv)*result != tmp; })
2913
+ // (large_signedbv)(result_type)tmp != tmp; })
2914
+ // The _p variant just uses result; in place of the assignment to *result.
2915
+ code_blockt statements;
2916
+
2906
2917
// This performs the operation (+, -, *) on a signed bitvector type of
2907
2918
// sufficiently large width to store the precise result, cast to result
2908
2919
// type, check if the casted result is not equivalent to the full-length
@@ -2923,23 +2934,43 @@ exprt c_typecheck_baset::do_special_functions(
2923
2934
2924
2935
code_declt decl{new_symbol.symbol_expr ()};
2925
2936
decl.add_source_location () = expr.source_location ();
2937
+ statements.add (decl);
2926
2938
2927
2939
code_assignt tmp_assignment{decl.symbol (), operation};
2928
2940
tmp_assignment.add_source_location () = expr.source_location ();
2941
+ statements.add (tmp_assignment);
2929
2942
2930
- const auto &result_type = to_pointer_type (result_ptr.type ()).subtype ();
2931
- code_assignt result_assignment{dereference_exprt{result_ptr},
2932
- typecast_exprt{decl.symbol (), result_type}};
2933
- result_assignment.add_source_location () = expr.source_location ();
2943
+ typet result_type;
2944
+ if (!is__p_variant)
2945
+ {
2946
+ result_type = to_pointer_type (result_ptr.type ()).subtype ();
2947
+ code_assignt result_assignment{
2948
+ dereference_exprt{result_ptr},
2949
+ typecast_exprt{decl.symbol (), result_type}};
2950
+ result_assignment.add_source_location () = expr.source_location ();
2951
+ statements.add (result_assignment);
2952
+ }
2953
+ else
2954
+ {
2955
+ result_type = result_ptr.type ();
2956
+ code_expressiont eval_side_effects{result_ptr};
2957
+ eval_side_effects.add_source_location () = expr.source_location ();
2958
+ statements.add (eval_side_effects);
2959
+ }
2934
2960
2935
- notequal_exprt overflow_check{
2936
- typecast_exprt{dereference_exprt{result_ptr}, operation.type ()},
2937
- decl.symbol ()};
2961
+ typecast_exprt inner_tc{decl.symbol (), result_type};
2962
+ inner_tc.add_source_location () = expr.source_location ();
2963
+ inner_tc.add_source_location ().add_pragma (" disable:conversion-check" );
2964
+ typecast_exprt outer_tc{inner_tc, operation.type ()};
2965
+ outer_tc.add_source_location () = expr.source_location ();
2966
+ outer_tc.add_source_location ().add_pragma (" disable:conversion-check" );
2967
+ notequal_exprt overflow_check{outer_tc, decl.symbol ()};
2938
2968
overflow_check.add_source_location () = expr.source_location ();
2969
+
2939
2970
code_expressiont return_expr{overflow_check};
2971
+ return_expr.add_source_location () = expr.source_location ();
2972
+ statements.add (return_expr);
2940
2973
2941
- code_blockt statements{
2942
- {decl, tmp_assignment, result_assignment, return_expr}};
2943
2974
return side_effect_expr_statement_expressiont{
2944
2975
statements, overflow_check.type (), expr.source_location ()};
2945
2976
}
0 commit comments