https://gcc.gnu.org/g:31b8c15fd7608fe5bad8b105e9b5112ed18166dd

commit r17-3924-g31b8c15fd7608fe5bad8b105e9b5112ed18166dd
Author: Andrew MacLeod <[email protected]>
Date:   Mon Aug 31 14:25:21 2026 -0400

    Disallow path ranger from current_range_query.
    
    Provide a generic way to set the current range_query, and disable
    path_ranger from being pushed.  It can provide incorrect ranges from
    the path to requests not dominated by the path.
    
            PR tree-optimization/126942
            gcc/
            * gimple-range-fold.cc (fold_using_range::fold_stmt): Use
            set_range_query.
            * gimple-range-path.h (path_ranger::active_query_compatible_p): New.
            * gimple-range.cc (enable_ranger): Use set_range_query.
            (disable_ranger): Likewise.
            * tree-vrp.cc (execute_fast_vrp): Likewise.
            * value-query.cc (set_range_query): New.
            * value-query.h (range_query::active_query_compatible_p): New.
            (set_range_query): Declare.
    
            gcc/testsuite/
            * gcc.dg/pr126942.c: New.

Diff:
---
 gcc/gimple-range-fold.cc        | 17 ++++++++++-------
 gcc/gimple-range-path.h         |  2 ++
 gcc/gimple-range.cc             | 11 ++++++-----
 gcc/testsuite/gcc.dg/pr126942.c | 35 +++++++++++++++++++++++++++++++++++
 gcc/tree-vrp.cc                 | 13 +++++++------
 gcc/value-query.cc              | 26 ++++++++++++++++++++++++++
 gcc/value-query.h               |  6 ++++++
 7 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a64529603f82..7dd9ddfd7963 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -694,9 +694,9 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, 
fur_source &src, tree name)
   // If the specified query is different, make it the current one.
   // PR 125854 - The fold machinery may make a query call.
   // PR 126814 - tree_expr_nonnegative_p may make a call.
-  range_query *save = cfun->x_range_query;
-  if (src.query () != get_range_query (cfun))
-    cfun->x_range_query = src.query ();
+  // PR 126942 - path_ranger queries should never be the current query.
+  //            set_range_query will revert to a global query for this.
+  range_query *saved_query = set_range_query (cfun, src.query ());
 
   gimple_range_op_handler handler (s);
   if (gimple_code (s) == GIMPLE_ASSIGN
@@ -731,7 +731,8 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, 
fur_source &src, tree name)
   if (!res)
     {
       // Restore the original query.
-      cfun->x_range_query = save;
+      if (saved_query)
+       set_range_query (cfun, saved_query);
       // If no name specified or range is unsupported, bail.
       if (!name || !gimple_range_ssa_p (name))
        return false;
@@ -743,7 +744,8 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, 
fur_source &src, tree name)
   if (r.undefined_p ())
     {
       // Restore the original query.
-      cfun->x_range_query = save;
+      if (saved_query)
+       set_range_query (cfun, saved_query);
       return true;
     }
 
@@ -771,7 +773,7 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, 
fur_source &src, tree name)
          else
            {
              // If we couldn't find anything, try fold.
-             x_fold_context = { s, src.query () };
+             x_fold_context = { s, get_range_query (cfun) };
              rhs = gimple_fold_stmt_to_constant_1 (s, pta_valueize,
                                                    pta_valueize);
              if (rhs && TREE_CODE (rhs) == ADDR_EXPR)
@@ -780,7 +782,8 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, 
fur_source &src, tree name)
        }
     }
   // Restore the original query.
-  cfun->x_range_query = save;
+  if (saved_query)
+    set_range_query (cfun, saved_query);
   return true;
 }
 
diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h
index 4c162ef11f64..b6a37638a337 100644
--- a/gcc/gimple-range-path.h
+++ b/gcc/gimple-range-path.h
@@ -42,6 +42,8 @@ public:
   bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
   bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
   bool unreachable_path_p ();
+  // Path ranger should not be an active query.
+  virtual bool active_query_compatible_p () { return false; }
   void dump (FILE *) override;
   void debug ();
 
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index b221cfc56164..898eb6964b75 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -748,10 +748,11 @@ enable_ranger (struct function *fun, bool use_imm_uses)
 {
   gimple_ranger *r;
 
-  gcc_checking_assert (!fun->x_range_query);
   r = new gimple_ranger (use_imm_uses);
-  fun->x_range_query = r;
+  range_query *q = set_range_query (fun, r);
 
+  // Ranger should be the first and only instance.
+  gcc_checking_assert (q == get_global_range_query ());
   return r;
 }
 
