[PATCH] Fix PR69760

Richard Biener rguenther@suse.de
Wed Feb 24 14:49:00 GMT 2016


The following fixes bogus SCEV analysis for expressions that are only
executed conditionally [note: conditionally here doesn't include
after a taken exit].  Basically we have to make sure further analysis
does not attempt to use undefined overflow for expressions we don't
know whether they are computed in the original source (for all
loop iterations).  This would result in bogus CHRECs as can be seen
in this PR.

The solution is to re-write those expressions in a way so overflow
behavior is well-defined.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2016-02-24  Richard Biener  <rguenther@suse.de>
	Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/69760
	* tree-scalar-evolution.c (interpret_rhs_expr): Re-write
	conditionally executed ops to well-defined overflow behavior.

	* gcc.dg/torture/pr69760.c: New testcase.

Index: gcc/tree-scalar-evolution.c
===================================================================
--- gcc/tree-scalar-evolution.c	(revision 233634)
+++ gcc/tree-scalar-evolution.c	(working copy)
@@ -1703,7 +1703,7 @@ static tree
 interpret_rhs_expr (struct loop *loop, gimple *at_stmt,
 		    tree type, tree rhs1, enum tree_code code, tree rhs2)
 {
-  tree res, chrec1, chrec2;
+  tree res, chrec1, chrec2, ctype;
   gimple *def;
 
   if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS)
