DOM's cprop folds a load from a constant table of doubles like one
of integers, so it threads a comparison the selected element decides:

  static const double tab[2] = { 0.5, 2.5 };
  if (c) i = 1; else { i = 0; d = d + 1; }
  if (d && tab[i] > 1.0) ...

On the other hand, ranger can't because range_from_readonly_var does
not handle floats as the TODO in there notes.  This patch implements
this.

Tested on ppc64le Linux.  The assembly is identical over a corpus of
.ii files from a stage1 bootstrap and over the LAPACK sources, and
LAPACK's ctests pass.

Pushed.

gcc/ChangeLog:

        * gimple-range-fold.cc (range_from_missing_constructor_part):
        Allow float types.
        (range_from_readonly_load): Add the range of a REAL_CST.
        (fold_using_range::range_from_readonly_var): Allow float types.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/vrp-from-cst-agg-8.c: New test.
---
 gcc/gimple-range-fold.cc                      | 37 +++++++++++++------
 .../gcc.dg/tree-ssa/vrp-from-cst-agg-8.c      | 28 ++++++++++++++
 2 files changed, 53 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-8.c

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 7dd9ddfd796..abe3ade2960 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -993,28 +993,29 @@ fold_using_range::range_of_address (prange &r, gimple 
*stmt, fur_source &src)
 }
 
 /* If TYPE is a pointer, return false.  Otherwise, add zero of TYPE (which must
-   be an integer) to R and return true.  */
+   be an integer or a float) to R and return true.  */
 
 static bool
 range_from_missing_constructor_part (vrange &r, tree type)
 {
   if (POINTER_TYPE_P (type))
     return false;
-  gcc_checking_assert (irange::supports_p (type));
-  wide_int zero = wi::zero (TYPE_PRECISION (type));
-  r.union_ (int_range<1> (type, zero, zero));
+  gcc_checking_assert (irange::supports_p (type)
+                      || frange::supports_p (type));
+  value_range zero (type);
+  zero.set_zero (type);
+  r.union_ (zero);
   return true;
 }
 
 // One step of fold_using_range::range_from_readonly_var.  Process expressions
 // in COMPS which together load a value of TYPE, from index I to 0 according to
 // the corresponding static initializer in CST which should be either a scalar
-// invariant or a constructor.  Currently TYPE must be either a pointer or an
-// integer.  If TYPE is a pointer, return true if all potentially loaded values
-// are known not to be zero and false if any of them can be zero.  Otherwise
-// return true if it is possible to add all constants which can be loaded from
-// CST (which must be storable to TYPE) to R and do so.
-// TODO: Add support for franges.
+// invariant or a constructor.  Currently TYPE must be a pointer, an integer
+// or a float.  If TYPE is a pointer, return true if all potentially loaded
+// values are known not to be zero and false if any of them can be zero.
+// Otherwise return true if it is possible to add all constants which can be
+// loaded from CST (which must be storable to TYPE) to R and do so.
 
 static bool
 range_from_readonly_load (vrange &r, tree type, tree cst,
@@ -1030,6 +1031,18 @@ range_from_readonly_load (vrange &r, tree type, tree cst,
          return tree_single_nonzero_p (cst);
        }
 
+      if (TREE_CODE (cst) == REAL_CST)
+       {
+         const REAL_VALUE_TYPE *rv = TREE_REAL_CST_PTR (cst);
+         frange elt;
+         if (real_isnan (rv))
+           elt.set_nan (type, real_isneg (rv));
+         else
+           elt.set (type, *rv, *rv, nan_state (false));
+         r.union_ (elt);
+         return true;
+       }
+
       if (TREE_CODE (cst) != INTEGER_CST)
        return false;
 
@@ -1118,9 +1131,9 @@ fold_using_range::range_from_readonly_var (vrange &r, 
gimple *stmt)
 {
   gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
   tree type = TREE_TYPE (gimple_assign_lhs (stmt));
-  /* TODO: Add support for frange.  */
   if (!irange::supports_p (type)
-      && !prange::supports_p (type))
+      && !prange::supports_p (type)
+      && !frange::supports_p (type))
     return false;
 
   unsigned HOST_WIDE_INT limit = param_vrp_cstload_limit;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-8.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-8.c
new file mode 100644
index 00000000000..6e37badeea8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-8.c
@@ -0,0 +1,28 @@
+/* { dg-do link } */
+/* { dg-options "-O2" } */
+
+volatile double gd;
+
+static const double values[4] = {0.5, 1.5, 2.5, 3.5};
+
+void link_error (void);
+
+void foo (int index)
+{
+  if (index < 0 || index > 3)
+    return;
+  const double v = values[index];
+  if (v < 0.5 || v > 3.5)
+    link_error ();
+  if (v != v)
+    link_error ();
+  gd = v;
+}
+
+__attribute__((noipa)) int get_index (void) { return 2; }
+
+int main (void)
+{
+  foo (get_index ());
+  return 0;
+}
-- 
2.53.0

Reply via email to