[I'll push this pending another round of testing, as I tweaked a few
things last minute.]
The functions range_from_readonly_* special case pointers and only
handle when a constant aggregate is known to be all non-null. We can
do better than this, and removing the special casing gives us better
ranges, while cleaning up the code.
This patch has us accumulate a pointer range like we do for integers,
all while handling missing elements in a constructor. I'm also
changing the meaning of the bool returned from
range_from_readonly_load, to match what we do in the rest of ranger
(true means we have a usable range).
There's a slight change in behavior for a zero-length array of
pointers which was taken as non-null the way the walk was structured,
but reading this array is undefined behavior anyhow. Now the walk
adds nothing to the range for it. This is the same behavior we have
for integers.
Tested on ppc64le Linux. No assembly changes over a corpus of .ii
files from a stage1 bootstrap.
gcc/ChangeLog:
* gimple-range-fold.cc (range_from_missing_constructor_part): Add
zero for pointers too. Remove assert.
(range_from_readonly_load): Add a null or a non-null range for a
pointer element.
(fold_using_range::range_from_readonly_var): Return the
accumulated range for pointers too, and fail if it is varying.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/vrp-from-cst-agg-12.c: New test.
---
gcc/gimple-range-fold.cc | 35 +++++------
.../gcc.dg/tree-ssa/vrp-from-cst-agg-12.c | 60 +++++++++++++++++++
2 files changed, 76 insertions(+), 19 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-12.c
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a143c19647a..be4c00b055e 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -992,16 +992,11 @@ fold_using_range::range_of_address (prange &r, gimple
*stmt, fur_source &src)
return true;
}
-/* If TYPE is a pointer, return false. Otherwise, add zero of TYPE (which must
- be an integer or a float) to R and return true. */
+/* Add zero of TYPE 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)
- || frange::supports_p (type));
value_range zero (type);
zero.set_zero (type);
r.union_ (zero);
@@ -1011,11 +1006,9 @@ range_from_missing_constructor_part (vrange &r, tree
type)
// 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 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.
+// invariant or a constructor. 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,
@@ -1028,7 +1021,15 @@ range_from_readonly_load (vrange &r, tree type, tree cst,
if (POINTER_TYPE_P (type))
{
- return tree_single_nonzero_p (cst);
+ prange elt;
+ if (integer_zerop (cst))
+ elt.set_zero (type);
+ else if (tree_single_nonzero_p (cst))
+ elt.set_nonzero (type);
+ else
+ return false;
+ r.union_ (elt);
+ return true;
}
if (TREE_CODE (cst) == REAL_CST)
@@ -1182,14 +1183,10 @@ fold_using_range::range_from_readonly_var (vrange &r,
gimple *stmt)
}
value_range tmp (type);
- bool res = range_from_readonly_load (tmp, type, ctor, comps, count);
+ bool res = (range_from_readonly_load (tmp, type, ctor, comps, count)
+ && !tmp.varying_p ());
if (res)
- {
- if (POINTER_TYPE_P (type))
- r.set_nonzero (type);
- else
- r = tmp;
- }
+ r = tmp;
return res;
}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-12.c
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-12.c
new file mode 100644
index 00000000000..b755791f28a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-12.c
@@ -0,0 +1,60 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+/* A load from a constant aggregate whose pointers are all null, or left
+ out of its initializer, is null. One that may read a null or a
+ non-null pointer is either. */
+
+void link_error (void);
+
+static void handle (void) { }
+
+struct op { int code; void (*handler) (void); };
+static const struct op ops[3] = { { 1, 0 }, { 2, 0 }, { 3, 0 } };
+static void (*const fns[4]) (void) = { 0 };
+static void (*const mixed[2]) (void) = { 0, handle };
+
+[[gnu::noinline]] void
+foo (int i)
+{
+ if (ops[i].handler)
+ link_error ();
+}
+
+[[gnu::noinline]] void
+bar (int i)
+{
+ if (fns[i])
+ link_error ();
+}
+
+[[gnu::noipa]] int
+baz (int i)
+{
+ return mixed[i] != 0;
+}
+
+[[gnu::noipa]] int
+qux (int i, int c)
+{
+ void (*p) (void) = c ? mixed[i] : handle;
+ return p != 0;
+}
+
+[[gnu::noipa]] int
+get_index (void)
+{
+ return 1;
+}
+
+int
+main (void)
+{
+ foo (get_index ());
+ bar (get_index ());
+ if (baz (0) || !baz (1))
+ __builtin_abort ();
+ if (qux (0, 1) || !qux (1, 1))
+ __builtin_abort ();
+ return 0;
+}
--
2.53.0