aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c79
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;
}