value-range: Fix handling of POLY_INT_CST anti-ranges [PR96146]
authorRichard Sandiford <richard.sandiford@arm.com>
Sat, 11 Jul 2020 12:25:26 +0000 (13:25 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Sat, 11 Jul 2020 12:25:26 +0000 (13:25 +0100)
The range infrastructure has code to decompose POLY_INT_CST ranges
to worst-case integer bounds.  However, it had the fundamental flaw
(obvious in hindsight) that it applied to anti-ranges too, meaning
that a range 2+2X would end up with a range of ~[2, +INF], i.e.
[-INF, 1].  This patch decays to varying in that case instead.

I'm still a bit uneasy about this.  ISTM that in terms of
generality:

  SSA_NAME => POLY_INT_CST => INTEGER_CST
           => ADDR_EXPR

I.e. an SSA_NAME could store a POLY_INT_CST and a POLY_INT_CST
could store an INTEGER_CST (before canonicalisation).  POLY_INT_CST
is also “as constant as” ADDR_EXPR (well, OK, only some ADDR_EXPRs
are run-time rather than link-time constants, whereas all POLY_INT_CSTs
are, but still).  So it seems like we should at least be able to treat
POLY_INT_CST as symbolic.  On the other hand, I don't have any examples
in which that would be useful.

gcc/
PR tree-optimization/96146
* value-range.cc (value_range::set): Only decompose POLY_INT_CST
bounds to integers for VR_RANGE.  Decay to VR_VARYING for anti-ranges
involving POLY_INT_CSTs.

gcc/testsuite/
PR tree-optimization/96146
* gcc.target/aarch64/sve/acle/general/pr96146.c: New test.

gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr96146.c [new file with mode: 0644]
gcc/value-range.cc

diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr96146.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr96146.c
new file mode 100644 (file)
index 0000000..b05fac4
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O3" } */
+
+#include <arm_sve.h>
+
+void __attribute__ ((noipa))
+f (volatile int *x)
+{
+  int i;
+  for (int i = 0; i < svcntd (); ++i)
+    *x = i;
+}
+
+int
+main (void)
+{
+  volatile int x;
+  f (&x);
+  return 0;
+}
index 929a6b59aafb1c1f1313a4bc396be775142cd2c8..bc4b061da57170f7140ccfd6b50c68b75d958ec5 100644 (file)
@@ -86,7 +86,34 @@ value_range::set (tree min, tree max, value_range_kind kind)
       set_undefined ();
       return;
     }
-  else if (kind == VR_VARYING)
+
+  if (kind == VR_RANGE)
+    {
+      /* Convert POLY_INT_CST bounds into worst-case INTEGER_CST bounds.  */
+      if (POLY_INT_CST_P (min))
+       {
+         tree type_min = vrp_val_min (TREE_TYPE (min));
+         widest_int lb
+           = constant_lower_bound_with_limit (wi::to_poly_widest (min),
+                                              wi::to_widest (type_min));
+         min = wide_int_to_tree (TREE_TYPE (min), lb);
+       }
+      if (POLY_INT_CST_P (max))
+       {
+         tree type_max = vrp_val_max (TREE_TYPE (max));
+         widest_int ub
+           = constant_upper_bound_with_limit (wi::to_poly_widest (max),
+                                              wi::to_widest (type_max));
+         max = wide_int_to_tree (TREE_TYPE (max), ub);
+       }
+    }
+  else if (kind != VR_VARYING)
+    {
+      if (POLY_INT_CST_P (min) || POLY_INT_CST_P (max))
+       kind = VR_VARYING;
+    }
+
+  if (kind == VR_VARYING)
     {
       gcc_assert (TREE_TYPE (min) == TREE_TYPE (max));
       tree typ = TREE_TYPE (min);
@@ -99,24 +126,6 @@ value_range::set (tree min, tree max, value_range_kind kind)
       return;
     }
 
-  /* Convert POLY_INT_CST bounds into worst-case INTEGER_CST bounds.  */
-  if (POLY_INT_CST_P (min))
-    {
-      tree type_min = vrp_val_min (TREE_TYPE (min));
-      widest_int lb
-       = constant_lower_bound_with_limit (wi::to_poly_widest (min),
-                                          wi::to_widest (type_min));
-      min = wide_int_to_tree (TREE_TYPE (min), lb);
-    }
-  if (POLY_INT_CST_P (max))
-    {
-      tree type_max = vrp_val_max (TREE_TYPE (max));
-      widest_int ub
-       = constant_upper_bound_with_limit (wi::to_poly_widest (max),
-                                          wi::to_widest (type_max));
-      max = wide_int_to_tree (TREE_TYPE (max), ub);
-    }
-
   /* Nothing to canonicalize for symbolic ranges.  */
   if (TREE_CODE (min) != INTEGER_CST
       || TREE_CODE (max) != INTEGER_CST)