On 10/31/25 17:46, Martin Jambor wrote:
Hi,

this patch adds the ability to infer ranges from loads from global
constant static aggregates which have static initializers.  Even when
the load has an ARRAY_REF with an unknown index and thus we do not know
the particular constant that is being loaded, we can traverse the
corresponding elements of the initializer and see if we know in what
range(s) the loaded value must fall - or for pointers we can sometimes
infer that the value cannot be NULL.

I thought this was similar to fold_using_range::range_of_address and
so I decided to put my implementation alongside of it.  I hope that is
the correct place.
seems reasonable.
Bootstrapped, LTO-bootstrapped and tested on x86_64-linux, bootstrap
on aarch64-linux is underway.  OK for master if it passes?

Thanks,

Martin


gcc/ChangeLog:

2025-10-31  Martin Jambor  <[email protected]>

        * gimple-range-fold.h (class fold_using_range): New member
        function range_from_readonly_var.
        * gimple-range-fold.cc (fold_using_range::fold_stmt): Call
        range_from_readonly_var on assignments.
        (add_loaded_invariant_to_range): New function.
        (range_from_readonly_load): Likewise.
        (fold_using_range::range_from_readonly_var): Likewise.
        * params.opt (param_vrp_cstload_limit): New.
        * doc/invoke.texi (vrp-cstload-limit): Likewise.

gcc/testsuite/ChangeLog:

2025-10-31  Martin Jambor  <[email protected]>

        * gcc.dg/tree-ssa/vrp-from-cst-agg-1.c: New test.
        * gcc.dg/tree-ssa/vrp-from-cst-agg-2.c: Likewise.
        * gcc.dg/tree-ssa/vrp-from-cst-agg-3.c: Likewise.
        * gcc.dg/tree-ssa/vrp-from-cst-agg-4.c: Likewise.
        * gcc.dg/ipa/vrp-from-cst-agg-5.c: Likewise.
---
  gcc/doc/invoke.texi                           |   3 +
  gcc/gimple-range-fold.cc                      | 214 +++++++++++++++++-
  gcc/gimple-range-fold.h                       |   1 +
  gcc/params.opt                                |   4 +
  gcc/testsuite/gcc.dg/ipa/vrp-from-cst-agg-5.c |  33 +++
  .../gcc.dg/tree-ssa/vrp-from-cst-agg-1.c      |  36 +++
  .../gcc.dg/tree-ssa/vrp-from-cst-agg-2.c      |  57 +++++
  .../gcc.dg/tree-ssa/vrp-from-cst-agg-3.c      |  34 +++
  .../gcc.dg/tree-ssa/vrp-from-cst-agg-4.c      |  34 +++
  9 files changed, 412 insertions(+), 4 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/ipa/vrp-from-cst-agg-5.c
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-1.c
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-2.c
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-3.c
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-4.c

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index b40fc892fa0..c2542f8b882 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -17632,6 +17632,9 @@ Increasing the cost multiplier will make vector loops 
more profitable.
  @item vrp-block-limit
  Maximum number of basic blocks before VRP switches to a lower memory 
algorithm.
+@item vrp-cstload-limit
+Maximum number of VRP intervals inferred from a load from a constant aggregate.
+
  @item vrp-sparse-threshold
  Maximum number of basic blocks before VRP uses a sparse bitmap cache.
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 06c645f3d08..b455589428e 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -639,10 +639,14 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source 
&src, tree name)
    if (!name)
      name = gimple_get_lhs (s);
- // Process addresses.
-  if (gimple_code (s) == GIMPLE_ASSIGN
-      && gimple_assign_rhs_code (s) == ADDR_EXPR)
-    return range_of_address (as_a <prange> (r), s, src);
+  // Process addresses and loads from static constructors.
+  if (gimple_code (s) == GIMPLE_ASSIGN)
+    {
+      if (gimple_assign_rhs_code (s) == ADDR_EXPR)
+       return range_of_address (as_a <prange> (r), s, src);
+      if (range_from_readonly_var (r, s))
+       return true;
+    }
gimple_range_op_handler handler (s);
    if (handler)
@@ -891,6 +895,208 @@ fold_using_range::range_of_address (prange &r, gimple *stmt, 
fur_source &src)
    return true;
  }
+// VAL must be an interprocedural invariant. If VAL is a pointer which cannot
+// be zero, then set it to nonzero if it is undefined and return true.  If VAL
+// is a pointer which can be zero return false.  If VAL is of another type, add
+// the constant to the set of ranges to R and return true.
+
+static bool
+add_loaded_invariant_to_range (vrange &r, tree val)
+{
+  if (POINTER_TYPE_P (TREE_TYPE (val)))
+    {
+      bool strict_overflow_p;
+      if (tree_single_nonzero_warnv_p (val, &strict_overflow_p))
+       {
+         if (r.undefined_p ())
+           r.set_nonzero (TREE_TYPE (val));
+         return true;
+       }
+      else
+       return false;


Do you want to return true if  r  is not undefined and you don't change it?

+    }
+  else
+    {
+      if (TREE_CODE (val) == REAL_CST
+         && real_isnan (TREE_REAL_CST_PTR (val)))
+       return false;
+
If val is not a REAL_CST.. do you want to drop down to create a value_range with it?  and i think frange handles NAN as a value just fine...  do you even need this part?
+      if (is_a <irange> (r))
+       {
+         irange &ir = as_a <irange> (r);
+         if (!r.contains_p (val)
+             && ir.num_pairs () >= (unsigned) param_vrp_cstload_limit)
+           return false;
+       }
+
+      value_range tmp (val, val, VR_RANGE);
+      if (r.undefined_p ())
+       r = tmp;
+      else
+       r.union_ (tmp);
+      return true;
+    }
+}

answering from a different message, Yes, only iranges have multiple pairs.

No need to check for undefined... just call union_ ().. it is pretty efficient.  It does an assign if it is undefined.

 Andrew


Reply via email to