@@ -1798,30 +1798,63 @@ interpret_rhs_expr (struct loop *loop, g
     case PLUS_EXPR:
       chrec1 = analyze_scalar_evolution (loop, rhs1);
       chrec2 = analyze_scalar_evolution (loop, rhs2);
-      chrec1 = chrec_convert (type, chrec1, at_stmt);
-      chrec2 = chrec_convert (type, chrec2, at_stmt);
+      ctype = type;
+      /* When the stmt is conditionally executed re-write the CHREC
+         into a form that has well-defined behavior on overflow.  */
+      if (at_stmt
+	  && INTEGRAL_TYPE_P (type)
+	  && ! TYPE_OVERFLOW_WRAPS (type)
+	  && ! dominated_by_p (CDI_DOMINATORS, loop->latch,
+			       gimple_bb (at_stmt)))
+	ctype = unsigned_type_for (type);
+      chrec1 = chrec_convert (ctype, chrec1, at_stmt);
+      chrec2 = chrec_convert (ctype, chrec2, at_stmt);
       chrec1 = instantiate_parameters (loop, chrec1);
       chrec2 = instantiate_parameters (loop, chrec2);
-      res = chrec_fold_plus (type, chrec1, chrec2);
+      res = chrec_fold_plus (ctype, chrec1, chrec2);
+      if (type != ctype)
+	res = chrec_convert (type, res, at_stmt);
       break;
 
     case MINUS_EXPR:
       chrec1 = analyze_scalar_evolution (loop, rhs1);
       chrec2 = analyze_scalar_evolution (loop, rhs2);
-      chrec1 = chrec_convert (type, chrec1, at_stmt);
-      chrec2 = chrec_convert (type, chrec2, at_stmt);
+      ctype = type;
+      /* When the stmt is conditionally executed re-write the CHREC
+         into a form that has well-defined behavior on overflow.  */
+      if (at_stmt
+	  && INTEGRAL_TYPE_P (type)
+	  && ! TYPE_OVERFLOW_WRAPS (type)
+	  && ! dominated_by_p (CDI_DOMINATORS,
+			       loop->latch, gimple_bb (at_stmt)))
+	ctype = unsigned_type_for (type);
+      chrec1 = chrec_convert (ctype, chrec1, at_stmt);
+      chrec2 = chrec_convert (ctype, chrec2, at_stmt);
       chrec1 = instantiate_parameters (loop, chrec1);
       chrec2 = instantiate_parameters (loop, chrec2);
-      res = chrec_fold_minus (type, chrec1, chrec2);
+      res = chrec_fold_minus (ctype, chrec1, chrec2);
+      if (type != ctype)
+	res = chrec_convert (type, res, at_stmt);
       break;
 
     case NEGATE_EXPR:
       chrec1 = analyze_scalar_evolution (loop, rhs1);
-      chrec1 = chrec_convert (type, chrec1, at_stmt);
+      ctype = type;
+      /* When the stmt is conditionally executed re-write the CHREC
+         into a form that has well-defined behavior on overflow.  */
+      if (at_stmt
+	  && INTEGRAL_TYPE_P (type)
+	  && ! TYPE_OVERFLOW_WRAPS (type)
+	  && ! dominated_by_p (CDI_DOMINATORS,
+			       loop->latch, gimple_bb (at_stmt)))
+	ctype = unsigned_type_for (type);
+      chrec1 = chrec_convert (ctype, chrec1, at_stmt);
       /* TYPE may be integer, real or complex, so use fold_convert.  */
       chrec1 = instantiate_parameters (loop, chrec1);
-      res = chrec_fold_multiply (type, chrec1,
-				 fold_convert (type, integer_minus_one_node));
+      res = chrec_fold_multiply (ctype, chrec1,
+				 fold_convert (ctype, integer_minus_one_node));
+      if (type != ctype)
+	res = chrec_convert (type, res, at_stmt);
       break;
 
     case BIT_NOT_EXPR:
@@ -1837,11 +1870,22 @@ interpret_rhs_expr (struct loop *loop, g
     case MULT_EXPR:
       chrec1 = analyze_scalar_evolution (loop, rhs1);
       chrec2 = analyze_scalar_evolution (loop, rhs2);
-      chrec1 = chrec_convert (type, chrec1, at_stmt);
-      chrec2 = chrec_convert (type, chrec2, at_stmt);
+      ctype = type;
+      /* When the stmt is conditionally executed re-write the CHREC
+         into a form that has well-defined behavior on overflow.  */
+      if (at_stmt
+	  && INTEGRAL_TYPE_P (type)
+	  && ! TYPE_OVERFLOW_WRAPS (type)
+	  && ! dominated_by_p (CDI_DOMINATORS,
+			       loop->latch, gimple_bb (at_stmt)))
+	ctype = unsigned_type_for (type);
+      chrec1 = chrec_convert (ctype, chrec1, at_stmt);
+      chrec2 = chrec_convert (ctype, chrec2, at_stmt);
       chrec1 = instantiate_parameters (loop, chrec1);
       chrec2 = instantiate_parameters (loop, chrec2);
-      res = chrec_fold_multiply (type, chrec1, chrec2);
+      res = chrec_fold_multiply (ctype, chrec1, chrec2);
+      if (type != ctype)
+	res = chrec_convert (type, res, at_stmt);
       break;
 
     case LSHIFT_EXPR:
Index: gcc/testsuite/gcc.dg/torture/pr69760.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr69760.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr69760.c	(working copy)
@@ -0,0 +1,50 @@
+/* PR tree-optimization/69760 */
+/* { dg-do run { target { { *-*-linux* *-*-gnu* } && mmap } } } */
+/* { dg-options "-O2" } */
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+__attribute__((noinline, noclone)) void
+test_func (double *a, int L, int m, int n, int N)
+{
+  int i, k;
+  for (i = 0; i < N; i++)
+    {
+      k = i - m;
+      if (k >= 0 && k < n)
+	a[L * k] = 0.0;
+    }
+}
+
+int
+main ()
+{
+  char *p;
+  int L, m, n, N;
+  long l;
+  L = 10000000;
+  n = 4;
+  N = 100 * n;
+  long pgsz = sysconf(_SC_PAGESIZE);
+  if (pgsz < sizeof (double) || pgsz > L * sizeof (double))
+    return 0;
+  p = mmap ((void *) 0, L * n * sizeof (double), PROT_NONE,
+	    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (p == MAP_FAILED)
+    return 0;
+  if (mprotect (p, pgsz, PROT_READ | PROT_WRITE))
+    return 0;
+  l = (L * sizeof (double)) / pgsz * pgsz;
+  if (mprotect (p + l, pgsz, PROT_READ | PROT_WRITE))
+    return 0;
+  l = (2 * L * sizeof (double)) / pgsz * pgsz;
+  if (mprotect (p + l, pgsz, PROT_READ | PROT_WRITE))
+    return 0;
+  l = (3 * L * sizeof (double)) / pgsz * pgsz;
+  if (mprotect (p + l, pgsz, PROT_READ | PROT_WRITE))
+    return 0;
+  for (m = 0; m < N; m += n)
+    test_func ((double *) p, L, m, n, N);
+  return 0;
+}



More information about the Gcc-patches mailing list