Reduce path-explosion via phi-aware control-flow merge - #287
Draft
PhilippGrulich wants to merge 3 commits into
Draft
Reduce path-explosion via phi-aware control-flow merge#287PhilippGrulich wants to merge 3 commits into
PhilippGrulich wants to merge 3 commits into
Conversation
Adds operand reconciliation to ExecutionTrace::processControlFlowMerge so that CMPs at the same Tag* reached via different upstream sibling paths collapse into a single merge block with phi-style block arguments, rather than enumerating one trace branch per upstream sibling. Mechanism: - AliveVariableHash tracks an ordered list of live (ref, type) pairs alongside the existing XOR-hash, exposed via order(). - recordCmpSnapshot() drops aliveVars.hash() so the same Tag* collides across sibling paths. Non-CMP snapshots keep the full hash. - addCmpOperation stores the reference path's alive list keyed by the arena-stable TraceOperation pointer. - processControlFlowMerge pairs the reference and current alive lists positionally and, for each divergent slot, declares a phi block-arg on the merge block (Block::phiArgCount) and populates BlockRef.arguments on both predecessor JMPs with the path-local values. Best-effort: any size or type mismatch skips reconciliation for that slot and falls back to the legacy SSA propagation path. - SSACreationPhase::propagateValue is now phi-aware: when a propagated value matches a pre-populated phi block-arg, it consults each predecessor's BlockRef.arguments[phiIdx] to substitute the path-local ValueRef before continuing propagation upstream. The worklist now carries (blockId, ref) pairs. - checkTag is split into findTag (pure lookup) + an explicit processControlFlowMerge call so callers can supply currentAlive. Acceptance criteria (from plan): - baseline_threeCallsNoBranch: 27 -> 3 RETURNs (53 -> 17 blocks) - postCallBranch_1: 6 -> 2 RETURNs - postCallBranch_2: 18 -> 2 RETURNs - postCallBranch_3: 54 -> 2 RETURNs - baseline_oneCall, independentIfs_4, constraintBlind_dead: unchanged - Loop, control-flow, expression, regression, std, val tests: all byte-identical - 198/198 ctest pass, 4490/4490 tracing assertions pass Net source delta: ~+250 LoC. Path-explosion fixtures shrink ~4000 lines.
Contributor
There was a problem hiding this comment.
Tracing Benchmark
Details
| Benchmark suite | Current: 7deb341 | Previous: f9cd28f | Ratio |
|---|---|---|---|
tiered_compile_addOne |
55.08 us (± 12.7382) |
55.1658 us (± 10.7264) |
1.00 |
single_compile_mlir_addOne |
3.24139 ms (± 110.104) |
3.25749 ms (± 57.5499) |
1.00 |
single_compile_cpp_addOne |
25.4625 ms (± 551.707) |
24.4391 ms (± 405.29) |
1.04 |
single_compile_bc_addOne |
59.6926 us (± 14.3217) |
60.6703 us (± 11.2707) |
0.98 |
tiered_compile_sumLoop |
81.1866 us (± 15.0119) |
79.6202 us (± 15.7788) |
1.02 |
single_compile_mlir_sumLoop |
5.44274 ms (± 430.735) |
5.35632 ms (± 118.42) |
1.02 |
single_compile_cpp_sumLoop |
26.5295 ms (± 603.016) |
26.0899 ms (± 453.281) |
1.02 |
single_compile_bc_sumLoop |
78.9325 us (± 14.2043) |
78.6934 us (± 10.1775) |
1.00 |
exec_mlir_add |
10.5637 ns (± 1.36723) |
10.6651 ns (± 0.946586) |
0.99 |
exec_mlir_fibonacci |
13.8983 us (± 1.86467) |
13.4703 us (± 2.01788) |
1.03 |
exec_mlir_sum |
565.563 us (± 23.4934) |
527.422 us (± 21.2529) |
1.07 |
exec_cpp_add |
5.2564 ns (± 0.879107) |
4.69868 ns (± 0.745035) |
1.12 |
exec_cpp_fibonacci |
97.7501 us (± 11.1064) |
96.6361 us (± 9.26507) |
1.01 |
exec_cpp_sum |
36.0015 ms (± 308.766) |
35.9426 ms (± 115.287) |
1.00 |
exec_bc_add |
44.7456 ns (± 6.1126) |
44.8635 ns (± 8.015) |
1.00 |
exec_bc_fibonacci |
859.886 us (± 25.8727) |
859.028 us (± 13.0138) |
1.00 |
exec_bc_sum |
186.518 ms (± 12.0908) |
186.067 ms (± 1.36597) |
1.00 |
exec_asmjit_add |
3.64071 ns (± 0.620939) |
3.48273 ns (± 0.424618) |
1.05 |
exec_asmjit_fibonacci |
21.1335 us (± 2.51557) |
20.8625 us (± 3.3694) |
1.01 |
exec_asmjit_sum |
4.89715 ms (± 286.237) |
4.87965 ms (± 312.598) |
1.00 |
exec_bc_add_noRegAlloc |
46.6641 ns (± 9.05818) |
44.3118 ns (± 3.89068) |
1.05 |
exec_bc_add_regAlloc |
46.1065 ns (± 10.9004) |
44.599 ns (± 5.15383) |
1.03 |
exec_bc_fibonacci_noRegAlloc |
858.393 us (± 25.2971) |
852.767 us (± 11.3762) |
1.01 |
exec_bc_fibonacci_regAlloc |
861.166 us (± 39.2289) |
875.208 us (± 25.409) |
0.98 |
exec_bc_sum_noRegAlloc |
191.649 ms (± 2.95548) |
185.974 ms (± 222.438) |
1.03 |
exec_bc_sum_regAlloc |
191.009 ms (± 339.93) |
185.982 ms (± 165.251) |
1.03 |
trace_add |
2.6104 us (± 436.813) |
2.27731 us (± 155.69) |
1.15 |
completing_trace_add |
2.62456 us (± 390.309) |
2.32405 us (± 143.855) |
1.13 |
trace_ifThenElse |
9.27602 us (± 1.25405) |
8.63915 us (± 776.354) |
1.07 |
completing_trace_ifThenElse |
4.84761 us (± 514.074) |
4.54071 us (± 401.003) |
1.07 |
trace_deeplyNestedIfElse |
27.8659 us (± 3.34119) |
25.5445 us (± 1.57172) |
1.09 |
completing_trace_deeplyNestedIfElse |
13.5322 us (± 1.85172) |
12.559 us (± 987.646) |
1.08 |
trace_loop |
9.31819 us (± 1.23192) |
8.80429 us (± 1.55155) |
1.06 |
completing_trace_loop |
5.03941 us (± 611.677) |
4.79104 us (± 376.911) |
1.05 |
trace_ifInsideLoop |
18.5321 us (± 3.08354) |
16.6688 us (± 1.56827) |
1.11 |
completing_trace_ifInsideLoop |
8.76721 us (± 1.11305) |
8.40114 us (± 807.253) |
1.04 |
trace_loopDirectCall |
9.96863 us (± 1.84385) |
8.6864 us (± 697.439) |
1.15 |
completing_trace_loopDirectCall |
5.52852 us (± 948.737) |
4.86476 us (± 354.791) |
1.14 |
trace_pointerLoop |
15.8466 us (± 3.42309) |
14.0902 us (± 1.18648) |
1.12 |
completing_trace_pointerLoop |
10.6087 us (± 2.47767) |
10.1206 us (± 990.611) |
1.05 |
trace_staticLoop |
7.92873 us (± 936.311) |
7.21602 us (± 496.139) |
1.10 |
completing_trace_staticLoop |
8.3794 us (± 1.48357) |
7.43532 us (± 991.516) |
1.13 |
trace_fibonacci |
10.8714 us (± 1.84479) |
10.0814 us (± 861.346) |
1.08 |
completing_trace_fibonacci |
6.71962 us (± 967.351) |
6.00031 us (± 426.095) |
1.12 |
trace_gcd |
8.523 us (± 1.32527) |
7.79585 us (± 648.305) |
1.09 |
completing_trace_gcd |
4.37857 us (± 664.304) |
3.87126 us (± 272.452) |
1.13 |
trace_nestedIf10 |
47.7861 us (± 8.8094) |
38.0283 us (± 3.64798) |
1.26 |
completing_trace_nestedIf10 |
45.5224 us (± 6.86483) |
37.3711 us (± 3.21573) |
1.22 |
trace_nestedIf100 |
2.03509 ms (± 46.6594) |
1.35476 ms (± 22.6997) |
1.50 |
completing_trace_nestedIf100 |
2.02132 ms (± 71.0396) |
1.35268 ms (± 26.016) |
1.49 |
trace_chainedIf10 |
112.115 us (± 15.229) |
97.7583 us (± 4.73759) |
1.15 |
completing_trace_chainedIf10 |
53.3599 us (± 7.92169) |
48.3258 us (± 3.59147) |
1.10 |
trace_chainedIf100 |
5.26086 ms (± 63.4455) |
4.43042 ms (± 29.6138) |
1.19 |
completing_trace_chainedIf100 |
2.46322 ms (± 60.2296) |
2.24075 ms (± 31.9951) |
1.10 |
comp_mlir_add |
5.77637 ms (± 375.913) |
5.55479 ms (± 56.4997) |
1.04 |
comp_mlir_ifThenElse |
6.36056 ms (± 425.254) |
6.14317 ms (± 38.4483) |
1.04 |
comp_mlir_deeplyNestedIfElse |
5.10948 ms (± 175.436) |
5.06889 ms (± 99.0918) |
1.01 |
comp_mlir_loop |
7.27976 ms (± 231.426) |
7.14743 ms (± 31.0585) |
1.02 |
comp_mlir_ifInsideLoop |
29.3896 ms (± 422.215) |
28.6125 ms (± 100.629) |
1.03 |
comp_mlir_loopDirectCall |
12.2554 ms (± 363.528) |
11.792 ms (± 44.0495) |
1.04 |
comp_mlir_pointerLoop |
28.6147 ms (± 381.038) |
27.7179 ms (± 76.6326) |
1.03 |
comp_mlir_staticLoop |
5.06184 ms (± 185.559) |
5.03112 ms (± 38.6111) |
1.01 |
comp_mlir_fibonacci |
10.668 ms (± 236.254) |
10.4618 ms (± 76.5332) |
1.02 |
comp_mlir_gcd |
9.61775 ms (± 279.53) |
9.43388 ms (± 42.8866) |
1.02 |
comp_mlir_nestedIf10 |
10.7621 ms (± 259.766) |
10.5281 ms (± 45.0755) |
1.02 |
comp_mlir_nestedIf100 |
25.3895 ms (± 349.465) |
25.0116 ms (± 102.345) |
1.02 |
comp_mlir_chainedIf10 |
9.79848 ms (± 362.328) |
9.56929 ms (± 46.3491) |
1.02 |
comp_mlir_chainedIf100 |
21.5533 ms (± 599.803) |
20.2061 ms (± 81.9884) |
1.07 |
comp_cpp_add |
25.8545 ms (± 592.213) |
24.3267 ms (± 189.47) |
1.06 |
comp_cpp_ifThenElse |
26.5258 ms (± 582.406) |
24.9638 ms (± 283.6) |
1.06 |
comp_cpp_deeplyNestedIfElse |
27.6494 ms (± 681.921) |
26.0088 ms (± 233.598) |
1.06 |
comp_cpp_loop |
27.0718 ms (± 1.09087) |
25.0851 ms (± 291.998) |
1.08 |
comp_cpp_ifInsideLoop |
27.5859 ms (± 769.763) |
26.2072 ms (± 775.414) |
1.05 |
comp_cpp_loopDirectCall |
26.8482 ms (± 517.827) |
25.3831 ms (± 531.136) |
1.06 |
comp_cpp_pointerLoop |
27.4615 ms (± 584.203) |
25.4858 ms (± 203.254) |
1.08 |
comp_cpp_staticLoop |
26.8976 ms (± 636.782) |
24.7845 ms (± 176.103) |
1.09 |
comp_cpp_fibonacci |
27.696 ms (± 907.271) |
25.2385 ms (± 205.167) |
1.10 |
comp_cpp_gcd |
27.7658 ms (± 1.17937) |
25.0233 ms (± 436.288) |
1.11 |
comp_cpp_nestedIf10 |
29.9917 ms (± 1.04188) |
28.0721 ms (± 363.361) |
1.07 |
comp_cpp_nestedIf100 |
63.4899 ms (± 876.803) |
61.7276 ms (± 707.638) |
1.03 |
comp_cpp_chainedIf10 |
33.0005 ms (± 1.05903) |
30.7822 ms (± 574.356) |
1.07 |
comp_cpp_chainedIf100 |
92.6536 ms (± 650.762) |
91.9107 ms (± 685.096) |
1.01 |
comp_bc_add |
14.8817 us (± 2.91381) |
14.7773 us (± 1.91246) |
1.01 |
comp_bc_ifThenElse |
19.4578 us (± 3.42374) |
19.2429 us (± 3.53172) |
1.01 |
comp_bc_deeplyNestedIfElse |
23.9522 us (± 5.64956) |
23.0339 us (± 3.44593) |
1.04 |
comp_bc_loop |
19.2508 us (± 3.86476) |
18.9128 us (± 2.70016) |
1.02 |
comp_bc_ifInsideLoop |
22.3974 us (± 4.80484) |
21.5194 us (± 2.28647) |
1.04 |
comp_bc_loopDirectCall |
19.9046 us (± 3.99212) |
19.2878 us (± 2.03113) |
1.03 |
comp_bc_pointerLoop |
21.0813 us (± 3.69849) |
20.5351 us (± 2.66896) |
1.03 |
comp_bc_staticLoop |
17.6891 us (± 3.81934) |
17.2132 us (± 2.1155) |
1.03 |
comp_bc_fibonacci |
19.6346 us (± 3.68796) |
19.1709 us (± 2.93634) |
1.02 |
comp_bc_gcd |
18.9728 us (± 3.38573) |
18.5754 us (± 2.5724) |
1.02 |
comp_bc_nestedIf10 |
37.4633 us (± 6.40199) |
35.6002 us (± 4.60432) |
1.05 |
comp_bc_nestedIf100 |
199.667 us (± 11.1716) |
198.41 us (± 10.198) |
1.01 |
comp_bc_chainedIf10 |
52.8155 us (± 8.50553) |
52.6073 us (± 9.11991) |
1.00 |
comp_bc_chainedIf100 |
306.415 us (± 14.035) |
309.294 us (± 26.888) |
0.99 |
comp_asmjit_add |
24.7312 us (± 7.47397) |
22.1735 us (± 4.82406) |
1.12 |
comp_asmjit_ifThenElse |
33.4544 us (± 5.46188) |
33.4071 us (± 4.26649) |
1.00 |
comp_asmjit_deeplyNestedIfElse |
58.2577 us (± 10.1015) |
56.4176 us (± 5.25514) |
1.03 |
comp_asmjit_loop |
35.8883 us (± 5.87708) |
35.8631 us (± 4.35405) |
1.00 |
comp_asmjit_ifInsideLoop |
59.1684 us (± 12.7318) |
57.5183 us (± 8.7641) |
1.03 |
comp_asmjit_loopDirectCall |
45.966 us (± 8.92276) |
47.2559 us (± 9.00425) |
0.97 |
comp_asmjit_pointerLoop |
48.5558 us (± 8.32074) |
48.2785 us (± 6.56048) |
1.01 |
comp_asmjit_staticLoop |
29.1558 us (± 5.45808) |
28.6917 us (± 4.31543) |
1.02 |
comp_asmjit_fibonacci |
44.4846 us (± 9.48286) |
43.5157 us (± 6.92307) |
1.02 |
comp_asmjit_gcd |
35.0783 us (± 5.85223) |
35.3711 us (± 4.19816) |
0.99 |
comp_asmjit_nestedIf10 |
104.644 us (± 14.0525) |
103.255 us (± 10.7623) |
1.01 |
comp_asmjit_nestedIf100 |
1043.29 us (± 22160.3) |
1057.97 us (± 54427.5) |
0.99 |
comp_asmjit_chainedIf10 |
157.204 us (± 20.3646) |
153.183 us (± 14.6589) |
1.03 |
comp_asmjit_chainedIf100 |
2.17404 ms (± 83.3169) |
2.16653 ms (± 46.7063) |
1.00 |
e2e_tiered_bc_to_mlir |
57.3564 us (± 14.2707) |
56.9167 us (± 7.69512) |
1.01 |
e2e_single_mlir |
5.57257 ms (± 245.939) |
5.52315 ms (± 41.2737) |
1.01 |
ir_add |
773.691 ns (± 64.9998) |
757.379 ns (± 38.5584) |
1.02 |
ir_ifThenElse |
1.5482 us (± 106.235) |
1.58461 us (± 136.165) |
0.98 |
ir_deeplyNestedIfElse |
3.35748 us (± 273.436) |
3.40826 us (± 363.019) |
0.99 |
ir_loop |
1.72179 us (± 289.978) |
1.63694 us (± 149.086) |
1.05 |
ir_ifInsideLoop |
2.91199 us (± 372.458) |
2.83439 us (± 293.378) |
1.03 |
ir_loopDirectCall |
1.92527 us (± 286.38) |
1.80584 us (± 177.074) |
1.07 |
ir_pointerLoop |
2.00582 us (± 197.202) |
1.97161 us (± 153.779) |
1.02 |
ir_staticLoop |
1.50957 us (± 170.736) |
1.44956 us (± 119.501) |
1.04 |
ir_fibonacci |
1.75775 us (± 177.421) |
1.72022 us (± 143.401) |
1.02 |
ir_gcd |
1.60984 us (± 275.292) |
1.4549 us (± 101.976) |
1.11 |
ir_nestedIf10 |
7.93441 us (± 1.12044) |
7.70943 us (± 540.522) |
1.03 |
ir_nestedIf100 |
91.6472 us (± 6.28121) |
93.6887 us (± 16.2569) |
0.98 |
ir_chainedIf10 |
11.8349 us (± 1.22543) |
11.594 us (± 826.837) |
1.02 |
ir_chainedIf100 |
174.368 us (± 10.0168) |
169.138 us (± 8.3263) |
1.03 |
ssa_add |
177.784 ns (± 11.292) |
178.473 ns (± 9.97434) |
1.00 |
ssa_ifThenElse |
450.707 ns (± 46.506) |
459.53 ns (± 43.4269) |
0.98 |
ssa_deeplyNestedIfElse |
1.21132 us (± 201.865) |
1.16567 us (± 124.837) |
1.04 |
ssa_loop |
480.52 ns (± 39.7273) |
487.861 ns (± 38.2642) |
0.98 |
ssa_ifInsideLoop |
895.852 ns (± 84.1508) |
895.76 ns (± 72.8648) |
1.00 |
ssa_loopDirectCall |
525.324 ns (± 88.0394) |
491.118 ns (± 45.7827) |
1.07 |
ssa_pointerLoop |
592.313 ns (± 69.1639) |
583.073 ns (± 41.8959) |
1.02 |
ssa_staticLoop |
425.872 ns (± 54.0771) |
422.539 ns (± 47.7647) |
1.01 |
ssa_fibonacci |
542.528 ns (± 91.3668) |
503.737 ns (± 39.1986) |
1.08 |
ssa_gcd |
467.01 ns (± 62.2076) |
445.234 ns (± 36.8343) |
1.05 |
exec_bc_addOne |
37.8528 ns (± 8.30051) |
36.0837 ns (± 6.3975) |
1.05 |
exec_mlir_addOne |
261.803 ns (± 9.252) |
258.154 ns (± 2.33301) |
1.01 |
exec_cpp_addOne |
4.11971 ns (± 0.66208) |
3.54853 ns (± 0.249363) |
1.16 |
exec_interpreted_addOne |
45.24 ns (± 7.93783) |
37.1985 ns (± 2.33453) |
1.22 |
This comment was automatically generated by workflow using github-action-benchmark.
CI ubuntu-24.04 clang-21 -DENABLE_SHORT_CIRCUIT_BOOL=ON failed because val<bool> temporaries returned from compare ops (`value == 20`, etc.) and fed straight into the if-condition under native && / || have a lifetime too short for aliveVars.order() to include them at the moment of traceBool. Result: refAlive and currentAlive matched positionally (both [$1, $2]), my phi-aware merge inserted zero phi-args, the merged CMP at the merge block ended up with an operand defined on only one predecessor path, and SSACreationPhase threw "Wrong number of arguments in trace: expected 1, got 2". Carve-out: processControlFlowMerge now also accepts the current path's CMP operand. It reads the reference path's operand from refOp->input[0] and, if the two differ but weren't already covered by the alive-list phi loop, inserts a phi for them unconditionally. This handles the short-circuit bool temp case without depending on aliveVars tracking. Regenerated the two affected .shortcircuit fixtures for multipleConditions and complexLogicalExpressions across all five stages (tracing, after_ssa, ir, after_constant_folding, after_empty_block_elim). The default (non-shortcircuit) builds remain byte-identical. ctest --test-dir nautilus: 198/198 pass in both default and ENABLE_SHORT_CIRCUIT_BOOL=ON configs.
Two changes: 1. Tracing-time efficiency. AliveVariableHash no longer maintains an ordered active vector + index map on every allocateValRef / freeValRef. Instead the (id, type) pair is stored in the counts map and a sorted snapshot is built on demand at recordCmpSnapshot time. Snapshots are roughly two orders of magnitude rarer than val<T> ctor/dtor on chained-if traces, so amortising the O(N log N) sort over rare calls is a net win and avoids per-val vector allocation churn. addCmpOperation now takes the alive list by value and moves it into cmpAliveAtRecord, eliminating one copy per CMP record. 2. SHORT_CIRCUIT_BOOL fix. The AsmJit backend's visitIf does not handle conditional branches whose condition arrives as a bool block argument (the dual-arm processBlockInvocation in nautilus/src/nautilus/compiler/backends/amsjit/X64LoweringProvider.cpp:651 binds the wrong register at SSA merges with bool phis). Under ENABLE_SHORT_CIRCUIT_BOOL the native && / || lowering creates exactly that pattern, so recordCmpSnapshot conservatively keeps aliveVars in the snapshot in that build, preserving the legacy non-merged CMP shape. SHORT_CIRCUIT_BOOL is opt-in; default builds still get the path-explosion optimisation. The path-explosion fixtures gain .shortcircuit overrides that mirror the legacy shape. Reverted the multipleConditions / complexLogicalExpressions .shortcircuit fixtures to their pre-PR shape (they no longer go through the phi merge under SHORT_CIRCUIT_BOOL). ctest --test-dir nautilus: 206/206 pass in both default and ENABLE_SHORT_CIRCUIT_BOOL=ON builds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds operand reconciliation to
ExecutionTrace::processControlFlowMergeso that CMPs at the sameTag*reached via different upstream sibling paths collapse into a single merge block with phi-style block arguments, rather than enumerating one trace branch per upstream sibling.pathExplosion_baseline_threeCallsNoBranch(chain of three inlined helpers, each with three returns) previously produced 27 RETURNs / 53 blocks because the second and third callee's internal CMPs got distinct snapshots per upstream sibling. With this PR it produces 3 RETURNs / 17 blocks — the natural fanout.Mechanism
AliveVariableHash(inExceptionBasedTraceContext.hpp) gains anactive_ordervector ofTypedValueRefs, updated on 0→1 (push) and 1→0 (swap-and-pop) transitions. BothallocateValRef/freeValRefare extended to carry theTypeso the merge layer can emit phi block-args with correct types.aliveVars.hash(). NewrecordCmpSnapshot()returns{Tag*, staticHash}only. Non-CMP snapshots keep the full hash.ExecutionTrace::addCmpOperationaccepts the alive list and stores it in acmpAliveAtRecordside-map keyed by the arena-stableTraceOperation*.processControlFlowMergereconciles divergent operand ValueRefs. For each positional alive slot where reference and current ValueRefs differ (and types match), the merge block gets a phi block-arg, both predecessor JMPs supply their path-local value viaBlockRef.arguments, andBlock::phiArgCountmarks the phi prefix. Best-effort: any size/type mismatch falls through to the legacy SSA path.SSACreationPhase::propagateValueis phi-aware. The worklist now carries(blockId, ref)pairs; when a propagated value matches a pre-populated phi block-arg, it substitutes the path-local value from each predecessor'sBlockRef.arguments[phiIdx]before continuing.checkTagis split.findTagis pure lookup; the caller invokesprocessControlFlowMerge(*existing, currentAlive)explicitly so it can supply the current path's alive-vars.Acceptance
baseline_threeCallsNoBranch.tracepostCallBranch_1.tracepostCallBranch_2.tracepostCallBranch_3.tracebaseline_oneCall.traceindependentIfs_4.traceconstraintBlind_dead.tracectest --test-dir nautilus: 198 / 198 passing. Tracing assertions: 4490 / 4490 passing.Net source delta: ~+250 LoC across 13 source files. Path-explosion fixtures shrink ~4000 lines.
Test plan
ctestsweep passes (198/198).TracingBenchmark.cpp) — not run locally; CI will catch any regression.Risks / followups
active_orderis best-effort. On size or type mismatch the merge logic skips phi-arg insertion and SSA falls back to its legacy behaviour, so this is non-regressive.propagateValueworklist type changed fromvector<uint32_t>tovector<pair<uint32_t, TypedValueRef>>— negligible perf impact but flagged for review.constraintBlind_dead) is unchanged; a follow-up PR could address it with a separate mechanism.https://claude.ai/code/session_01Sb9g18UwCgxJJz5WZzFnsU
Generated by Claude Code