Skip to content

fix(compiler): prevent phi crashes in EVM SSA stack-lift path - #530

Merged
zoowii merged 3 commits into
DTVMStack:mainfrom
abmcar:fix/evm-ssa-lift-phi-crashes
Jun 10, 2026
Merged

fix(compiler): prevent phi crashes in EVM SSA stack-lift path#530
zoowii merged 3 commits into
DTVMStack:mainfrom
abmcar:fix/evm-ssa-lift-phi-crashes

Conversation

@abmcar

@abmcar abmcar commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

What

Fixes three independent defects in the EVM multipass JIT's SSA stack-lift
path (ZEN_ENABLE_EVM_STACK_SSA_LIFT, default OFF, from #395 / #493).
With the flag ON, the JIT emitted invalid MIR that the verifier rejects and
that aborts the compiler (SIGABRT) on common control flow (loops,
dynamic-jump targets). All edits are reachable only when a block is lifted,
so the default flag-off build is unaffected.

The three bugs

  1. Phi contiguitycreatePendingPhi appended phis at the block end, so a
    multi-slot stack merge interleaved a later slot's phis after an earlier
    slot's temp-store dassigns, breaking the "phis contiguous at block start"
    invariant. Fix: insert each phi after the block's leading phi run.

  2. Dynamic-jump-target phi undersize — codegen's indirect-jump dispatch
    wires an edge from every computed-JUMP block to every JUMPDEST, but the
    analyzer's shape-class predecessor enumeration (which sizes a merge block's
    phis) is a strict subset, so such blocks got phis smaller than their real
    predecessor count → downstream out-of-bounds SIGABRT. Fix: a
    predecessor-coverage check in finalizeLiftability excludes these blocks
    from lifting (they fall back to the memory-backed stack path).

  3. Loop back-edge phi incoming block — a loop header's merge phi froze its
    back-edge incoming block before the JUMPI terminator wired the real CFG
    edge, recording the source block's entry MIR BB instead of the actual
    predecessor. Fix: re-resolve incoming blocks once the full CFG exists, at
    the end of finalizeEVMBase (value preserved; only the block pointer fixed).

Validation

Suite Result
Default path (flag OFF) multipass evmone-unittests 223/223
Default path (flag OFF) multipass evmone-statetest -k fork_Cancun (EEST) 2723/2723
Lift path (flag ON) multipass evmone-unittests 223/223 (was 222/223; memory_grow_mstore8 now passes)
Lift path (flag ON) 228-fixture mainnet-replay corpus compiles crash-free, verifier-clean (was SIGABRT)
tools/format.sh check passes

The default-path numbers were produced from this branch rebuilt with the flag
off; they confirm the change is a no-op for the shipping configuration.

Known limitation (disclosed)

This does not make SSA stack-lifting production-ready, and the flag stays
OFF. With the flag ON, at least one further crash remains:
stEIP1153_transientStorage/transStorageOK (EEST) still aborts under SSA-lift
(confirmed in isolation; passes with the flag off). That defect is independent
of the three fixed here and will be addressed separately. CI does not build
with ZEN_ENABLE_EVM_STACK_SSA_LIFT=ON, so it does not exercise this path; the
lift-path results above were produced manually.

These are latent correctness/robustness fixes in merged code, worthwhile on
their own merits independent of when the feature is eventually enabled.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 9, 2026 12:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes multiple verifier/abort crashes in the EVM SSA stack-lift path by ensuring phi placement/incomings match MIR invariants and codegen CFG wiring.

Changes:

  • Insert newly created phis contiguously at the start of a block to satisfy MIR verifier constraints.
  • Re-resolve stack-merge phi incoming blocks after CFG construction to correctly handle loop back-edges.
  • Prevent stack-lifting for dynamic-jump-target blocks when the analyzer’s predecessor enumeration can’t cover codegen’s dispatch edges; adds change documentation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/compiler/evm_frontend/evm_mir_compiler.h Adds bookkeeping + API to finalize stack-merge phi incoming blocks post-CFG-build.
src/compiler/evm_frontend/evm_mir_compiler.cpp Fixes phi insertion position; adds post-finalization fix-up to re-resolve incoming blocks for stack-merge phis.
src/compiler/evm_frontend/evm_analyzer.h Adds analysis to conservatively disable lifting for dynamic-jump targets when predecessor modeling mismatches codegen edges.
docs/changes/2026-06-09-evm-ssa-lift-phi-crashes/README.md Documents the three fixed crash causes, approach, and validation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/compiler/evm_frontend/evm_mir_compiler.cpp Outdated
Comment thread src/compiler/evm_frontend/evm_mir_compiler.cpp Outdated
Comment thread src/compiler/evm_frontend/evm_mir_compiler.cpp Outdated
Comment thread src/compiler/evm_frontend/evm_analyzer.h
Comment thread src/compiler/evm_frontend/evm_analyzer.h
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

