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);
