aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-eh.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-02-01 11:08:26 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2018-02-01 11:08:26 +0100
commit31b6733b1628a861de4c545bff40acc97850dbbf (patch)
treef42a2adeb53b018ecc56134e5735e062d67b17fa /gcc/tree-eh.c
parenteae4d8fbb529d67428a2b0eba407b975ee13e7d1 (diff)
downloadgcc-31b6733b1628a861de4c545bff40acc97850dbbf.zip
gcc-31b6733b1628a861de4c545bff40acc97850dbbf.tar.gz
gcc-31b6733b1628a861de4c545bff40acc97850dbbf.tar.bz2
re PR tree-optimization/81661 (ICE in gimplify_modify_expr, at gimplify.c:5638)
PR tree-optimization/81661 PR tree-optimization/84117 * tree-eh.h (rewrite_to_non_trapping_overflow): Declare. * tree-eh.c: Include gimplify.h. (find_trapping_overflow, replace_trapping_overflow, rewrite_to_non_trapping_overflow): New functions. * tree-vect-loop.c: Include tree-eh.h. (vect_get_loop_niters): Use rewrite_to_non_trapping_overflow. * tree-data-ref.c: Include tree-eh.h. (get_segment_min_max): Use rewrite_to_non_trapping_overflow. * gcc.dg/pr81661.c: New test. * gfortran.dg/pr84117.f90: New test. From-SVN: r257284
Diffstat (limited to 'gcc/tree-eh.c')
-rw-r--r--gcc/tree-eh.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 3f54623..75385f7 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "gimplify.h"
/* In some instances a tree and a gimple need to be stored in a same table,
i.e. in hash tables. This is a structure to do this. */
@@ -2720,6 +2721,91 @@ tree_could_trap_p (tree expr)
}
}
+/* Return non-NULL if there is an integer operation with trapping overflow
+ we can rewrite into non-trapping. Called via walk_tree from
+ rewrite_to_non_trapping_overflow. */
+
+static tree
+find_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
+{
+ if (EXPR_P (*tp)
+ && !operation_no_trapping_overflow (TREE_TYPE (*tp), TREE_CODE (*tp)))
+ return *tp;
+ if (IS_TYPE_OR_DECL_P (*tp)
+ || (TREE_CODE (*tp) == SAVE_EXPR && data == NULL))
+ *walk_subtrees = 0;
+ return NULL_TREE;
+}
+
+/* Rewrite selected operations into unsigned arithmetics, so that they
+ don't trap on overflow. */
+
+static tree
+replace_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
+{
+ if (find_trapping_overflow (tp, walk_subtrees, data))
+ {
+ tree type = TREE_TYPE (*tp);
+ tree utype = unsigned_type_for (type);
+ *walk_subtrees = 0;
+ int len = TREE_OPERAND_LENGTH (*tp);
+ for (int i = 0; i < len; ++i)
+ walk_tree (&TREE_OPERAND (*tp, i), replace_trapping_overflow,
+ data, (hash_set<tree> *) data);
+
+ if (TREE_CODE (*tp) == ABS_EXPR)
+ {
+ tree op = TREE_OPERAND (*tp, 0);
+ op = save_expr (op);
+ /* save_expr skips simple arithmetics, which is undesirable
+ here, if it might trap due to flag_trapv. We need to
+ force a SAVE_EXPR in the COND_EXPR condition, to evaluate
+ it before the comparison. */
+ if (EXPR_P (op)
+ && TREE_CODE (op) != SAVE_EXPR
+ && walk_tree (&op, find_trapping_overflow, NULL, NULL))
+ {
+ op = build1_loc (EXPR_LOCATION (op), SAVE_EXPR, type, op);
+ TREE_SIDE_EFFECTS (op) = 1;
+ }
+ /* Change abs (op) to op < 0 ? -op : op and handle the NEGATE_EXPR
+ like other signed integer trapping operations. */
+ tree cond = fold_build2 (LT_EXPR, boolean_type_node,
+ op, build_int_cst (type, 0));
+ tree neg = fold_build1 (NEGATE_EXPR, utype,
+ fold_convert (utype, op));
+ *tp = fold_build3 (COND_EXPR, type, cond,
+ fold_convert (type, neg), op);
+ }
+ else
+ {
+ TREE_TYPE (*tp) = utype;
+ len = TREE_OPERAND_LENGTH (*tp);
+ for (int i = 0; i < len; ++i)
+ TREE_OPERAND (*tp, i)
+ = fold_convert (utype, TREE_OPERAND (*tp, i));
+ *tp = fold_convert (type, *tp);
+ }
+ }
+ return NULL_TREE;
+}
+
+/* If any subexpression of EXPR can trap due to -ftrapv, rewrite it
+ using unsigned arithmetics to avoid traps in it. */
+
+tree
+rewrite_to_non_trapping_overflow (tree expr)
+{
+ if (!flag_trapv)
+ return expr;
+ hash_set<tree> pset;
+ if (!walk_tree (&expr, find_trapping_overflow, &pset, &pset))
+ return expr;
+ expr = unshare_expr (expr);
+ pset.empty ();
+ walk_tree (&expr, replace_trapping_overflow, &pset, &pset);
+ return expr;
+}
/* Helper for stmt_could_throw_p. Return true if STMT (assumed to be a
an assignment or a conditional) may throw. */