⚡ Performance Regression Check Results

✅ Performance Check Passed (interpreter)

Performance Benchmark Results (threshold: 25%)

Benchmark Baseline (us) Current (us) Change Status
total/main/blake2b_huff/8415nulls 3.70 3.71 +0.3% PASS
total/main/blake2b_huff/empty 0.06 0.06 +1.6% PASS
total/main/blake2b_shifts/8415nulls 20.83 21.06 +1.1% PASS
total/main/sha1_divs/5311 11.94 12.16 +1.9% PASS
total/main/sha1_divs/empty 0.15 0.15 +1.2% PASS
total/main/sha1_shifts/5311 9.22 8.71 -5.5% PASS
total/main/sha1_shifts/empty 0.08 0.08 +1.8% PASS
total/main/snailtracer/benchmark 109.96 110.73 +0.7% PASS
total/main/structarray_alloc/nfts_rank 1.38 1.38 -0.0% PASS
total/main/swap_math/insufficient_liquidity 0.00 0.00 +1.2% PASS
total/main/swap_math/received 0.01 0.01 -1.1% PASS
total/main/swap_math/spent 0.01 0.01 +1.1% PASS
total/main/weierstrudel/1 0.40 0.39 -0.8% PASS
total/main/weierstrudel/15 4.36 4.40 +0.9% PASS
total/micro/JUMPDEST_n0/empty 2.86 2.86 -0.0% PASS
total/micro/jump_around/empty 0.11 0.11 +0.6% PASS
total/micro/loop_with_many_jumpdests/empty 65.01 64.90 -0.2% PASS
total/micro/memory_grow_mload/by1 0.23 0.23 +0.0% PASS
total/micro/memory_grow_mload/by16 0.25 0.25 -0.8% PASS
total/micro/memory_grow_mload/by32 0.15 0.15 -0.2% PASS
total/micro/memory_grow_mload/nogrow 0.11 0.12 +3.0% PASS
total/micro/memory_grow_mstore/by1 0.24 0.24 +2.9% PASS
total/micro/memory_grow_mstore/by16 0.14 0.14 -0.2% PASS
total/micro/memory_grow_mstore/by32 0.28 0.28 -1.2% PASS
total/micro/memory_grow_mstore/nogrow 0.23 0.24 +1.6% PASS
total/micro/signextend/one 0.28 0.28 -0.1% PASS
total/micro/signextend/zero 0.48 0.48 -0.2% PASS
total/synth/ADD/b0 3.23 3.22 -0.2% PASS
total/synth/ADD/b1 6.11 5.66 -7.4% PASS
total/synth/ADDRESS/a0 6.70 6.85 +2.3% PASS
total/synth/ADDRESS/a1 5.17 5.36 +3.7% PASS
total/synth/AND/b0 2.87 2.86 -0.0% PASS
total/synth/AND/b1 5.22 5.18 -0.8% PASS
total/synth/BYTE/b0 6.05 6.06 +0.0% PASS
total/synth/BYTE/b1 8.79 8.49 -3.2% PASS
total/synth/CALLDATASIZE/a0 5.42 5.57 +2.8% PASS
total/synth/CALLDATASIZE/a1 3.69 3.69 -0.1% PASS
total/synth/CALLER/a0 6.71 6.67 -0.7% PASS
total/synth/CALLER/a1 6.78 6.67 -1.7% PASS
total/synth/CALLVALUE/a0 3.60 3.56 -1.0% PASS
total/synth/CALLVALUE/a1 6.22 6.57 +5.6% PASS
total/synth/CODESIZE/a0 6.76 6.73 -0.5% PASS
total/synth/CODESIZE/a1 6.36 6.46 +1.7% PASS
total/synth/DUP1/d0 2.00 1.97 -1.8% PASS
total/synth/DUP1/d1 2.13 2.04 -4.3% PASS
total/synth/DUP10/d0 2.02 2.05 +1.8% PASS
total/synth/DUP10/d1 2.30 2.06 -10.1% PASS
total/synth/DUP11/d0 1.12 1.23 +9.3% PASS
total/synth/DUP11/d1 2.13 2.10 -1.7% PASS
total/synth/DUP12/d0 2.03 2.01 -1.2% PASS
total/synth/DUP12/d1 1.65 1.66 +0.2% PASS
total/synth/DUP13/d0 1.96 2.00 +1.8% PASS
total/synth/DUP13/d1 2.21 2.17 -1.9% PASS
total/synth/DUP14/d0 1.23 1.23 -0.0% PASS
total/synth/DUP14/d1 2.09 2.07 -1.3% PASS
total/synth/DUP15/d0 1.99 2.00 +0.3% PASS
total/synth/DUP15/d1 1.45 1.65 +14.1% PASS
total/synth/DUP16/d0 1.99 2.00 +0.9% PASS
total/synth/DUP16/d1 2.10 2.08 -0.8% PASS
total/synth/DUP2/d0 1.23 1.10 -10.5% PASS
total/synth/DUP2/d1 2.02 2.09 +3.7% PASS
total/synth/DUP3/d0 1.97 1.96 -0.4% PASS
total/synth/DUP3/d1 1.51 1.65 +9.2% PASS
total/synth/DUP4/d0 2.04 2.01 -1.6% PASS
total/synth/DUP4/d1 2.21 2.16 -2.6% PASS
total/synth/DUP5/d0 1.23 1.11 -9.6% PASS
total/synth/DUP5/d1 2.16 2.12 -1.5% PASS
total/synth/DUP6/d0 1.96 2.01 +2.6% PASS
total/synth/DUP6/d1 1.45 1.65 +14.0% PASS
total/synth/DUP7/d0 1.98 2.02 +2.2% PASS
total/synth/DUP7/d1 2.09 2.36 +13.1% PASS
total/synth/DUP8/d0 1.23 1.23 -0.0% PASS
total/synth/DUP8/d1 2.09 2.14 +2.7% PASS
total/synth/DUP9/d0 1.94 2.07 +6.7% PASS
total/synth/DUP9/d1 1.45 1.45 -0.3% PASS
total/synth/EQ/b0 6.09 6.19 +1.6% PASS
total/synth/EQ/b1 6.33 6.35 +0.3% PASS
total/synth/GAS/a0 3.95 3.93 -0.3% PASS
total/synth/GAS/a1 7.53 7.39 -1.8% PASS
total/synth/GT/b0 6.54 6.32 -3.4% PASS
total/synth/GT/b1 6.57 6.54 -0.5% PASS
total/synth/ISZERO/u0 10.18 10.14 -0.3% PASS
total/synth/JUMPDEST/n0 2.86 2.81 -1.9% PASS
total/synth/LT/b0 6.27 6.32 +0.7% PASS
total/synth/LT/b1 5.45 5.43 -0.4% PASS
total/synth/MSIZE/a0 5.94 6.04 +1.5% PASS
total/synth/MSIZE/a1 6.21 6.22 +0.3% PASS
total/synth/MUL/b0 7.65 7.64 -0.1% PASS
total/synth/MUL/b1 5.92 5.92 +0.0% PASS
total/synth/NOT/u0 7.84 8.14 +3.9% PASS
total/synth/OR/b0 5.16 4.97 -3.6% PASS
total/synth/OR/b1 3.67 3.69 +0.5% PASS
total/synth/PC/a0 5.54 5.57 +0.6% PASS
total/synth/PC/a1 3.47 3.45 -0.6% PASS
total/synth/PUSH1/p0 2.25 2.25 +0.1% PASS
total/synth/PUSH1/p1 1.54 1.74 +13.2% PASS
total/synth/PUSH10/p0 2.20 2.24 +1.8% PASS
total/synth/PUSH10/p1 1.55 1.68 +8.7% PASS
total/synth/PUSH11/p0 2.24 2.21 -1.5% PASS
total/synth/PUSH11/p1 2.32 2.47 +6.6% PASS
total/synth/PUSH12/p0 1.32 1.32 +0.2% PASS
total/synth/PUSH12/p1 2.47 2.63 +6.3% PASS
total/synth/PUSH13/p0 2.33 2.28 -1.9% PASS
total/synth/PUSH13/p1 1.55 1.75 +12.7% PASS
total/synth/PUSH14/p0 2.30 2.29 -0.5% PASS
total/synth/PUSH14/p1 2.56 2.45 -4.2% PASS
total/synth/PUSH15/p0 1.32 1.32 -0.2% PASS
total/synth/PUSH15/p1 2.47 2.66 +7.8% PASS
total/synth/PUSH16/p0 2.47 2.59 +4.9% PASS
total/synth/PUSH16/p1 1.55 1.75 +12.4% PASS
total/synth/PUSH17/p0 2.29 2.22 -3.3% PASS
total/synth/PUSH17/p1 2.40 2.36 -1.6% PASS
total/synth/PUSH18/p0 1.32 1.32 +0.3% PASS
total/synth/PUSH18/p1 2.51 2.34 -7.0% PASS
total/synth/PUSH19/p0 2.21 2.30 +3.6% PASS
total/synth/PUSH19/p1 1.61 1.78 +11.1% PASS
total/synth/PUSH2/p0 2.24 2.39 +6.5% PASS
total/synth/PUSH2/p1 2.47 2.39 -3.2% PASS
total/synth/PUSH20/p0 2.62 2.29 -12.6% PASS
total/synth/PUSH20/p1 2.36 2.46 +4.2% PASS
total/synth/PUSH21/p0 1.33 1.33 +0.4% PASS
total/synth/PUSH21/p1 2.39 2.41 +0.8% PASS
total/synth/PUSH22/p0 2.21 2.22 +0.6% PASS
total/synth/PUSH22/p1 1.67 1.54 -8.0% PASS
total/synth/PUSH23/p0 2.77 2.28 -17.7% PASS
total/synth/PUSH23/p1 2.52 2.38 -5.3% PASS
total/synth/PUSH24/p0 1.33 1.31 -0.9% PASS
total/synth/PUSH24/p1 2.44 2.51 +2.8% PASS
total/synth/PUSH25/p0 2.19 2.36 +7.6% PASS
total/synth/PUSH25/p1 1.55 1.71 +10.2% PASS
total/synth/PUSH26/p0 2.86 2.20 -22.9% PASS
total/synth/PUSH26/p1 2.39 2.47 +3.7% PASS
total/synth/PUSH27/p0 1.32 1.32 -0.2% PASS
total/synth/PUSH27/p1 2.49 2.43 -2.7% PASS
total/synth/PUSH28/p0 2.32 2.36 +2.0% PASS
total/synth/PUSH28/p1 1.55 1.57 +1.3% PASS
total/synth/PUSH29/p0 2.31 2.22 -4.0% PASS
total/synth/PUSH29/p1 2.39 2.43 +1.7% PASS
total/synth/PUSH3/p0 1.32 1.32 +0.2% PASS
total/synth/PUSH3/p1 2.31 2.31 -0.1% PASS
total/synth/PUSH30/p0 1.47 1.48 +0.4% PASS
total/synth/PUSH30/p1 2.43 2.43 +0.0% PASS
total/synth/PUSH31/p0 2.34 2.37 +1.2% PASS
total/synth/PUSH31/p1 1.71 1.89 +10.0% PASS
total/synth/PUSH32/p0 2.54 2.27 -10.7% PASS
total/synth/PUSH32/p1 2.50 2.24 -10.1% PASS
total/synth/PUSH4/p0 2.30 2.20 -4.6% PASS
total/synth/PUSH4/p1 1.54 1.55 +0.7% PASS
total/synth/PUSH5/p0 2.28 2.32 +1.8% PASS
total/synth/PUSH5/p1 2.42 2.39 -1.3% PASS
total/synth/PUSH6/p0 1.32 1.40 +6.2% PASS
total/synth/PUSH6/p1 2.61 2.59 -0.6% PASS
total/synth/PUSH7/p0 2.49 2.24 -10.1% PASS
total/synth/PUSH7/p1 1.59 1.78 +11.9% PASS
total/synth/PUSH8/p0 2.30 2.42 +5.2% PASS
total/synth/PUSH8/p1 2.58 2.38 -7.8% PASS
total/synth/PUSH9/p0 1.33 1.33 +0.1% PASS
total/synth/PUSH9/p1 2.40 2.40 -0.0% PASS
total/synth/RETURNDATASIZE/a0 3.51 3.54 +0.6% PASS
total/synth/RETURNDATASIZE/a1 6.41 6.51 +1.5% PASS
total/synth/SAR/b0 3.93 3.93 -0.0% PASS
total/synth/SAR/b1 7.60 7.61 +0.0% PASS
total/synth/SGT/b0 5.73 5.66 -1.3% PASS
total/synth/SGT/b1 4.14 4.14 +0.1% PASS
total/synth/SHL/b0 7.23 7.05 -2.6% PASS
total/synth/SHL/b1 3.81 3.85 +1.0% PASS
total/synth/SHR/b0 7.07 7.02 -0.7% PASS
total/synth/SHR/b1 6.34 6.60 +4.1% PASS
total/synth/SIGNEXTEND/b0 3.36 3.41 +1.5% PASS
total/synth/SIGNEXTEND/b1 6.58 6.66 +1.2% PASS
total/synth/SLT/b0 4.29 4.30 +0.3% PASS
total/synth/SLT/b1 5.58 5.63 +0.9% PASS
total/synth/SUB/b0 5.60 6.03 +7.7% PASS
total/synth/SUB/b1 5.78 5.92 +2.4% PASS
total/synth/SWAP1/s0 3.52 3.52 +0.0% PASS
total/synth/SWAP10/s0 3.54 3.54 +0.0% PASS
total/synth/SWAP11/s0 3.42 3.53 +3.3% PASS
total/synth/SWAP12/s0 3.49 3.51 +0.6% PASS
total/synth/SWAP13/s0 3.54 3.53 -0.0% PASS
total/synth/SWAP14/s0 3.53 3.43 -2.7% PASS
total/synth/SWAP15/s0 3.58 3.68 +2.6% PASS
total/synth/SWAP16/s0 3.56 3.65 +2.8% PASS
total/synth/SWAP2/s0 3.43 3.46 +0.9% PASS
total/synth/SWAP3/s0 3.42 3.43 +0.4% PASS
total/synth/SWAP4/s0 3.53 3.53 +0.0% PASS
total/synth/SWAP5/s0 3.52 3.48 -0.3% PASS
total/synth/SWAP6/s0 3.52 3.42 -2.8% PASS
total/synth/SWAP7/s0 3.53 3.53 +0.1% PASS
total/synth/SWAP8/s0 3.47 3.56 +2.7% PASS
total/synth/SWAP9/s0 3.44 3.55 +3.0% PASS
total/synth/XOR/b0 5.19 5.01 -3.2% PASS
total/synth/XOR/b1 5.37 5.17 -3.7% PASS
total/synth/loop_v1 12.06 12.68 +5.2% PASS
total/synth/loop_v2 12.57 11.90 -5.3% PASS

