This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix vectorizer ICEs with -ftrapv (PR tree-optimization/81661, PR tree-optimization/84117)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]