STATUS AUDIT (2026-07-23, main at 4d652c2dfa6). The previous body was stale and internally contradictory. The original walker-slot map/filter work is complete. This issue remains open for two independent structural tails:
- pcdep-derived register-allocation compensations that make CPython frame-slot liveness visible to coloring; and
- walker-specific exception-CFG reconstructions in
flatten.rs.
Draft PR #742 optimizes the cost of the first tail, but intentionally does not claim to delete it.
Background
This is a follow-up to #267. The runtime flat slot-pinning resume model has been retired, and later work moved runtime lookup to JitCode-keyed metadata:
The original #371 body continued to describe already-deleted walker machinery and an obsolete PYRE_NO_XSLOT_FILTER reproduction. Those descriptions are removed below.
Completed work
PR #424 and subsequent cleanup retired the mechanisms named in the original title:
filter_cross_slot_coalesce_pairs is deleted.
walker_slot_for_variable, slot_pre_color, same-slot pinning, and the post-walk inputarg seeding are deleted from production code.
- Cross-slot candidate rejection now goes through the RPython
RegAllocator._try_coalesce-equivalent has_edge guard on the pre-renaming graph.
pcdep_canonical_slot + build_slot_disjoint_interference replaced the old walker-slot post-filter as the source of extra slot-identity edges.
The old four kept-stack/short-circuit failures remain useful regression coverage, but they are no longer a reproduction for a live filter:
kept_stack_branch_depths
short_circuit_boxed_int_cross_fn
short_circuit_value_kept_stack
short_circuit_value_local_kept
Current pipeline on main
transform_graph_to_jitcode currently performs the following Ref-bank allocation sequence before canonical flattening:
- Collect CFG
link.args ↔ target.inputargs coalesce candidates on the pre-renaming graph.
- Replay the RPython interference check with
filter_coalesce_pairs_by_interference(..., &[]).
- Build the initial graph coloring.
- Derive canonical CPython slots from
pcdep_slot_var and pcdep_slot_var_resume.
- Build
build_slot_disjoint_interference edges and filter the candidates again.
- Build the accepted-pair value partition with
build_value_parent.
- Build CPython-co-live edges with
build_colive_interference from both pcdep snapshot families.
- Rerun Ref allocation through
perform_register_allocation_all_kinds_with_pairs_and_interference and flatten that coloring.
This is substantially different from the pipeline described in the original issue.
Remaining work A: delete the pcdep-derived regalloc compensation
The remaining adaptation surface is:
pcdep_canonical_slot
build_slot_disjoint_interference
build_value_parent
build_colive_interference
filter_coalesce_pairs_by_interference's external-interference replay
perform_register_allocation_*_with_pairs_and_interference
- the second Ref allocation driven by those extra pairs/edges
Why it is still needed
The old body claimed that moving coalescing after dependency construction would make the separate co-live pass unnecessary. That is no longer accurate.
Current main already applies the upstream has_edge rule on the pre-renaming graph. The remaining problem is that ordinary flowgraph SSA liveness does not express all live Python frame slots:
- fresh Variables are created across local/stack rereads;
- a value can remain live in a Python frame slot across the end of its SSA live range; and
- two distinct slots can occupy disjoint PCs yet still be unsafe to merge into one resume color.
RegAllocator.make_dependencies() therefore cannot see every edge required by color-indexed guard resume. build_colive_interference supplies the missing per-resume-PC edges, while build_slot_disjoint_interference prevents disjoint-PC, distinct-slot coalesces that would extend a color through a box-less region.
RPython-parity direction
Make frame/resume state structurally visible in the graph that the normal RPython allocation pipeline consumes. Once ordinary make_dependencies() observes the correct Variables as live and ordinary coalesce_variables() runs exactly once after it, delete the pcdep-derived slot oracle, value side partition, extra interference plumbing, and second allocation pass.
Do not replace these helpers with another side table. The target shape is the upstream sequence:
make_dependencies()
coalesce_variables()
find_node_coloring()
Draft PR #742 replaces the current naive union-find walk with the existing RPython-style UnionFind and caches dense representatives. This removes a large transform_graph_to_jitcode cost for regex/compiler-sized JitCodes, but the functions remain and this deletion criterion remains open.
Remaining work B: delete walker-specific exception-CFG reconstruction
This tail is independent of the coalescing work and did not fall out when #424 landed.
Live adaptations include:
Link::explicit_raise_value plus carry_explicit_raise_value_on_catch_stack and the single-exit explicit-raise arm in FlattenGraph::insert_exits;
- emitted-stream
block_can_raise detection;
- the
hoisted_tail rewrite that moves vable stores around catch_exception; and
- the release
assert! that enforces -live- / catch_exception adjacency after reconstructing it.
They exist because pyre's walker-built graph does not yet have the same exception shape as RPython flowspace:
- RPython
flowcontext.py::guessexception closes a block at each caught can-raise operation.
- Explicit
raise is represented in the graph/exception links consumed by the standard flattener.
- Pyre can keep later vable-mirror stores in the same block and records an explicit raised value out-of-band on the link, so
flatten.rs reconstructs the bytecode shape after the fact.
RPython-parity direction
Build the exception CFG in the flowspace shape: split at caught can-raise operations and represent explicit raise semantics in the graph itself. Then the ordinary flatten.py::insert_exits port should emit the correct adjacent -live- / catch_exception sequence without scanning emitted instructions, moving a tail, or consulting explicit_raise_value.
#174 is already closed by #551, which promoted the adjacency check from debug_assert! to release assert!. That hardening prevents silent release mis-resume, but it did not remove these structural adaptations; there is no longer a coordinated-closure dependency between #174 and this issue.
Done criteria
Regalloc tail
- The production Ref allocation follows one upstream-shaped dependency/coalesce/color pass.
pcdep_canonical_slot, build_slot_disjoint_interference, build_value_parent, and build_colive_interference are deleted.
- External pair/interference allocation wrappers used only by the splice adaptation are deleted.
- Runtime guard/bridge resume remains unambiguous for every live local/stack slot.
Exception-CFG tail
- Caught can-raise operations have structural flowgraph block boundaries matching
flowcontext.py.
- Explicit raise reaches the standard graph flattener without
Link::explicit_raise_value.
- The emitted-stream
block_can_raise scan and hoisted_tail reconstruction are deleted.
catch_exception adjacency follows from graph structure and standard flattening rather than a repair.
Validation
cargo check --features dynasm
cargo test --features dynasm
- Full
check.py on dynasm and Cranelift, including the kept-stack/short-circuit regressions above and exception/inline-frame synths.
- No Cranelift regression on
fib_recursive, raise_catch, fannkuch, or nbody.
- Byte-exact guard/blackhole resume versus the no-JIT oracle.
— audited and rewritten against current main on 2026-07-23
Background
This is a follow-up to #267. The runtime flat slot-pinning resume model has been retired, and later work moved runtime lookup to JitCode-keyed metadata:
stack_slot_color_mapand the old flat resume readers are gone (JIT: migrate resume-liveness readers from flat stack_slot_color_map to per-PC pcdep (#73) #300/JIT: retire flat stack_slot_color_map kept-stack resume for the vstack mirror + pcdep (#73/#267) #348).pcdep_color_slots,result_color_at_pc, anddepth_at_py_pcare gone (jit: #621 retire the py-indexed VALUE tables (pcdep_color_slots / result_color_at_pc) #627). The codewriter still builds temporary py-indexed vectors while constructing the JitCode-keyedpcdep_trivia_*/ result-color twins; those vectors are not runtime metadata fields.The original #371 body continued to describe already-deleted walker machinery and an obsolete
PYRE_NO_XSLOT_FILTERreproduction. Those descriptions are removed below.Completed work
PR #424 and subsequent cleanup retired the mechanisms named in the original title:
filter_cross_slot_coalesce_pairsis deleted.walker_slot_for_variable,slot_pre_color, same-slot pinning, and the post-walk inputarg seeding are deleted from production code.RegAllocator._try_coalesce-equivalenthas_edgeguard on the pre-renaming graph.pcdep_canonical_slot+build_slot_disjoint_interferencereplaced the old walker-slot post-filter as the source of extra slot-identity edges.The old four kept-stack/short-circuit failures remain useful regression coverage, but they are no longer a reproduction for a live filter:
kept_stack_branch_depthsshort_circuit_boxed_int_cross_fnshort_circuit_value_kept_stackshort_circuit_value_local_keptCurrent pipeline on
maintransform_graph_to_jitcodecurrently performs the following Ref-bank allocation sequence before canonical flattening:link.args ↔ target.inputargscoalesce candidates on the pre-renaming graph.filter_coalesce_pairs_by_interference(..., &[]).pcdep_slot_varandpcdep_slot_var_resume.build_slot_disjoint_interferenceedges and filter the candidates again.build_value_parent.build_colive_interferencefrom both pcdep snapshot families.perform_register_allocation_all_kinds_with_pairs_and_interferenceand flatten that coloring.This is substantially different from the pipeline described in the original issue.
Remaining work A: delete the pcdep-derived regalloc compensation
The remaining adaptation surface is:
pcdep_canonical_slotbuild_slot_disjoint_interferencebuild_value_parentbuild_colive_interferencefilter_coalesce_pairs_by_interference's external-interference replayperform_register_allocation_*_with_pairs_and_interferenceWhy it is still needed
The old body claimed that moving coalescing after dependency construction would make the separate co-live pass unnecessary. That is no longer accurate.
Current
mainalready applies the upstreamhas_edgerule on the pre-renaming graph. The remaining problem is that ordinary flowgraph SSA liveness does not express all live Python frame slots:RegAllocator.make_dependencies()therefore cannot see every edge required by color-indexed guard resume.build_colive_interferencesupplies the missing per-resume-PC edges, whilebuild_slot_disjoint_interferenceprevents disjoint-PC, distinct-slot coalesces that would extend a color through a box-less region.RPython-parity direction
Make frame/resume state structurally visible in the graph that the normal RPython allocation pipeline consumes. Once ordinary
make_dependencies()observes the correct Variables as live and ordinarycoalesce_variables()runs exactly once after it, delete the pcdep-derived slot oracle, value side partition, extra interference plumbing, and second allocation pass.Do not replace these helpers with another side table. The target shape is the upstream sequence:
Draft PR #742 replaces the current naive union-find walk with the existing RPython-style
UnionFindand caches dense representatives. This removes a largetransform_graph_to_jitcodecost for regex/compiler-sized JitCodes, but the functions remain and this deletion criterion remains open.Remaining work B: delete walker-specific exception-CFG reconstruction
This tail is independent of the coalescing work and did not fall out when #424 landed.
Live adaptations include:
Link::explicit_raise_valuepluscarry_explicit_raise_value_on_catch_stackand the single-exit explicit-raise arm inFlattenGraph::insert_exits;block_can_raisedetection;hoisted_tailrewrite that moves vable stores aroundcatch_exception; andassert!that enforces-live-/catch_exceptionadjacency after reconstructing it.They exist because pyre's walker-built graph does not yet have the same exception shape as RPython flowspace:
flowcontext.py::guessexceptioncloses a block at each caught can-raise operation.raiseis represented in the graph/exception links consumed by the standard flattener.flatten.rsreconstructs the bytecode shape after the fact.RPython-parity direction
Build the exception CFG in the flowspace shape: split at caught can-raise operations and represent explicit raise semantics in the graph itself. Then the ordinary
flatten.py::insert_exitsport should emit the correct adjacent-live-/catch_exceptionsequence without scanning emitted instructions, moving a tail, or consultingexplicit_raise_value.#174 is already closed by #551, which promoted the adjacency check from
debug_assert!to releaseassert!. That hardening prevents silent release mis-resume, but it did not remove these structural adaptations; there is no longer a coordinated-closure dependency between #174 and this issue.Done criteria
Regalloc tail
pcdep_canonical_slot,build_slot_disjoint_interference,build_value_parent, andbuild_colive_interferenceare deleted.Exception-CFG tail
flowcontext.py.Link::explicit_raise_value.block_can_raisescan andhoisted_tailreconstruction are deleted.catch_exceptionadjacency follows from graph structure and standard flattening rather than a repair.Validation
cargo check --features dynasmcargo test --features dynasmcheck.pyon dynasm and Cranelift, including the kept-stack/short-circuit regressions above and exception/inline-frame synths.fib_recursive,raise_catch,fannkuch, ornbody.— audited and rewritten against current
mainon 2026-07-23