diff options
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 71fbf09..1cd65ed 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -9724,6 +9724,62 @@ fold_builtin_unordered_cmp (location_t loc, tree fndecl, tree arg0, tree arg1, fold_build2_loc (loc, code, type, arg0, arg1)); } +/* Fold __builtin_{,s,u}{add,sub,mul}{,l,ll}_overflow, either into normal + arithmetics if it can never overflow, or into internal functions that + return both result of arithmetics and overflowed boolean flag in + a complex integer result, or some other check for overflow. */ + +static tree +fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode, + tree arg0, tree arg1, tree arg2) +{ + enum internal_fn ifn = IFN_LAST; + tree type = TREE_TYPE (TREE_TYPE (arg2)); + tree mem_arg2 = build_fold_indirect_ref_loc (loc, arg2); + switch (fcode) + { + case BUILT_IN_ADD_OVERFLOW: + case BUILT_IN_SADD_OVERFLOW: + case BUILT_IN_SADDL_OVERFLOW: + case BUILT_IN_SADDLL_OVERFLOW: + case BUILT_IN_UADD_OVERFLOW: + case BUILT_IN_UADDL_OVERFLOW: + case BUILT_IN_UADDLL_OVERFLOW: + ifn = IFN_ADD_OVERFLOW; + break; + case BUILT_IN_SUB_OVERFLOW: + case BUILT_IN_SSUB_OVERFLOW: + case BUILT_IN_SSUBL_OVERFLOW: + case BUILT_IN_SSUBLL_OVERFLOW: + case BUILT_IN_USUB_OVERFLOW: + case BUILT_IN_USUBL_OVERFLOW: + case BUILT_IN_USUBLL_OVERFLOW: + ifn = IFN_SUB_OVERFLOW; + break; + case BUILT_IN_MUL_OVERFLOW: + case BUILT_IN_SMUL_OVERFLOW: + case BUILT_IN_SMULL_OVERFLOW: + case BUILT_IN_SMULLL_OVERFLOW: + case BUILT_IN_UMUL_OVERFLOW: + case BUILT_IN_UMULL_OVERFLOW: + case BUILT_IN_UMULLL_OVERFLOW: + ifn = IFN_MUL_OVERFLOW; + break; + default: + gcc_unreachable (); + } + tree ctype = build_complex_type (type); + tree call = build_call_expr_internal_loc (loc, ifn, ctype, + 2, arg0, arg1); + tree tgt = save_expr (call); + tree intres = build1_loc (loc, REALPART_EXPR, type, tgt); + tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt); + ovfres = fold_convert_loc (loc, boolean_type_node, ovfres); + tree store + = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, mem_arg2, intres); + return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres); +} + /* Fold a call to built-in function FNDECL with 0 arguments. IGNORE is true if the result of the function call is ignored. This function returns NULL_TREE if no simplification was possible. */ @@ -10431,6 +10487,29 @@ fold_builtin_3 (location_t loc, tree fndecl, case BUILT_IN_EXPECT: return fold_builtin_expect (loc, arg0, arg1, arg2); + case BUILT_IN_ADD_OVERFLOW: + case BUILT_IN_SUB_OVERFLOW: + case BUILT_IN_MUL_OVERFLOW: + case BUILT_IN_SADD_OVERFLOW: + case BUILT_IN_SADDL_OVERFLOW: + case BUILT_IN_SADDLL_OVERFLOW: + case BUILT_IN_SSUB_OVERFLOW: + case BUILT_IN_SSUBL_OVERFLOW: + case BUILT_IN_SSUBLL_OVERFLOW: + case BUILT_IN_SMUL_OVERFLOW: + case BUILT_IN_SMULL_OVERFLOW: + case BUILT_IN_SMULLL_OVERFLOW: + case BUILT_IN_UADD_OVERFLOW: + case BUILT_IN_UADDL_OVERFLOW: + case BUILT_IN_UADDLL_OVERFLOW: + case BUILT_IN_USUB_OVERFLOW: + case BUILT_IN_USUBL_OVERFLOW: + case BUILT_IN_USUBLL_OVERFLOW: + case BUILT_IN_UMUL_OVERFLOW: + case BUILT_IN_UMULL_OVERFLOW: + case BUILT_IN_UMULLL_OVERFLOW: + return fold_builtin_arith_overflow (loc, fcode, arg0, arg1, arg2); + default: break; } |