This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix vectorizer ICEs with -ftrapv (PR tree-optimization/81661, PR tree-optimization/84117)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Biener <rguenther at suse dot de>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Wed, 31 Jan 2018 21:53:29 +0100
- Subject: [PATCH] Fix vectorizer ICEs with -ftrapv (PR tree-optimization/81661, PR tree-optimization/84117)
- Authentication-results: sourceware.org; auth=none
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
Some spots in the vectorizer create generic COND_EXPRs that in one of the
branches compute some +/-/* arithmetics. When -ftrapv, the gimplifier
ICEs on this as it may trap, we can't emit code with multiple basic blocks
from the APIs and don't want to evaluate it if the guarding condition is
false.
This patch resolves it by making that arithmetic untrappable (i.e. in
unsigned types).
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2018-01-31 Jakub Jelinek <jakub@redhat.com>
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.
--- gcc/tree-eh.h.jj 2018-01-03 10:19:54.561533862 +0100
+++ gcc/tree-eh.h 2018-01-31 11:59:36.328182707 +0100
@@ -37,6 +37,7 @@ extern bool operation_could_trap_helper_
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 *);
--- gcc/tree-eh.c.jj 2018-01-03 10:19:56.103534109 +0100
+++ gcc/tree-eh.c 2018-01-31 16:51:00.726119778 +0100
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.
#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. */
--- gcc/tree-vect-loop.c.jj 2018-01-19 19:41:53.624549770 +0100
+++ gcc/tree-vect-loop.c 2018-01-31 12:02:02.642190868 +0100
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.
#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,
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;
}
--- gcc/tree-data-ref.c.jj 2018-01-14 17:16:55.614836141 +0100
+++ gcc/tree-data-ref.c 2018-01-31 12:01:04.836187642 +0100
@@ -98,6 +98,7 @@ along with GCC; see the file COPYING3.
#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_l
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);
--- gcc/testsuite/gcc.dg/pr81661.c.jj 2018-01-31 12:08:20.457211930 +0100
+++ gcc/testsuite/gcc.dg/pr81661.c 2018-01-31 12:08:03.723210999 +0100
@@ -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--;
+}
--- gcc/testsuite/gfortran.dg/pr84117.f90.jj 2018-01-31 12:09:11.305214765 +0100
+++ gcc/testsuite/gfortran.dg/pr84117.f90 2018-01-31 12:09:31.827215918 +0100
@@ -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
Jakub