https://gcc.gnu.org/g:8b34a015640d9ffbd4a32525c5fcc3617a238688

commit r17-4005-g8b34a015640d9ffbd4a32525c5fcc3617a238688
Author: Aldy Hernandez <[email protected]>
Date:   Mon Sep 7 17:28:22 2026 +0000

    backthreader: reuse one path_range_query across candidate paths
    
    find_taken_edge_* built a fresh path_range_query for every candidate
    path, which means a path_oracle allocation, an ssa_lazy_cache setup
    and a heap vec for the path per candidate.  path_range_query already
    has a reset_path method for exactly this, which we're already using in
    DOM's hybrid threader.  Do the same here.
    
    Measured in perf instructions retired over our stage1 .ii corpus, this
    drops back_threader::thread_blocks() by a further 6.7%
    (pass_thread_jumps 7.9%, pass_thread_jumps_full 5.0%,
    pass_early_thread_jumps 5.1%) and the whole compile by a further 0.08%
    over 806 TUs, for 8.8% and 0.10% over the two patches.
    
    Tested on ppc64le Linux.  The assembly is identical over the .ii
    files, so this is a NFC.
    
    gcc/ChangeLog:
    
            * gimple-range-path.cc (path_range_query::reset_path): Splice
            into the existing path vector.
            (path_range_query::compute_ranges): Reset the path oracle
            unconditionally.
            * tree-ssa-threadbackward.cc (back_threader::m_solver): New.
            (back_threader::back_threader): Allocate it.
            (back_threader::~back_threader): Free it.
            (back_threader::find_taken_edge_goto): Use it.
            (back_threader::find_taken_edge_switch): Same.
            (back_threader::find_taken_edge_cond): Same.

Diff:
---
 gcc/gimple-range-path.cc       | 15 +++++++++------
 gcc/tree-ssa-threadbackward.cc | 19 +++++++++++--------
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index 54c8a04b486f..aa60db65f4ff 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -205,7 +205,11 @@ path_range_query::reset_path (const vec<basic_block> &path,
                              const bitmap_head *dependencies)
 {
   gcc_checking_assert (path.length () > 1);
-  m_path = path.copy ();
+
+  // Use truncate/safe_splice instead of copy() to avoid repeated mallocs here.
+  m_path.truncate (0);
+  m_path.safe_splice (path);
+
   m_pos = m_path.length () - 1;
   m_undefined_path = false;
   m_cache.clear ();
@@ -576,11 +580,10 @@ path_range_query::compute_ranges (const bitmap_head 
*dependencies)
   else
     compute_exit_dependencies (m_exit_dependencies);
 
-  if (m_resolve)
-    {
-      path_oracle *p = get_path_oracle ();
-      p->reset_path (&(m_ranger.relation ()));
-    }
+  // The oracle carries state from any previously solved path, so it has
+  // to be reset even in non-resolving mode.
+  path_oracle *p = get_path_oracle ();
+  p->reset_path (&(m_ranger.relation ()));
 
   if (DEBUG_SOLVER)
     {
diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc
index 20bb74c507fd..4173f9c9e8c3 100644
--- a/gcc/tree-ssa-threadbackward.cc
+++ b/gcc/tree-ssa-threadbackward.cc
@@ -135,6 +135,8 @@ private:
   function *m_fun;
   // Ranger for the path solver.
   gimple_ranger *m_ranger;
+  // Path solver, reused across all candidate paths.
+  path_range_query *m_solver;
   unsigned m_flags;
   // Set to TRUE for the first of each thread[12] pass or the first of
   // each threadfull[12] pass.  This is used to differentiate between
@@ -163,10 +165,12 @@ back_threader::back_threader (function *fun, unsigned 
flags, bool first)
     mark_dfs_back_edges ();
 
   m_ranger = new gimple_ranger;
+  m_solver = new path_range_query (*m_ranger, flags & BT_RESOLVE);
 }
 
 back_threader::~back_threader ()
 {
+  delete m_solver;
   delete m_ranger;
   loop_optimizer_finalize ();
 }
@@ -300,9 +304,8 @@ back_threader::find_taken_edge_goto (const vec<basic_block> 
&path,
   if (TREE_CODE (dest) == SSA_NAME)
     {
       prange r;
-      path_range_query solver (*m_ranger, path, m_imports,
-                              m_flags & BT_RESOLVE);
-      if (!solver.range_of_expr (r, dest, stmt))
+      m_solver->reset_path (path, m_imports);
+      if (!m_solver->range_of_expr (r, dest, stmt))
        return NULL;
 
       if (r.undefined_p ())
@@ -328,8 +331,8 @@ back_threader::find_taken_edge_switch (const 
vec<basic_block> &path,
   tree name = gimple_switch_index (sw);
   int_range_max r;
 
-  path_range_query solver (*m_ranger, path, m_imports, m_flags & BT_RESOLVE);
-  solver.range_of_expr (r, name, sw);
+  m_solver->reset_path (path, m_imports);
+  m_solver->range_of_expr (r, name, sw);
 
   if (r.undefined_p ())
     return UNREACHABLE_EDGE;
@@ -352,10 +355,10 @@ back_threader::find_taken_edge_cond (const 
vec<basic_block> &path,
 {
   int_range_max r;
 
-  path_range_query solver (*m_ranger, path, m_imports, m_flags & BT_RESOLVE);
-  solver.range_of_stmt (r, cond);
+  m_solver->reset_path (path, m_imports);
+  m_solver->range_of_stmt (r, cond);
 
-  if (solver.unreachable_path_p ())
+  if (m_solver->unreachable_path_p ())
     return UNREACHABLE_EDGE;
 
   int_range<2> true_range = range_true ();

Reply via email to