diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88df7ab9c19..b1c56173d59 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2018-02-01 Jakub Jelinek + + 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. + 2018-01-31 Uros Bizjak PR rtl-optimization/84123 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 778ba75498d..92d013e4879 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2018-02-01 Jakub Jelinek + + PR tree-optimization/81661 + PR tree-optimization/84117 + * gcc.dg/pr81661.c: New test. + * gfortran.dg/pr84117.f90: New test. + 2018-02-01 Janne Blomqvist PR fortran/83705 diff --git a/gcc/testsuite/gcc.dg/pr81661.c b/gcc/testsuite/gcc.dg/pr81661.c new file mode 100644 index 00000000000..d8d27304ddb --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr81661.c @@ -0,0 +1,12 @@ +/* PR tree-optimization/81661 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -ftrapv" } */ + +int a, b, c; + +void +foo (void) +{ + while (a + c > b) + a--; +} diff --git a/gcc/testsuite/gfortran.dg/pr84117.f90 b/gcc/testsuite/gfortran.dg/pr84117.f90 new file mode 100644 index 00000000000..1853d8c5f39 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr84117.f90 @@ -0,0 +1,7 @@ +! PR tree-optimization/84117 +! { dg-do compile } +! { dg-options "-O3 -ftrapv" } + FUNCTION pw_integral_aa ( cc ) RESULT ( integral_value ) + COMPLEX(KIND=8), DIMENSION(:), POINTER :: cc + integral_value = accurate_sum ( CONJG ( cc (:) ) * cc (:) ) + END FUNCTION pw_integral_aa diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 0b6ad5fd529..b5c0b7f4281 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -98,6 +98,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "tree-vrp.h" #include "tree-ssanames.h" +#include "tree-eh.h" static struct datadep_stats { @@ -1790,7 +1791,8 @@ get_segment_min_max (const dr_with_seg_len &d, tree *seg_min_out, tree addr_base = fold_build_pointer_plus (DR_BASE_ADDRESS (d.dr), DR_OFFSET (d.dr)); addr_base = fold_build_pointer_plus (addr_base, DR_INIT (d.dr)); - tree seg_len = fold_convert (sizetype, d.seg_len); + tree seg_len + = fold_convert (sizetype, rewrite_to_non_trapping_overflow (d.seg_len)); tree min_reach = fold_build3 (COND_EXPR, sizetype, neg_step, seg_len, size_zero_node); diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 3f546231089..75385f7b53f 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 *) 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 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. */ diff --git a/gcc/tree-eh.h b/gcc/tree-eh.h index 6e1fa713e08..11e096c9e5f 100644 --- a/gcc/tree-eh.h +++ b/gcc/tree-eh.h @@ -37,6 +37,7 @@ extern bool operation_could_trap_helper_p (enum tree_code, bool, bool, bool, bool, tree, bool *); extern bool operation_could_trap_p (enum tree_code, bool, bool, tree); extern bool tree_could_trap_p (tree); +extern tree rewrite_to_non_trapping_overflow (tree); extern bool stmt_could_throw_p (gimple *); extern bool tree_could_throw_p (tree); extern bool stmt_can_throw_external (gimple *); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index f75a48313a2..c5301684028 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "internal-fn.h" #include "tree-vector-builder.h" #include "vec-perm-indices.h" +#include "tree-eh.h" /* Loop Vectorization Pass. @@ -1063,7 +1064,8 @@ vect_get_loop_niters (struct loop *loop, tree *assumptions, may_be_zero)); else niter = fold_build3 (COND_EXPR, TREE_TYPE (niter), may_be_zero, - build_int_cst (TREE_TYPE (niter), 0), niter); + build_int_cst (TREE_TYPE (niter), 0), + rewrite_to_non_trapping_overflow (niter)); may_be_zero = NULL_TREE; }