diff options
author | Jakub Jelinek <jakub@redhat.com> | 2018-02-01 11:08:26 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2018-02-01 11:08:26 +0100 |
commit | 31b6733b1628a861de4c545bff40acc97850dbbf (patch) | |
tree | f42a2adeb53b018ecc56134e5735e062d67b17fa /gcc/tree-eh.c | |
parent | eae4d8fbb529d67428a2b0eba407b975ee13e7d1 (diff) | |
download | gcc-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.c | 86 |
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. */ |