Summary: 194 benchmarks, 0 regressions


✅ Performance Check Passed (multipass)

Performance Benchmark Results (threshold: 25%)

Benchmark Baseline (us) Current (us) Change Status
total/main/blake2b_huff/8415nulls 2.29 2.31 +0.6% PASS
total/main/blake2b_huff/empty 0.04 0.04 +1.0% PASS
total/main/blake2b_shifts/8415nulls 21.61 20.82 -3.6% PASS
total/main/sha1_divs/5311 11.73 11.60 -1.1% PASS
total/main/sha1_divs/empty 0.14 0.14 -0.2% PASS
total/main/sha1_shifts/5311 9.15 8.63 -5.7% PASS
total/main/sha1_shifts/empty 0.08 0.08 -1.7% PASS
total/main/snailtracer/benchmark 105.56 106.38 +0.8% PASS
total/main/structarray_alloc/nfts_rank 1.46 1.42 -2.2% PASS
total/main/swap_math/insufficient_liquidity 0.00 0.00 -1.4% PASS
total/main/swap_math/received 0.01 0.01 +3.6% PASS
total/main/swap_math/spent 0.01 0.01 +0.2% PASS
total/main/weierstrudel/1 0.39 0.39 -0.7% PASS
total/main/weierstrudel/15 4.31 4.23 -1.7% PASS
total/micro/JUMPDEST_n0/empty 0.00 0.00 -1.8% PASS
total/micro/jump_around/empty 0.08 0.07 -8.4% PASS
total/micro/loop_with_many_jumpdests/empty 0.01 0.01 -1.4% PASS
total/micro/memory_grow_mload/by1 0.02 0.02 -5.0% PASS
total/micro/memory_grow_mload/by16 0.02 0.02 +3.6% PASS
total/micro/memory_grow_mload/by32 0.01 0.01 +0.5% PASS
total/micro/memory_grow_mload/nogrow 0.01 0.01 +2.4% PASS
total/micro/memory_grow_mstore/by1 0.02 0.02 -2.8% PASS
total/micro/memory_grow_mstore/by16 0.01 0.01 +1.1% PASS
total/micro/memory_grow_mstore/by32 0.03 0.03 +3.0% PASS
total/micro/memory_grow_mstore/nogrow 0.02 0.02 -3.6% PASS
total/micro/signextend/one 0.08 0.08 -1.7% PASS
total/micro/signextend/zero 0.19 0.19 -0.2% PASS
total/synth/ADD/b0 0.00 0.00 -1.5% PASS
total/synth/ADD/b1 0.00 0.00 -0.7% PASS
total/synth/ADDRESS/a0 0.23 0.23 +0.3% PASS
total/synth/ADDRESS/a1 0.15 0.15 +0.1% PASS
total/synth/AND/b0 0.00 0.00 -1.1% PASS
total/synth/AND/b1 0.00 0.00 +0.2% PASS
total/synth/BYTE/b0 0.00 0.00 -1.7% PASS
total/synth/BYTE/b1 0.00 0.00 +0.4% PASS
total/synth/CALLDATASIZE/a0 0.13 0.12 -7.6% PASS
total/synth/CALLDATASIZE/a1 0.07 0.07 -0.0% PASS
total/synth/CALLER/a0 0.22 0.25 +10.8% PASS
total/synth/CALLER/a1 0.22 0.23 +4.4% PASS
total/synth/CALLVALUE/a0 0.19 0.19 +0.3% PASS
total/synth/CALLVALUE/a1 0.28 0.29 +2.4% PASS
total/synth/CODESIZE/a0 0.13 0.12 -4.7% PASS
total/synth/CODESIZE/a1 0.12 0.12 +3.6% PASS
total/synth/DUP1/d0 0.00 0.00 -0.9% PASS
total/synth/DUP1/d1 0.00 0.00 +0.3% PASS
total/synth/DUP10/d0 0.00 0.00 -0.3% PASS
total/synth/DUP10/d1 0.00 0.00 -0.0% PASS
total/synth/DUP11/d0 0.00 0.00 -1.5% PASS
total/synth/DUP11/d1 0.00 0.00 -0.8% PASS
total/synth/DUP12/d0 0.00 0.00 +0.7% PASS
total/synth/DUP12/d1 0.00 0.00 -1.5% PASS
total/synth/DUP13/d0 0.00 0.00 -0.4% PASS
total/synth/DUP13/d1 0.00 0.00 -0.5% PASS
total/synth/DUP14/d0 0.00 0.00 -2.9% PASS
total/synth/DUP14/d1 0.00 0.00 -0.7% PASS
total/synth/DUP15/d0 0.00 0.00 -0.0% PASS
total/synth/DUP15/d1 0.00 0.00 -2.0% PASS
total/synth/DUP16/d0 0.00 0.00 -0.8% PASS
total/synth/DUP16/d1 0.00 0.00 +1.7% PASS
total/synth/DUP2/d0 0.00 0.00 -1.7% PASS
total/synth/DUP2/d1 0.00 0.00 -2.8% PASS
total/synth/DUP3/d0 0.00 0.00 -0.1% PASS
total/synth/DUP3/d1 0.00 0.00 -1.9% PASS
total/synth/DUP4/d0 0.00 0.00 -0.5% PASS
total/synth/DUP4/d1 0.00 0.00 +0.1% PASS
total/synth/DUP5/d0 0.00 0.00 -1.4% PASS
total/synth/DUP5/d1 0.00 0.00 -1.1% PASS
total/synth/DUP6/d0 0.00 0.00 -0.2% PASS
total/synth/DUP6/d1 0.00 0.00 -1.3% PASS
total/synth/DUP7/d0 0.00 0.00 -1.0% PASS
total/synth/DUP7/d1 0.00 0.00 -1.2% PASS
total/synth/DUP8/d0 0.00 0.00 -3.1% PASS
total/synth/DUP8/d1 0.00 0.00 +0.6% PASS
total/synth/DUP9/d0 0.00 0.00 -0.8% PASS
total/synth/DUP9/d1 0.00 0.00 -1.3% PASS
total/synth/EQ/b0 0.00 0.00 -1.0% PASS
total/synth/EQ/b1 0.00 0.00 +0.5% PASS
total/synth/GAS/a0 0.76 0.76 +0.1% PASS
total/synth/GAS/a1 0.92 0.92 -0.2% PASS
total/synth/GT/b0 0.00 0.00 -0.5% PASS
total/synth/GT/b1 0.00 0.00 -0.8% PASS
total/synth/ISZERO/u0 0.00 0.00 -0.1% PASS
total/synth/JUMPDEST/n0 0.00 0.00 -1.4% PASS
total/synth/LT/b0 0.00 0.00 -0.3% PASS
total/synth/LT/b1 0.00 0.00 -1.6% PASS
total/synth/MSIZE/a0 0.00 0.00 -0.2% PASS
total/synth/MSIZE/a1 0.00 0.00 -0.3% PASS
total/synth/MUL/b0 0.00 0.00 -0.3% PASS
total/synth/MUL/b1 0.00 0.00 -1.7% PASS
total/synth/NOT/u0 0.00 0.00 +0.1% PASS
total/synth/OR/b0 0.00 0.00 +0.4% PASS
total/synth/OR/b1 0.00 0.00 -1.4% PASS
total/synth/PC/a0 0.00 0.00 -0.0% PASS
total/synth/PC/a1 0.00 0.00 -1.5% PASS
total/synth/PUSH1/p0 0.00 0.00 -0.3% PASS
total/synth/PUSH1/p1 0.00 0.00 -1.5% PASS
total/synth/PUSH10/p0 0.00 0.00 +3.8% PASS
total/synth/PUSH10/p1 0.00 0.00 -1.1% PASS
total/synth/PUSH11/p0 0.00 0.00 -3.2% PASS
total/synth/PUSH11/p1 0.00 0.00 +2.2% PASS
total/synth/PUSH12/p0 0.00 0.00 -2.4% PASS
total/synth/PUSH12/p1 0.00 0.00 +7.1% PASS
total/synth/PUSH13/p0 0.00 0.00 +1.4% PASS
total/synth/PUSH13/p1 0.00 0.00 -1.8% PASS
total/synth/PUSH14/p0 0.00 0.00 -1.0% PASS
total/synth/PUSH14/p1 0.00 0.00 +2.5% PASS
total/synth/PUSH15/p0 0.00 0.00 +0.2% PASS
total/synth/PUSH15/p1 0.00 0.00 +1.0% PASS
total/synth/PUSH16/p0 0.00 0.00 +4.5% PASS
total/synth/PUSH16/p1 0.00 0.00 -2.2% PASS
total/synth/PUSH17/p0 0.00 0.00 -1.5% PASS
total/synth/PUSH17/p1 0.00 0.00 -1.5% PASS
total/synth/PUSH18/p0 0.00 0.00 -1.4% PASS
total/synth/PUSH18/p1 0.00 0.00 -4.3% PASS
total/synth/PUSH19/p0 0.00 0.00 -2.0% PASS
total/synth/PUSH19/p1 0.00 0.00 -1.3% PASS
total/synth/PUSH2/p0 0.00 0.00 +0.3% PASS
total/synth/PUSH2/p1 0.00 0.00 +2.2% PASS
total/synth/PUSH20/p0 0.00 0.00 +2.2% PASS
total/synth/PUSH20/p1 0.00 0.00 +1.3% PASS
total/synth/PUSH21/p0 0.00 0.00 -2.0% PASS
total/synth/PUSH21/p1 0.00 0.00 +4.7% PASS
total/synth/PUSH22/p0 2.20 2.12 -3.9% PASS
total/synth/PUSH22/p1 1.57 1.57 +0.1% PASS
total/synth/PUSH23/p0 2.12 2.27 +6.9% PASS
total/synth/PUSH23/p1 2.31 2.22 -3.7% PASS
total/synth/PUSH24/p0 1.32 1.32 -0.3% PASS
total/synth/PUSH24/p1 2.23 2.23 +0.2% PASS
total/synth/PUSH25/p0 2.12 2.18 +2.6% PASS
total/synth/PUSH25/p1 1.55 1.60 +3.7% PASS
total/synth/PUSH26/p0 2.12 2.13 +0.6% PASS
total/synth/PUSH26/p1 2.15 2.30 +7.1% PASS
total/synth/PUSH27/p0 1.32 1.32 -0.3% PASS
total/synth/PUSH27/p1 2.22 2.32 +4.2% PASS
total/synth/PUSH28/p0 2.14 2.14 +0.0% PASS
total/synth/PUSH28/p1 1.58 1.57 -0.5% PASS
total/synth/PUSH29/p0 2.14 2.12 -0.9% PASS
total/synth/PUSH29/p1 2.33 2.28 -2.0% PASS
total/synth/PUSH3/p0 0.00 0.00 -1.6% PASS
total/synth/PUSH3/p1 0.00 0.00 +0.7% PASS
total/synth/PUSH30/p0 1.48 1.49 +1.2% PASS
total/synth/PUSH30/p1 2.23 2.28 +2.0% PASS
total/synth/PUSH31/p0 2.12 2.14 +0.9% PASS
total/synth/PUSH31/p1 1.73 1.79 +3.4% PASS
total/synth/PUSH32/p0 2.24 2.15 -4.1% PASS
total/synth/PUSH32/p1 2.27 2.33 +3.0% PASS
total/synth/PUSH4/p0 0.00 0.00 -0.9% PASS
total/synth/PUSH4/p1 0.00 0.00 -1.5% PASS
total/synth/PUSH5/p0 0.00 0.00 +1.8% PASS
total/synth/PUSH5/p1 0.00 0.00 +3.9% PASS
total/synth/PUSH6/p0 0.00 0.00 -2.6% PASS
total/synth/PUSH6/p1 0.00 0.00 -0.8% PASS
total/synth/PUSH7/p0 0.00 0.00 +0.2% PASS
total/synth/PUSH7/p1 0.00 0.00 -1.7% PASS
total/synth/PUSH8/p0 0.00 0.00 +0.7% PASS
total/synth/PUSH8/p1 0.00 0.00 -3.4% PASS
total/synth/PUSH9/p0 0.00 0.00 -1.7% PASS
total/synth/PUSH9/p1 0.00 0.00 -3.4% PASS
total/synth/RETURNDATASIZE/a0 0.03 0.03 -0.2% PASS
total/synth/RETURNDATASIZE/a1 0.06 0.06 -5.4% PASS
total/synth/SAR/b0 0.00 0.00 -1.7% PASS
total/synth/SAR/b1 0.00 0.00 +0.6% PASS
total/synth/SGT/b0 0.00 0.00 -1.6% PASS
total/synth/SGT/b1 0.00 0.00 -1.9% PASS
total/synth/SHL/b0 0.00 0.00 +1.3% PASS
total/synth/SHL/b1 0.00 0.00 -1.5% PASS
total/synth/SHR/b0 0.00 0.00 +0.5% PASS
total/synth/SHR/b1 0.00 0.00 +1.3% PASS
total/synth/SIGNEXTEND/b0 0.00 0.00 -1.6% PASS
total/synth/SIGNEXTEND/b1 0.00 0.00 -0.9% PASS
total/synth/SLT/b0 0.00 0.00 -1.4% PASS
total/synth/SLT/b1 0.00 0.00 -1.2% PASS
total/synth/SUB/b0 0.00 0.00 -0.4% PASS
total/synth/SUB/b1 0.00 0.00 +0.1% PASS
total/synth/SWAP1/s0 0.00 0.00 -1.8% PASS
total/synth/SWAP10/s0 0.00 0.00 -2.7% PASS
total/synth/SWAP11/s0 0.00 0.00 -0.5% PASS
total/synth/SWAP12/s0 0.00 0.00 -0.1% PASS
total/synth/SWAP13/s0 0.00 0.00 -1.6% PASS
total/synth/SWAP14/s0 0.00 0.00 -1.0% PASS
total/synth/SWAP15/s0 0.00 0.00 -0.3% PASS
total/synth/SWAP16/s0 0.00 0.00 -1.4% PASS
total/synth/SWAP2/s0 0.00 0.00 -2.0% PASS
total/synth/SWAP3/s0 0.00 0.00 -0.6% PASS
total/synth/SWAP4/s0 0.00 0.00 -1.8% PASS
total/synth/SWAP5/s0 0.00 0.00 +0.5% PASS
total/synth/SWAP6/s0 0.00 0.00 +0.1% PASS
total/synth/SWAP7/s0 0.00 0.00 -1.0% PASS
total/synth/SWAP8/s0 0.00 0.00 -0.4% PASS
total/synth/SWAP9/s0 0.00 0.00 -0.7% PASS
total/synth/XOR/b0 0.00 0.00 +1.2% PASS
total/synth/XOR/b1 0.00 0.00 -0.1% PASS
total/synth/loop_v1 11.45 11.42 -0.2% PASS
total/synth/loop_v2 11.71 11.79 +0.7% PASS

