From 7159bd0702371a9eea6f8ae6e99a90e247f98c22 Mon Sep 17 00:00:00 2001 From: Christoph Burgdorf Date: Sun, 1 Mar 2026 22:08:00 +0000 Subject: [PATCH] Fix infinite recursion in GVN value-phi computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ValuePhiFinder can enter an infinite recursion cycle through lookup_value_phi_arg → compute_value_phi → compute_value_phi_for_binary → lookup_value_phi_arg when the same GVN instruction query is encountered again during recursive value-phi resolution. Add a `visited_queries` set to ValuePhiFinder that tracks which GVN instructions are currently being resolved on the call stack. If a query is seen a second time, bail out with None to break the cycle. The entry is removed after the recursive call returns (backtracking) so that the same query reached through a different non-cyclic branch is not incorrectly suppressed. --- crates/codegen/src/optim/gvn.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/codegen/src/optim/gvn.rs b/crates/codegen/src/optim/gvn.rs index ef0e851a..27accb76 100644 --- a/crates/codegen/src/optim/gvn.rs +++ b/crates/codegen/src/optim/gvn.rs @@ -1556,15 +1556,22 @@ struct GvnBlock { /// `Detection of Redundant Expressions: A Complete and Polynomial-Time Algorithm in SSA`. struct ValuePhiFinder<'a> { solver: &'a mut GvnSolver, - /// Hold visited values to prevent infinite loop. + /// Hold visited values to prevent infinite loop in `get_phi_of`. visited: FxHashSet, + /// Hold visited queries to prevent infinite recursion in + /// `lookup_value_phi_arg` → `compute_value_phi` cycles. + visited_queries: FxHashSet, } impl<'a> ValuePhiFinder<'a> { fn new(solver: &'a mut GvnSolver, inst_result: ValueId) -> Self { let mut visited = FxHashSet::default(); visited.insert(inst_result); - Self { solver, visited } + Self { + solver, + visited, + visited_queries: FxHashSet::default(), + } } /// Main entry of this struct. @@ -1803,8 +1810,22 @@ impl<'a> ValuePhiFinder<'a> { return Some(ValuePhi::Value(leader)); } + // Break cycle: if we are already computing a value phi for this + // exact query higher up the call stack, bail out to avoid infinite + // recursion through lookup_value_phi_arg → compute_value_phi → + // compute_value_phi_for_binary → lookup_value_phi_arg. + // + // Use backtracking (remove after the call) so that the same query + // reached through a different non-cyclic branch is not incorrectly + // suppressed. + if !self.visited_queries.insert(query.clone()) { + return None; + } + // Try to further compute value phi for the query insn. - self.compute_value_phi(func, &query) + let result = self.compute_value_phi(func, &query); + self.visited_queries.remove(&query); + result } /// Returns the `ValuePhi` if the value is defined by the phi insn or the class of the value