summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-dce.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2014-11-12 13:28:06 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2014-11-12 13:28:06 +0100
commit1304953e4fa46305d1ce0b884bf2f58e08409ff3 (patch)
tree551c242f138ac032ded6f0171ee39700e6ea032e /gcc/tree-ssa-dce.c
parent6a3cbe90926bbe62fcbce85dc735cbf077fd0f0b (diff)
re PR c/59708 (clang-compatible checked arithmetic builtins)
PR c/59708 * builtin-attrs.def (ATTR_NOTHROW_TYPEGENERIC_LEAF): New attribute. * builtins.c (fold_builtin_arith_overflow): New function. (fold_builtin_3): Use it. * builtins.def (BUILT_IN_ADD_OVERFLOW, BUILT_IN_SUB_OVERFLOW, BUILT_IN_MUL_OVERFLOW, BUILT_IN_SADD_OVERFLOW, BUILT_IN_SADDL_OVERFLOW, BUILT_IN_SADDLL_OVERFLOW, BUILT_IN_SSUB_OVERFLOW, BUILT_IN_SSUBL_OVERFLOW, BUILT_IN_SSUBLL_OVERFLOW, BUILT_IN_SMUL_OVERFLOW, BUILT_IN_SMULL_OVERFLOW, BUILT_IN_SMULLL_OVERFLOW, BUILT_IN_UADDL_OVERFLOW, BUILT_IN_UADDLL_OVERFLOW, BUILT_IN_USUB_OVERFLOW, BUILT_IN_USUBL_OVERFLOW, BUILT_IN_USUBLL_OVERFLOW, BUILT_IN_UMUL_OVERFLOW, BUILT_IN_UMULL_OVERFLOW, BUILT_IN_UMULLL_OVERFLOW): New built-in functions. * builtin-types.def (BT_PTR_UINT, BT_PTR_ULONG, BT_PTR_LONGLONG, BT_FN_BOOL_INT_INT_INTPTR, BT_FN_BOOL_LONG_LONG_LONGPTR, BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, BT_FN_BOOL_UINT_UINT_UINTPTR, BT_FN_BOOL_ULONG_ULONG_ULONGPTR, BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, BT_FN_BOOL_VAR): New. * expr.c (write_complex_part): Remove prototype, no longer static. * expr.h (write_complex_part): New prototype. * function.c (aggregate_value_p): For internal functions return 0. * gimple-fold.c (arith_overflowed_p): New functions. (gimple_fold_call): Fold {ADD,SUB,MUL}_OVERFLOW internal calls. * gimple-fold.h (arith_overflowed_p): New prototype. * tree-ssa-dce.c: Include tree-ssa-propagate.h and gimple-fold.h. (find_non_realpart_uses, maybe_optimize_arith_overflow): New functions. (eliminate_unnecessary_stmts): Transform {ADD,SUB,MUL}_OVERFLOW into COMPLEX_CST/COMPLEX_EXPR if IMAGPART_EXPR of the result is never used. * gimplify.c (gimplify_call_expr): Handle gimplification of internal calls with lhs. * internal-fn.c (get_range_pos_neg, get_min_precision, expand_arith_overflow_result_store): New functions. (ubsan_expand_si_overflow_addsub_check): Renamed to ... (expand_addsub_overflow): ... this. Add LOC, LHS, ARG0, ARG1, UNSR_P, UNS0_P, UNS1_P, IS_UBSAN arguments, remove STMT argument. Handle ADD_OVERFLOW and SUB_OVERFLOW expansion. (ubsan_expand_si_overflow_neg_check): Renamed to ... (expand_neg_overflow): ... this. Add LOC, LHS, ARG1, IS_UBSAN arguments, remove STMT argument. Handle SUB_OVERFLOW with 0 as first argument expansion. (ubsan_expand_si_overflow_mul_check): Renamed to ... (expand_mul_overflow): ... this. Add LOC, LHS, ARG0, ARG1, UNSR_P, UNS0_P, UNS1_P, IS_UBSAN arguments, remove STMT argument. Handle MUL_OVERFLOW expansion. (expand_UBSAN_CHECK_ADD): Use expand_addsub_overflow, prepare arguments for it. (expand_UBSAN_CHECK_SUB): Use expand_addsub_overflow or expand_neg_overflow, prepare arguments for it. (expand_UBSAN_CHECK_MUL): Use expand_mul_overflow, prepare arguments for it. (expand_arith_overflow, expand_ADD_OVERFLOW, expand_SUB_OVERFLOW, expand_MUL_OVERFLOW): New functions. * internal-fn.def (ADD_OVERFLOW, SUB_OVERFLOW, MUL_OVERFLOW): New internal functions. * tree-vrp.c (check_for_binary_op_overflow): New function. (extract_range_basic): Handle {REAL,IMAG}PART_EXPR if the operand is SSA_NAME set by {ADD,SUB,MUL}_OVERFLOW internal functions. (simplify_internal_call_using_ranges): Handle {ADD,SUB,MUL}_OVERFLOW internal functions. * optabs.def (umulv4_optab): New optab. * config/i386/i386.md (umulv<mode>4, <u>mulvqi4): New define_expands. (*umulv<mode>4, *<u>mulvqi4): New define_insns. * doc/extend.texi (Integer Overflow Builtins): Document __builtin_*_overflow. c-family/ * c-common.c (check_builtin_function_arguments): Handle BUILT_IN_{ADD,SUB,MUL}_OVERFLOW. testsuite/ * c-c++-common/builtin-arith-overflow-1.c: New test. * c-c++-common/torture/builtin-arith-overflow-10.c: New test. * c-c++-common/torture/builtin-arith-overflow-11.c: New test. * c-c++-common/torture/builtin-arith-overflow-12.c: New test. * c-c++-common/torture/builtin-arith-overflow-12.h: New file. * c-c++-common/torture/builtin-arith-overflow-13.c: New test. * c-c++-common/torture/builtin-arith-overflow-14.c: New test. * c-c++-common/torture/builtin-arith-overflow-15.c: New test. * c-c++-common/torture/builtin-arith-overflow-16.c: New test. * c-c++-common/torture/builtin-arith-overflow-17.c: New test. * c-c++-common/torture/builtin-arith-overflow-18.c: New test. * c-c++-common/torture/builtin-arith-overflow-1.c: New test. * c-c++-common/torture/builtin-arith-overflow-1.h: New file. * c-c++-common/torture/builtin-arith-overflow-2.c: New test. * c-c++-common/torture/builtin-arith-overflow-3.c: New test. * c-c++-common/torture/builtin-arith-overflow-4.c: New test. * c-c++-common/torture/builtin-arith-overflow-5.c: New test. * c-c++-common/torture/builtin-arith-overflow-6.c: New test. * c-c++-common/torture/builtin-arith-overflow-7.c: New test. * c-c++-common/torture/builtin-arith-overflow-8.c: New test. * c-c++-common/torture/builtin-arith-overflow-9.c: New test. * c-c++-common/torture/builtin-arith-overflow.h: New file. * gcc.dg/builtin-arith-overflow-1.c: New test. * gcc.dg/builtin-arith-overflow-2.c: New test. From-SVN: r217415
Diffstat (limited to 'gcc/tree-ssa-dce.c')
-rw-r--r--gcc/tree-ssa-dce.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 923a0341fad..6543dc7d26a 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -85,6 +85,8 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
#include "tree-chkp.h"
+#include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
static struct stmt_stats
{
@@ -1162,6 +1164,109 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
release_defs (stmt);
}
+/* Helper for maybe_optimize_arith_overflow. Find in *TP if there are any
+ uses of data (SSA_NAME) other than REALPART_EXPR referencing it. */
+
+static tree
+find_non_realpart_uses (tree *tp, int *walk_subtrees, void *data)
+{
+ if (TYPE_P (*tp) || TREE_CODE (*tp) == REALPART_EXPR)
+ *walk_subtrees = 0;
+ if (*tp == (tree) data)
+ return *tp;
+ return NULL_TREE;
+}
+
+/* If the IMAGPART_EXPR of the {ADD,SUB,MUL}_OVERFLOW result is never used,
+ but REALPART_EXPR is, optimize the {ADD,SUB,MUL}_OVERFLOW internal calls
+ into plain unsigned {PLUS,MINUS,MULT}_EXPR, and if needed reset debug
+ uses. */
+
+static void
+maybe_optimize_arith_overflow (gimple_stmt_iterator *gsi,
+ enum tree_code subcode)
+{
+ gimple stmt = gsi_stmt (*gsi);
+ tree lhs = gimple_call_lhs (stmt);
+
+ if (lhs == NULL || TREE_CODE (lhs) != SSA_NAME)
+ return;
+
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ bool has_debug_uses = false;
+ bool has_realpart_uses = false;
+ bool has_other_uses = false;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+ {
+ gimple use_stmt = USE_STMT (use_p);
+ if (is_gimple_debug (use_stmt))
+ has_debug_uses = true;
+ else if (is_gimple_assign (use_stmt)
+ && gimple_assign_rhs_code (use_stmt) == REALPART_EXPR
+ && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == lhs)
+ has_realpart_uses = true;
+ else
+ {
+ has_other_uses = true;
+ break;
+ }
+ }
+
+ if (!has_realpart_uses || has_other_uses)
+ return;
+
+ tree arg0 = gimple_call_arg (stmt, 0);
+ tree arg1 = gimple_call_arg (stmt, 1);
+ location_t loc = gimple_location (stmt);
+ tree type = TREE_TYPE (TREE_TYPE (lhs));
+ tree utype = type;
+ if (!TYPE_UNSIGNED (type))
+ utype = build_nonstandard_integer_type (TYPE_PRECISION (type), 1);
+ tree result = fold_build2_loc (loc, subcode, utype,
+ fold_convert_loc (loc, utype, arg0),
+ fold_convert_loc (loc, utype, arg1));
+ result = fold_convert_loc (loc, type, result);
+
+ if (has_debug_uses)
+ {
+ gimple use_stmt;
+ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
+ {
+ if (!gimple_debug_bind_p (use_stmt))
+ continue;
+ tree v = gimple_debug_bind_get_value (use_stmt);
+ if (walk_tree (&v, find_non_realpart_uses, lhs, NULL))
+ {
+ gimple_debug_bind_reset_value (use_stmt);
+ update_stmt (use_stmt);
+ }
+ }
+ }
+
+ if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result))
+ result = drop_tree_overflow (result);
+ tree overflow = build_zero_cst (type);
+ tree ctype = build_complex_type (type);
+ if (TREE_CODE (result) == INTEGER_CST)
+ result = build_complex (ctype, result, overflow);
+ else
+ result = build2_loc (gimple_location (stmt), COMPLEX_EXPR,
+ ctype, result, overflow);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Transforming call: ");
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ fprintf (dump_file, "because the overflow result is never used into: ");
+ print_generic_stmt (dump_file, result, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+
+ if (!update_call_from_tree (gsi, result))
+ gimplify_and_update_call_from_tree (gsi, result);
+}
+
/* Eliminate unnecessary statements. Any instruction not marked as necessary
contributes nothing to the program, and can be deleted. */
@@ -1298,6 +1403,21 @@ eliminate_unnecessary_stmts (void)
update_stmt (stmt);
release_ssa_name (name);
}
+ else if (gimple_call_internal_p (stmt))
+ switch (gimple_call_internal_fn (stmt))
+ {
+ case IFN_ADD_OVERFLOW:
+ maybe_optimize_arith_overflow (&gsi, PLUS_EXPR);
+ break;
+ case IFN_SUB_OVERFLOW:
+ maybe_optimize_arith_overflow (&gsi, MINUS_EXPR);
+ break;
+ case IFN_MUL_OVERFLOW:
+ maybe_optimize_arith_overflow (&gsi, MULT_EXPR);
+ break;
+ default:
+ break;
+ }
}
}
}