Summary: 194 benchmarks, 0 regressions


abmcar and others added 3 commits June 9, 2026 21:30
The EVM multipass JIT's SSA stack-lift path (ZEN_ENABLE_EVM_STACK_SSA_LIFT,
off by default) emitted invalid MIR that the verifier rejected and that
crashed the JIT (SIGABRT) on real-world control flow. Three independent
defects, each fixed here; all changes are reachable only on the lift path,
so the default (flag-off) build is byte-for-byte unaffected.

1. Phi contiguity: createPendingPhi appended phis at the block end, so a
   multi-slot stack merge interleaved a later slot's phis after an earlier
   slot's temp-store dassigns, violating the phis-contiguous-at-block-start
   invariant. Insert each phi after the block's leading phi run instead.

2. Dynamic-jump-target phi undersize: codegen's indirect-jump dispatch wires
   an edge from every non-constant JUMP to every JUMPDEST, but the analyzer's
   shape-class predecessor enumeration is a strict subset, so such merge
   blocks got phis sized below their real predecessor count, causing a
   downstream out-of-bounds SIGABRT. Exclude these blocks from lifting via a
   predecessor-coverage check in finalizeLiftability.

3. Loop back-edge phi incoming block: a loop header's merge phi froze its
   back-edge incoming block before the JUMPI terminator wired the real CFG
   edge, recording the source block's entry MIR BB instead of the actual
   predecessor. Re-resolve incoming blocks once the full CFG exists, at the
   end of finalizeEVMBase (value preserved, only the block pointer fixed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
No behavior change; default-path multipass unittests stay 223/223.

- Deduplicate the phi-incoming forward walk: extract the BFS into
  resolveReachablePredecessorBB(TargetBB, CandidateBB) and have both
  resolveReachablePhiIncomingPredecessorBB and
  finalizeStackMergePhiIncomingBlocks use it, so reachability rules live in
  one place.
- Drop the const_cast: add PhiInstruction::setIncomingBlock(Index, Block),
  which updates only the incoming block and leaves the value untouched.
- Make a failed walk explicit: assert that the resolved block is a real
  predecessor (debug builds) instead of silently leaving a bad incoming block.
- Avoid O(N^2) in finalizeLiftability: compute the dynamic-jump dispatch
  source set once and pass it to the coverage check, which now tests
  membership against an unordered_set instead of recomputing and linear-scanning
  per block.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@abmcar
abmcar force-pushed the fix/evm-ssa-lift-phi-crashes branch from 1c6ff0b to 3b7fced Compare June 9, 2026 13:30
@zoowii
zoowii merged commit 302a0fc into DTVMStack:main Jun 10, 2026
17 checks passed
@abmcar
abmcar deleted the fix/evm-ssa-lift-phi-crashes branch June 18, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants