30
30
#include < util/range.h>
31
31
#include < util/simplify_expr.h>
32
32
#include < util/string_constant.h>
33
+ #include < util/suffix.h>
33
34
34
35
#include < goto-programs/adjust_float_expressions.h>
35
36
@@ -2965,7 +2966,10 @@ exprt c_typecheck_baset::do_special_functions(
2965
2966
else if (
2966
2967
identifier == " __builtin_add_overflow" ||
2967
2968
identifier == " __builtin_sub_overflow" ||
2968
- identifier == " __builtin_mul_overflow" )
2969
+ identifier == " __builtin_mul_overflow" ||
2970
+ identifier == " __builtin_add_overflow_p" ||
2971
+ identifier == " __builtin_sub_overflow_p" ||
2972
+ identifier == " __builtin_mul_overflow_p" )
2969
2973
{
2970
2974
// check function signature
2971
2975
if (expr.arguments ().size () != 3 )
@@ -2985,33 +2989,37 @@ exprt c_typecheck_baset::do_special_functions(
2985
2989
typecheck_expr (rhs);
2986
2990
typecheck_expr (result_ptr);
2987
2991
2992
+ const bool is__p_variant = has_suffix (id2string (identifier), " _p" );
2993
+
2988
2994
{
2989
2995
auto const raise_wrong_argument_error =
2990
- [this ,
2991
- identifier]( const exprt &wrong_argument, std::size_t argument_number) {
2996
+ [this , identifier](
2997
+ const exprt &wrong_argument, std::size_t argument_number, bool _p ) {
2992
2998
std::ostringstream error_message;
2993
2999
error_message << wrong_argument.source_location ().as_string () << " : "
2994
3000
<< identifier << " has signature " << identifier
2995
- << " (integral, integral, integral*), "
3001
+ << " (integral, integral, integral" << (_p ? " " : " *" )
3002
+ << " ), "
2996
3003
<< " but argument " << argument_number << " ("
2997
3004
<< expr2c (wrong_argument, *this ) << " ) has type `"
2998
3005
<< type2c (wrong_argument.type (), *this ) << ' `' ;
2999
3006
throw invalid_source_file_exceptiont{error_message.str ()};
3000
3007
};
3001
- for (auto const arg_index : { 0 , 1 } )
3008
+ for (int arg_index = 0 ; arg_index <= (!is__p_variant ? 1 : 2 ); ++arg_index )
3002
3009
{
3003
3010
auto const &argument = expr.arguments ()[arg_index];
3004
3011
3005
3012
if (!is_signed_or_unsigned_bitvector (argument.type ()))
3006
3013
{
3007
- raise_wrong_argument_error (argument, arg_index + 1 );
3014
+ raise_wrong_argument_error (argument, arg_index + 1 , is__p_variant );
3008
3015
}
3009
3016
}
3010
3017
if (
3011
- result_ptr.type ().id () != ID_pointer ||
3012
- !is_signed_or_unsigned_bitvector (result_ptr.type ().subtype ()))
3018
+ !is__p_variant &&
3019
+ (result_ptr.type ().id () != ID_pointer ||
3020
+ !is_signed_or_unsigned_bitvector (result_ptr.type ().subtype ())))
3013
3021
{
3014
- raise_wrong_argument_error (result_ptr, 3 );
3022
+ raise_wrong_argument_error (result_ptr, 3 , is__p_variant );
3015
3023
}
3016
3024
}
3017
3025
@@ -3025,14 +3033,14 @@ exprt c_typecheck_baset::do_special_functions(
3025
3033
if (rhs.type ().id () == ID_unsignedbv)
3026
3034
++rhs_ssize;
3027
3035
3028
- if (identifier == " __builtin_add_overflow" )
3036
+ if (has_prefix ( id2string ( identifier), " __builtin_add_overflow" ) )
3029
3037
{
3030
3038
std::size_t ssize = std::max (lhs_ssize, rhs_ssize) + 1 ;
3031
3039
integer_bitvector_typet ssize_type{ID_signedbv, ssize};
3032
3040
return plus_exprt{typecast_exprt{lhs, ssize_type},
3033
3041
typecast_exprt{rhs, ssize_type}};
3034
3042
}
3035
- else if (identifier == " __builtin_sub_overflow" )
3043
+ else if (has_prefix ( id2string ( identifier), " __builtin_sub_overflow" ) )
3036
3044
{
3037
3045
std::size_t ssize = std::max (lhs_ssize, rhs_ssize) + 1 ;
3038
3046
integer_bitvector_typet ssize_type{ID_signedbv, ssize};
@@ -3042,7 +3050,7 @@ exprt c_typecheck_baset::do_special_functions(
3042
3050
else
3043
3051
{
3044
3052
INVARIANT (
3045
- identifier == " __builtin_mul_overflow" ,
3053
+ has_prefix ( id2string ( identifier), " __builtin_mul_overflow" ) ,
3046
3054
" the three overflow operations are add, sub and mul" );
3047
3055
std::size_t ssize = lhs_ssize + rhs_ssize;
3048
3056
integer_bitvector_typet ssize_type{ID_signedbv, ssize};
@@ -3054,7 +3062,10 @@ exprt c_typecheck_baset::do_special_functions(
3054
3062
// Generating the following statement expression:
3055
3063
// ({ large_signedbv tmp = (large_signedbv)lhs OP (large_signedbv)rhs;
3056
3064
// *result = (result_type)large_signedbv;
3057
- // (large_signedbv)*result != tmp; })
3065
+ // (large_signedbv)(result_type)tmp != tmp; })
3066
+ // The _p variant just uses result; in place of the assignment to *result.
3067
+ code_blockt statements;
3068
+
3058
3069
// This performs the operation (+, -, *) on a signed bitvector type of
3059
3070
// sufficiently large width to store the precise result, cast to result
3060
3071
// type, check if the casted result is not equivalent to the full-length
@@ -3075,23 +3086,43 @@ exprt c_typecheck_baset::do_special_functions(
3075
3086
3076
3087
code_declt decl{new_symbol.symbol_expr ()};
3077
3088
decl.add_source_location () = expr.source_location ();
3089
+ statements.add (decl);
3078
3090
3079
3091
code_assignt tmp_assignment{decl.symbol (), operation};
3080
3092
tmp_assignment.add_source_location () = expr.source_location ();
3093
+ statements.add (tmp_assignment);
3081
3094
3082
- const auto &result_type = to_pointer_type (result_ptr.type ()).subtype ();
3083
- code_assignt result_assignment{dereference_exprt{result_ptr},
3084
- typecast_exprt{decl.symbol (), result_type}};
3085
- result_assignment.add_source_location () = expr.source_location ();
3095
+ typet result_type;
3096
+ if (!is__p_variant)
3097
+ {
3098
+ result_type = to_pointer_type (result_ptr.type ()).subtype ();
3099
+ code_assignt result_assignment{
3100
+ dereference_exprt{result_ptr},
3101
+ typecast_exprt{decl.symbol (), result_type}};
3102
+ result_assignment.add_source_location () = expr.source_location ();
3103
+ statements.add (result_assignment);
3104
+ }
3105
+ else
3106
+ {
3107
+ result_type = result_ptr.type ();
3108
+ code_expressiont eval_side_effects{result_ptr};
3109
+ eval_side_effects.add_source_location () = expr.source_location ();
3110
+ statements.add (eval_side_effects);
3111
+ }
3086
3112
3087
- notequal_exprt overflow_check{
3088
- typecast_exprt{dereference_exprt{result_ptr}, operation.type ()},
3089
- decl.symbol ()};
3113
+ typecast_exprt inner_tc{decl.symbol (), result_type};
3114
+ inner_tc.add_source_location () = expr.source_location ();
3115
+ inner_tc.add_source_location ().add_pragma (" disable:conversion-check" );
3116
+ typecast_exprt outer_tc{inner_tc, operation.type ()};
3117
+ outer_tc.add_source_location () = expr.source_location ();
3118
+ outer_tc.add_source_location ().add_pragma (" disable:conversion-check" );
3119
+ notequal_exprt overflow_check{outer_tc, decl.symbol ()};
3090
3120
overflow_check.add_source_location () = expr.source_location ();
3121
+
3091
3122
code_expressiont return_expr{overflow_check};
3123
+ return_expr.add_source_location () = expr.source_location ();
3124
+ statements.add (return_expr);
3092
3125
3093
- code_blockt statements{
3094
- {decl, tmp_assignment, result_assignment, return_expr}};
3095
3126
return side_effect_expr_statement_expressiont{
3096
3127
statements, overflow_check.type (), expr.source_location ()};
3097
3128
}
0 commit comments