Scope-specific executable coroutine transitions
Status: isolated candidate built; 81/81 host XIR/coroutine tests pass. The full original renderer module passes the actual production normalization boundary under both frozen baseline and candidate libraries. Device integration is pending. No renderer frame reduction or performance result is claimed here. The predicate-retirement follow-up also passes the expanded host suite and the same complete original module, without widening. Actual renderer integration and device gates remain pending.
Root cause and immutable red evidence
At SDK 98f4667ca678a3a1425ff4467e0d7803a0a0d12e, distillation walks both
successors of each raw conditional branch separately from the latest
continuation’s incoming state. A six-block, Phi-free raw XIR reproducer has
search=true at entry, yields A when true, assigns search=false after A,
and yields B when false. The original verifier accepts it, but distillation
reports all four edges entry -> A/B and A -> A/B instead of the two
executable edges entry -> A and A -> B. There are no structured Loop/If
operands in this counterexample.
The original host-only reduction and DSL controls are archived outside the
worktree at /var/tmp/psycles-holdout-CXlJR7/coro-transition-predicate-reduction.
The frozen baseline ran 5 test cases / 46 assertions, with 10 failed precision
assertions. It did not execute a shader or render a scene.
Artifact |
SHA-256 |
|---|---|
Frozen reduction source |
|
Frozen baseline executable |
|
Baseline log |
|
The source and binary hashes above identify the immutable first reduction; the permanent regression adds adversarial controls and is a different file.
Abstract semantics
The forward May state is (latest resume owner, executable block, possible Boolean valuations). It reuses CoroBooleanSetManager and predicate liveness.
Boolean slots and SSA snapshots are different predicates. A direct store
strongly updates its private slot; a load defines a new snapshot; repeated
execution replaces the old dynamic instance of an SSA definition. Unsupported
Boolean producers forget their prior value. Constant, Boolean copy, NOT,
AND/OR/XOR and Boolean equality transfers are exact within this domain.
Only exact scalar local allocations with no address escape are tracked. GEPs, casts, ordinary reference calls and unsupported uses disqualify a slot globally. A callee’s lack of a MUST-write is never used as a no-MAY-write proof. Every writable Extension binding invalidates its tracked slot at the actual suspension, for boundary, queued and resumed lifetimes alike. A prior SSA load is not invalidated by a later external memory write. An ordinary branch into a resume changes owner without inventing Extension effects.
Incoming states join by union. A conditional successor is selected only after the monotone fixed point has seen exactly one possible arm for that owner. Dead predicates are existentially projected; ROBDD budget exhaustion widens toward unknown. Both operations can retain extra paths but cannot remove a concrete execution. Unknown IndexedBranch/call-return selectors retain all raw successors. Existing matched-call analysis remains conservative and is not filtered by another owner’s certificate.
Compiler integration boundary
The chosen successor is sealed with each scope and the immutable source CFG. Scope discovery, cross-scope transition discovery, local May/Must liveness, and split operand dominance consume this same relation. Split emits a branch to the sole executable successor and does not resolve the discarded target: resolving it could synthesize an unwanted token store or fallback return. This is not a graph-only edge deletion or a renderer-specific stage rule.
A surviving ordinary transfer into a resume remains legal even when its matching static suspend was proved unreachable. Split validates the incoming sealed transition instead of requiring a reached suspend for every owner. Only executable suspensions contribute mandatory designated frame snapshots; global input validation still checks every source export declaration.
LUISA_CORO_DUMP_FRAME_LAYOUT=1 reports reachability state count, widening,
selected-arm count, and the full feasible token relation before frame liveness
and coloring. Current-ABI original-module capture, final graph and frame layout
have been checked below; candidate renderer execution remains an integration gate.
Permanent regression and pending gates
test_coro_transition_predicates covers the original raw witness, dynamic
entry/resume controls, real self edges, conditional reference writes, all three
writable Extension lifetimes, preserved SSA snapshots, late diamond joins,
re-executed Boolean definitions, ordinary resume entry, shared suspending
callables, and full DSL mandatory-yield / terminated-background patterns.
Raw cases split and verify the actual module and compare emitted continuation
token stores against the certified transition set. A tampered arm certificate
must be rejected.
Executed in the isolated SDK root with matching rebuilt libraries:
cmake --build build --parallel 32 --target test_coro_transition_predicates
ctest --test-dir build -R '^test_coro_transition_predicates$' -V
ctest --test-dir build -L 'unit_xir|unit_coro' --parallel 32 --output-on-failure
All 79 selected executable targets were built with --parallel 32 before the
full test command. Focused result: 11 tests / 161 assertions pass. Full result:
79/79 pass. Logs in the archived reduction directory are
candidate-focused-2.log and candidate-host-ctest-2.log; build logs and first
failed runs are also retained. The first focused follow-up exposed mandatory
collection of a dead export; its new assertion was preserved and the semantic
collection fixed. Four older distill tests used constant true while requiring
the false branch; their inputs now use genuine Boolean arguments, preserving
all prior bypass/export-rejection, greatest-fixed-point, transition-store and
shared-merge assertions.
Next validate the integrated renderer on HIP, fallback, and strict native XIR-to-SPIR-V Vulkan. Do not load a pre-change distill observer into this changed Scope ABI. No GPU gate has run for this candidate yet.
Complete original module: production-boundary replay
The fresh current-ABI observer links only the frozen production libraries.
Its complete original Barbershop parent module is archived under
/var/tmp/psycles-holdout-CXlJR7/coro-distill-current-BsxSjd/barbershop-large-egmbFh.
The module has 1,111,095 instructions and SHA-256
3e62bd7b664d5deb3bb1afb122b20bf7c23c08d6762fc461eccfbe9de1131568.
The diagnostic original render terminated 0. A temporary bounded transport
budget increase was required; the capture directory documents that isolated
writer/reader change and the frozen earlier serializer-limit failure.
Both matching-ABI replayers process that same complete input and preserve exact serialization across read-only distillation. They split all six continuations, materialize, detach the owned source, run cross-block reg2mem, and verify the complete module at the production boundary. Both terminate 0. Actual emitted nonterminal token-store sets equal the certified transitions for every stage.
Static compiler result |
Frozen baseline |
Isolated candidate |
|---|---|---|
Final graph boundaries |
17 |
12 |
Incoming surface boundaries |
6 |
2 (closest and volume) |
Total frame fields / AoS bytes |
92 / 416 |
92 / 416 |
Payload slots / logical values |
85 / 93 |
85 / 93 |
Normalized module instructions |
1,115,843 |
1,114,333 |
Production verifier errors |
0 |
0 |
The first replay checked raw post-split SSA too early. Frozen baseline has 276 and candidate 156 intermediate dominance diagnostics; both have zero after the production reg2mem boundary. These intermediate diagnostics are not evidence of a candidate execution regression and were not patched individually.
Some static field masks shrink despite unchanged allocation: background target live fields 73 -> 18; forward-light 81 -> 74; closest-to-background source stores 9 -> 2; volume-to-background 47 -> 15. These are compiler metadata counts, not measured bandwidth or renderer speedups. Candidate analysis still reports ROBDD widening (2,937 states / 44 selected arms), so generic intra-block predicate retirement is being reduced independently before any follow-up implementation.
Replay evidence is in ../replay/ relative to the capture directory above:
barbershop-baseline-production.log and barbershop-candidate-production.log.
Their SHA-256 hashes are respectively
db6479a26091aeeebd5acc585ffe9da0a90d3f89492344a54c00e6f601e9991d and
5a8c2698f14e5dfbbb3e23c7220f9dae55081b1ec31005a5201e7c3c914116c4.
Independent follow-up: retiring dead intra-block predicates
An independent raw XIR block snapshots n Boolean arguments through private slots, then inverts and stores each result into a distinct reference-array element. Every result is observable. With all early snapshot variables ordered before all late result variables, retaining their dead equalities admits 2^n distinct cofactors. A known-true gate after the chain exposes the precision loss when the existing finite ROBDD budget widens. This is a compiler-domain issue, not a renderer-specific instruction-count threshold.
test_coro_transition_predicate_retirement was built with 32 threads against the
unchanged preceding candidate and failed as expected: three cases / 56 assertions,
five failed precision requirements. n=3/8 preserve the constant gate without
widening; n=24 widens and retains a false edge. The dynamic n=24 control retains
both real edges and fails only the no-widening requirement. A genuinely later-used
snapshot relation also loses precision at n=24. All split, verifier and observable
output-store checks pass. Source, binary, logs and six matching libraries are
frozen under the reduction archive’s pre-retirement-eJ6IeP/, manifest
RETIREMENT_RED_SHA256SUMS; RED log SHA-256 is
bb8863aa2c85f649d5a019c47c6ba079b7c5d755e7f4cceb51d9666a0cfb4706.
The follow-up adds sparse deaths to the existing Boolean liveness
helper: DEAD[i] = (USE[i] union DEF[i]) - LIVE_AFTER[i], computed before killing
definitions, including never-used definitions. The forward analysis applies
existential projection after each nonterminator transfer. Terminator conditions
remain until outgoing states are refined. The backward fixed point still uses
every raw semantic successor, including loop and resume edges. Projection
distributes over May union; re-executed definitions still replace old instances.
Aliases, writable Extensions, unsupported producers and shared-call matching
retain their existing conservative handling. The budget and transfer functions
are unchanged. This family has a linear live relation frontier after retirement;
no polynomial claim is made for arbitrary genuinely live Boolean relations.
The unchanged retirement source and executable now pass all 3 cases / 56 assertions against the rebuilt compiler library. Every n=24 chain reports no widening, known/retained-snapshot gates have one edge, and dynamic gates retain both edges. Direct private-API controls cover overlapping USE=DEF with a live result, never-used definitions, and liveness through a raw false successor: 3 cases / 14 assertions pass. The original transition suite remains 11 / 161. All 81 host XIR/coroutine targets were built with 32 threads and pass CTest.
Logs are retirement-green-focused.log and retirement-green-host-ctest.log in
the reduction archive; full source/library/test hashes are in
retirement-green.sha256. The focused log SHA-256 is
df7062dfc716c5fd7e0eb7643742413e494739052e5e45da26b072ca296c4817;
full host log is f23648de2e28a95723b596c9e8c4449c44676855cf9f98b1747ad065c9646412.
The unchanged 1,111,095-instruction complete module was then replayed sequentially with the frozen pre-retirement libraries and the post-retirement candidate. Both terminate 0, preserve exact source serialization, and verify normalized output with zero errors. Every stage’s actual token stores match its certificate. Retirement removes widening (true -> false), reduces analysis states 2,937 -> 2,882 and increases selected arms 44 -> 99. The surface scope contains 2,614 instead of 2,669 blocks. Normalized instructions decrease 1,114,333 -> 1,114,278. Both final graphs have six nodes / 12 boundaries, both frames have 92 fields / 416 AoS bytes, and all printed stage/edge field masks are identical. This extra retirement step therefore has no demonstrated frame-capacity or field-mask gain.
These correctness replays overlapped another validation job. Their distill
durations (2.85892 s before, 2.00719 s after) are overlapping-load diagnostics,
not controlled timing, full-JIT measurements or renderer performance claims.
Logs in the full capture archive’s replay/ directory are
barbershop-pre-retirement-overlap.log (SHA-256
090d28c1a5355dda7a31e6529ea1cea84f7f0c835d1fa03d5ca5c58622d772ed)
and barbershop-post-retirement-overlap.log (SHA-256
465f5191f8bd2d7b8bbc5e87379fe3eab17a59db4546c3e988d0f7e646fb49ca).