@@ -761,9 +762,9 @@ enable_ranger (struct function *fun, bool use_imm_uses)
 void
 disable_ranger (struct function *fun)
 {
-  gcc_checking_assert (fun->x_range_query);
-  delete fun->x_range_query;
-  fun->x_range_query = NULL;
+  // Ensure this is the query being removed.
+  range_query *q = set_range_query (fun, get_global_range_query ());
+  delete q;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/gcc/testsuite/gcc.dg/pr126942.c b/gcc/testsuite/gcc.dg/pr126942.c
new file mode 100644
index 000000000000..c2100c6a895f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126942.c
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+signed char a;
+int b, c;
+short d[1];
+
+short
+foo (short *f, short g)
+{
+  int i = 0, j, l;
+  long n = 1;
+  for (int m = 0; m < a; m++)
+    for (; i <= m; i++)
+      n = i;
+  for (unsigned k = 0; k < g; k++)
+    {
+      l = 0;
+      do
+       if (f)
+         j = l + a;
+      while (++l <= k);
+    }
+  n ^= j;
+  while (a)
+    n ^= b;
+  return n;
+}
+
+int
+main ()
+{
+  if (foo (d, 2) != 0)
+    __builtin_abort ();
+}
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index dc8256dc33d3..11af4f681c03 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1241,20 +1241,21 @@ execute_fast_vrp (struct function *fun, bool final_p)
 {
   calculate_dominance_info (CDI_DOMINATORS);
   dom_ranger dr;
+  // Create a relation oracle without transitives.  It will automatically
+  // be destroyed when the destructor for 'dr' runs.
+  dr.create_relation_oracle (false);
   fvrp_folder folder (&dr, final_p);
 
-  gcc_checking_assert (!fun->x_range_query);
   set_all_edges_as_executable (fun);
-  fun->x_range_query = &dr;
-  // Create a relation oracle without transitives.
-  get_range_query (fun)->create_relation_oracle (false);
+  // Make DR the current range_query.
+  range_query *saved = set_range_query (fun, &dr);
 
   folder.substitute_and_fold ();
   if (folder.m_unreachable)
     folder.m_unreachable->remove ();
 
-  get_range_query (fun)->destroy_relation_oracle ();
-  fun->x_range_query = NULL;
+  range_query *q = set_range_query (fun, saved);
+  gcc_checking_assert (q == &dr);
   return 0;
 }
 
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 831dba9a39ab..337f66d9a794 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -35,6 +35,32 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-range-storage.h"
 #include "target.h"
 
+// Attempt to make Q the current range query for FUN.  If it is already the
+// current range query, return NULL.
+// If the specified query is not compatible with being the current query,
+// instead push the global query for safety.  This is most common when
+// the requested query is a path ranger, and it can be unstable to make
+// arbitrary queries which may be in the middle or after a path.
+
+range_query *
+set_range_query (struct function *fun, range_query *q)
+{
+  // Set the global query if it hasn't been set.
+  if (!fun->x_range_query)
+    fun->x_range_query = get_global_range_query ();
+
+  // If this is not a compatible range query, revert to the global query.
+  if (!q->active_query_compatible_p ())
+    q = get_global_range_query ();
+
+  if (q == fun->x_range_query)
+    return NULL;
+
+  range_query *orig = fun->x_range_query;
+  fun->x_range_query = q;
+  return orig;
+}
+
 // range_query default methods.
 
 bool
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 9932d7d493b2..85f877d94536 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -95,6 +95,8 @@ public:
   void create_gori (int not_executable_flag = 0, int sw_max_edges = INT_MAX);
   void destroy_gori ();
 
+  // Return TRUE if this path query can be a current_range_query.
+  virtual bool active_query_compatible_p () { return true; }
   virtual void dump (FILE *);
 
 protected:
@@ -139,6 +141,10 @@ get_range_query (const struct function *fun)
   return (fun && fun->x_range_query) ? fun->x_range_query : &global_ranges;
 }
 
+// Provide a way to change the current range query if it is valid, return
+// the previous query.
+range_query *set_range_query (struct function *fun, range_query *q);
+
 // Query the global range of NAME in function F.  Default to cfun.
 extern void gimple_range_global (vrange &v, tree name,
                                 struct function *f = cfun);

Reply via email to