From: Andrew MacLeod Date: Tue, 30 Jun 2026 14:43:07 +0000 (-0400) Subject: Ranger stmt prefill should process dependencies first. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b484690a29147fa190ccb74e0253b2ac89a4ee6d;p=thirdparty%2Fgcc.git Ranger stmt prefill should process dependencies first. Rangers stmt prefill is designed to prevent deep recursion through the normal range_of_stmt/range_of_expr/Range_on_entry cycle when dependencies have not yet been processed. It neglects to do this for PHI arguments and if the order is wrong, it can undo everything it is suppose to solve. Do a proper DFS stack simulation to process all operands properly. PR tree-optimization/125758 gcc/ * gimple-range.cc (gimple_ranger::gimple_ranger): Create prefill stack. (gimple_ranger::gimple_ranger): Dispose of prefill stack. (gimple_ranger::prefill_name): Maybe push name on prefill stack. (gimple_ranger::prefill_stmt_dependencies): Implement a DFS stack for dependency satisfaction. * gimple-range.h (struct prefill_frame): New. (m_prefill_stack): New. (prefill_name): Sadjust parameters. (m_active_prefill): New. --- diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 71e9038467d..37390c5df27 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -51,6 +51,8 @@ gimple_ranger::gimple_ranger (bool use_imm_uses) : m_stmt_list.create (0); m_stmt_list.safe_grow (num_ssa_names); m_stmt_list.truncate (0); + m_prefill_stack.create (0); + m_active_prefill = BITMAP_ALLOC (NULL); // Ensure the not_executable flag is clear everywhere. if (flag_checking) @@ -68,6 +70,8 @@ gimple_ranger::gimple_ranger (bool use_imm_uses) : gimple_ranger::~gimple_ranger () { + BITMAP_FREE (m_active_prefill); + m_prefill_stack.release (); m_stmt_list.release (); } @@ -375,31 +379,46 @@ gimple_ranger::range_of_stmt (vrange &r, gimple *s, tree name) return res; } +// Return true if NAME has not been calculated yet and is pushed onto +// the prefill to be processed. -// Check if NAME is a dependency that needs resolving, and push it on the -// stack if so. R is a scratch range. - -inline void -gimple_ranger::prefill_name (vrange &r, tree name) +inline bool +gimple_ranger::prefill_name (tree name) { if (!gimple_range_ssa_p (name)) - return; + return false; + + unsigned v = SSA_NAME_VERSION (name); + + // Already active cycle. Use seeded value and do not chase it. + if (bitmap_bit_p (m_active_prefill, v)) + return false; + + // Process only range-ops and PHIs. gimple *stmt = SSA_NAME_DEF_STMT (name); if (!gimple_range_op_handler::supported_p (stmt) && !is_a (stmt)) - return; + return false; - // If this op has not been processed yet, then push it on the stack - if (!m_cache.get_global_range (r, name)) - { - bool current; - // Set the global cache value and mark as alway_current. - m_cache.get_global_range (r, name, current); - m_stmt_list.safe_push (name); - } + // Already calculated. + value_range r (TREE_TYPE (name)); + if (m_cache.get_global_range (r, name)) + return false; + + bool current; + // Seed the initial cache value to avoid cycles. + m_cache.get_global_range (r, name, current); + + bitmap_set_bit (m_active_prefill, v); + m_prefill_stack.safe_push ({ name, 0 }); + return true; } -// This routine will seed the global cache with most of the dependencies of -// NAME. This prevents excessive call depth through the normal API. + +// This Prefills the global cache with the dependencies of SSA before it is +// evaluated. Dependencies are traversed iteratively in depth-first order, +// ensuring each operand is calculated and cached before the statement which +// uses it. This avoids deep recursion through the normal range_of_stmt / +// range_of_expr interfaces while preserving the natural dependency ordering. void gimple_ranger::prefill_stmt_dependencies (tree ssa) @@ -407,55 +426,28 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) if (SSA_NAME_IS_DEFAULT_DEF (ssa)) return; - unsigned idx; gimple *stmt = SSA_NAME_DEF_STMT (ssa); gcc_checking_assert (stmt); if (!gimple_bb (stmt)) return; - // Only pre-process range-ops and phis. + // Process only range-ops and PHIs. if (!gimple_range_op_handler::supported_p (stmt) && !is_a (stmt)) return; - // Mark where on the stack we are starting. - unsigned start = m_stmt_list.length (); - m_stmt_list.safe_push (ssa); + unsigned idx = tracer.header ("ROS dependence fill\n"); - idx = tracer.header ("ROS dependence fill\n"); + bitmap_set_bit (m_active_prefill, SSA_NAME_VERSION (ssa)); + m_prefill_stack.safe_push ({ ssa, 0 }); - // Loop until back at the start point. - while (m_stmt_list.length () > start) + while (!m_prefill_stack.is_empty ()) { - tree name = m_stmt_list.last (); - // NULL is a marker which indicates the next name in the stack has now - // been fully resolved, so we can fold it. - if (!name) - { - // Pop the NULL, then pop the name. - m_stmt_list.pop (); - name = m_stmt_list.pop (); - // Don't fold initial request, it will be calculated upon return. - if (m_stmt_list.length () > start) - { - // Fold and save the value for NAME. - stmt = SSA_NAME_DEF_STMT (name); - value_range r (TREE_TYPE (name)); - fold_range_internal (r, stmt, name); - // Make sure we don't lose any current global info. - value_range tmp (TREE_TYPE (name)); - m_cache.get_global_range (tmp, name); - bool changed = tmp.intersect (r); - m_cache.set_global_range (name, tmp, changed); - } - continue; - } - - // Add marker indicating previous NAME in list should be folded - // when we get to this NULL. - m_stmt_list.safe_push (NULL_TREE); + prefill_frame &frame = m_prefill_stack.last (); + tree name = frame.name; stmt = SSA_NAME_DEF_STMT (name); - if (idx) + // Print the ROS (Range Of Stmt) data the first time it is seen. + if (idx && frame.next_op == 0) { tracer.print (idx, "ROS dep fill ("); print_generic_expr (dump_file, name, TDF_SLIM); @@ -463,33 +455,50 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } - gphi *phi = dyn_cast (stmt); - if (phi) + if (gphi *phi = dyn_cast (stmt)) { - value_range r (TREE_TYPE (gimple_phi_result (phi))); - for (unsigned x = 0; x < gimple_phi_num_args (phi); x++) - prefill_name (r, gimple_phi_arg_def (phi, x)); + while (frame.next_op < gimple_phi_num_args (phi)) + { + tree op = gimple_phi_arg_def (phi, frame.next_op++); + if (prefill_name (op)) + break; + } } else { gimple_range_op_handler handler (stmt); - if (handler) + while (handler && frame.next_op < 2) { - tree op = handler.operand2 (); - if (op) - { - value_range r (TREE_TYPE (op)); - prefill_name (r, op); - } - op = handler.operand1 (); - if (op) - { - value_range r (TREE_TYPE (op)); - prefill_name (r, op); - } + tree op = (frame.next_op++ == 0) ? handler.operand2 () + : handler.operand1 (); + if (!op) + continue; + if (prefill_name (op)) + break; } } + + // If the same name is not top of stack, keep processing. + if (m_prefill_stack.last ().name != name) + continue; + + // All dependencies have been handled. Pop and fold. + m_prefill_stack.pop (); + bitmap_clear_bit (m_active_prefill, SSA_NAME_VERSION (name)); + + // Do not fold the original request. The caller will calculate it. + if (name == ssa) + continue; + + value_range r (TREE_TYPE (name)); + fold_range_internal (r, stmt, name); + + value_range tmp (TREE_TYPE (name)); + m_cache.get_global_range (tmp, name); + bool changed = tmp.intersect (r); + m_cache.set_global_range (name, tmp, changed); } + if (idx) { unsupported_range r; @@ -497,7 +506,6 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) } } - // This routine will invoke the gimple fold_stmt routine, providing context to // range_of_expr calls via an private internal API. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index b7df438e369..a74b48aafe6 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -67,12 +67,19 @@ public: range_query &const_query (); protected: bool fold_range_internal (vrange &r, gimple *s, tree name); - void prefill_name (vrange &r, tree name); + struct prefill_frame + { + tree name; + unsigned next_op; + }; + vec m_prefill_stack; + bool prefill_name (tree name); void prefill_stmt_dependencies (tree ssa); ranger_cache m_cache; range_tracer tracer; basic_block current_bb; vec m_stmt_list; + bitmap m_active_prefill; friend class path_range_query; };