Skip to content

feat(evm): implement true-SSA stack lifting for EVM multipass JIT#395

Open
ZR74 wants to merge 14 commits intoDTVMStack:mainfrom
ZR74:pr-stack
Open

feat(evm): implement true-SSA stack lifting for EVM multipass JIT#395
ZR74 wants to merge 14 commits intoDTVMStack:mainfrom
ZR74:pr-stack

Conversation

@ZR74
Copy link
Copy Markdown
Contributor

@ZR74 ZR74 commented Mar 10, 2026

1. Does this PR affect any open issues?(Y/N) and add issue references (e.g. "fix #123", "re #123".):

  • N
  • Y

2. What is the scope of this PR (e.g. component or file name):

3. Provide a description of the PR(e.g. more details, effects, motivations or doc link):

  • Affects user behaviors
  • Contains CI/CD configuration changes
  • Contains documentation changes
  • Contains experimental features
  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Other

4. Are there any breaking changes?(Y/N) and describe the breaking changes(e.g. more details, motivations or doc link):

  • N
  • Y

5. Are there test cases for these changes?(Y/N) select and add more details, references or doc links:

  • Unit test
  • Integration test
  • Benchmark (add benchmark stats below)
  • Manual test (add detailed scripts or steps below)
  • Other

6. Release note

None

Copilot AI review requested due to automatic review settings March 10, 2026 16:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a conservative Phase-1 EVM stack-value lifting pass in the multipass JIT frontend. It extends the EVMAnalyzer with control-flow graph (CFG) edges, per-block stack depth propagation, JUMPDEST canonicalization, and liftability flags, then wires those results into EVMByteCodeVisitor and EVMMirBuilder so stack values can flow across safe constant-jump and fallthrough edges without immediate runtime stack materialization. The feature is opt-in behind a new CMake flag (ZEN_ENABLE_EVM_STACK_SSA_LIFT) and a focused regression test suite is added.

Changes:

  • New ZEN_ENABLE_EVM_STACK_SSA_LIFT CMake option and compile-time definition added to the root and src build files.
  • EVMAnalyzer heavily refactored into multiple passes (suitability, JUMPDEST-run canonicalization, block building, predecessor linking, depth propagation, liftability finalization) and BlockInfo extended with CFG and lifted-stack metadata.
  • EVMByteCodeVisitor extended with lifted-block tracking, logical-to-runtime stack materialization, and per-edge lifted entry-state assignment; EVMMirBuilder gets four new stack helpers; new evmJitFrontendTests target added to the test build.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
CMakeLists.txt Adds ZEN_ENABLE_EVM_STACK_SSA_LIFT option
src/CMakeLists.txt Adds add_definitions for the new flag
src/tests/CMakeLists.txt Adds evmJitFrontendTests build/link/test rules guarded by ZEN_ENABLE_EVM + ZEN_ENABLE_MULTIPASS_JIT
src/compiler/evm_frontend/evm_analyzer.h Full refactor: CFG building, depth propagation, liftability computation
src/compiler/evm_frontend/evm_mir_compiler.h Declares four new builder helpers for lifted stack support
src/compiler/evm_frontend/evm_mir_compiler.cpp Implements setTrackedStackDepth, createStackEntryOperand, assignStackEntryOperand, spillTrackedStack
src/action/evm_bytecode_visitor.h Lifted-block visitor logic, drainLogicalStack/restoreLogicalStack/finalizeBlockExit, per-opcode lifted-edge assignments
src/tests/evm_jit_frontend_tests.cpp New test suite with MockEVMBuilder and analyzer/visitor regression tests
openspec/changes/add-evm-stack-ssa-lift/* Proposal, design, spec, and task documentation

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

Comment on lines +583 to +602
while (true) {
BlockInfo Info(CurEntryPC, BodyStartPC, IsJumpDestBlock);
size_t ScanPC = BodyStartPC;
uint64_t NextEntryPC = 0;
size_t NextBodyStartPC = BytecodeSize;
bool HasNextBlock = false;
analyzeBlockBody(Info, Bytecode, BytecodeSize, ScanPC, NextEntryPC,
NextBodyStartPC, HasNextBlock);
BlockInfos[CurEntryPC] = Info;
if (!HasNextBlock) {
break;
}
CurEntryPC = NextEntryPC;
BodyStartPC = NextBodyStartPC;
IsJumpDestBlock = hasCanonicalJumpDest(CurEntryPC) &&
getCanonicalJumpDestPC(CurEntryPC) == CurEntryPC;
if (BodyStartPC > BytecodeSize) {
break;
}
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

In buildBlocks, when the very first opcode of the entry block (with EntryPC = 0, BodyStartPC = 0) is a JUMPI, the fallthrough block gets NextEntryPC = 0 (the JUMPI's PC). The loop then sets CurEntryPC = 0 and creates a new BlockInfo(0, 1, false) which overwrites the original entry block in BlockInfos[0]. This loses the JUMJI block's Successors, HasConditionalJump, and other fields. As a result, resolveEntryDepths will find only the overwritten block at EntryPC=0, never propagate stack depth to the jump target, and the BFS will produce incorrect liftability results for this control-flow pattern. A guard should ensure that a block is not created with an EntryPC equal to one that already exists (or the JUMPI fallthrough block's PC should be handled as CurPC + 1 rather than CurPC).

Copilot uses AI. Check for mistakes.
Comment on lines 262 to +322
@@ -169,157 +275,404 @@ class EVMAnalyzer {
evmc_get_instruction_names_table(zen::evm::DEFAULT_REVISION);
}

// Initialize block info for the first block
BlockInfo CurInfo(0);

// JIT suitability tracking state
size_t CurConsecutiveExpensive = 0;
size_t CurBlockExpensiveCount = 0;
bool PrevWasDup = false;

while (Ip < IpEnd) {
evmc_opcode Opcode = static_cast<evmc_opcode>(*Ip);
size_t PCIndex = 0;
while (PCIndex < BytecodeSize) {
evmc_opcode Opcode = static_cast<evmc_opcode>(Bytecode[PCIndex]);
uint8_t OpcodeU8 = static_cast<uint8_t>(Opcode);
ptrdiff_t Diff = Ip - Bytecode;
PC = static_cast<uint64_t>(Diff >= 0 ? Diff : 0);

Ip++;

// --- JIT suitability: accumulate MIR estimate ---
JITResult.MirEstimate += MIR_OPCODE_WEIGHT[OpcodeU8];

// --- JIT suitability: RA-expensive pattern tracking ---
if (isRAExpensiveOpcode(OpcodeU8)) {
JITResult.RAExpensiveCount++;
CurInfo.RAExpensiveCount++;
CurBlockExpensiveCount++;
CurConsecutiveExpensive++;
// DUP feedback: previous opcode was DUP, now RA-expensive
if (PrevWasDup) {
JITResult.DupFeedbackPatternCount++;
}
PrevWasDup = false;
} else if (isDupOrSwapOpcode(OpcodeU8)) {
// DUP/SWAP are transparent — don't break consecutive run
PrevWasDup = isDupOpcode(OpcodeU8);
} else {
// Any other opcode breaks the consecutive run
JITResult.MaxConsecutiveExpensive = std::max(
JITResult.MaxConsecutiveExpensive, CurConsecutiveExpensive);
CurConsecutiveExpensive = 0;
PrevWasDup = false;
}

// Check if opcode is undefined for current revision
bool IsBlockBoundary = (Opcode == OP_JUMPI || Opcode == OP_JUMPDEST ||
isBlockTerminator(Opcode));
if (IsBlockBoundary) {
JITResult.MaxBlockExpensiveCount =
std::max(JITResult.MaxBlockExpensiveCount, CurBlockExpensiveCount);
CurBlockExpensiveCount = 0;
JITResult.MaxConsecutiveExpensive = std::max(
JITResult.MaxConsecutiveExpensive, CurConsecutiveExpensive);
CurConsecutiveExpensive = 0;
PrevWasDup = false;
}

size_t PushBytes = immediateSize(Opcode);
PCIndex += 1 + PushBytes;

(void)InstructionMetrics;
(void)InstructionNames;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

In analyzeSuitability, InstructionMetrics and InstructionNames are retrieved (with fallback logic) but are never actually used in the function body — they are only suppressed with (void) casts at lines 321-322. The original code used them for undefined instruction tracking and stack metric computation, but in the refactored version these responsibilities moved to analyzeBlockBody. The dead fetch and the fallback assignments to InstructionNames/InstructionMetrics (lines 266-276) should be removed.

Copilot uses AI. Check for mistakes.
Comment on lines +360 to +368
void ensureAbstractDepth(std::vector<AbstractValue> &Stack,
size_t &EntryDepth, size_t RequiredDepth) {
if (Stack.size() >= RequiredDepth) {
return;
}
size_t Deficit = RequiredDepth - Stack.size();
Stack.insert(Stack.begin(), Deficit, AbstractValue::unknown());
EntryDepth += Deficit;
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The ensureAbstractDepth function uses Stack.insert(Stack.begin(), ...) to prepend elements to a std::vector. This is O(n) per call because it shifts all existing elements. While the EVM stack is bounded at 1024 and this runs at compile time, the pattern is called repeatedly within analyzeBlockBody for each opcode that requires more stack depth than currently tracked, which could cause O(n²) behavior in degenerate cases where the block gradually reveals a deep pre-existing stack. Consider using a deque or prepending to a separate "prefix" vector to avoid repeated O(n) shifts.

Copilot uses AI. Check for mistakes.
bool InDeadCode = false;
uint64_t PC = 0;
bool CurrentBlockLifted = false;
std::map<uint64_t, bool> LiftedBlocks;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The LiftedBlocks member is declared as std::map<uint64_t, bool> but is used purely as a set (values are always true when inserted, and isLiftedBlock checks It->second). Using a std::set<uint64_t> or std::unordered_set<uint64_t> would be more semantically clear and slightly more efficient by removing the unused boolean storage. The rest of the codebase uses std::map for block data that has associated values (e.g. LiftedEntryStates), so this inconsistency stands out.

Copilot uses AI. Check for mistakes.
Comment on lines +852 to +862
bool tryAssignFallthroughEntryState(const EVMAnalyzer &Analyzer,
uint64_t SuccPC) {
(void)Analyzer;
if (!CurrentBlockLifted || !isLiftedBlock(SuccPC)) {
return false;
}
auto OutgoingStack = drainLogicalStack();
assignLiftedEntryState(SuccPC, OutgoingStack);
finalizeBlockExit(std::move(OutgoingStack), false);
return true;
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The tryAssignFallthroughEntryState method declares a const EVMAnalyzer &Analyzer parameter but immediately suppresses it with (void)Analyzer without using it anywhere in the function body. This unused parameter should be removed from the function signature and all call sites updated accordingly.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 10, 2026

⚡ 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 1.32 1.59 +21.0% PASS
total/main/blake2b_huff/empty 0.02 0.03 +21.6% PASS
total/main/blake2b_shifts/8415nulls 9.58 11.89 +24.1% PASS
total/main/sha1_divs/5311 4.33 5.20 +20.1% PASS
total/main/sha1_divs/empty 0.05 0.07 +27.0% PASS
total/main/sha1_shifts/5311 2.26 3.04 +34.2% PASS
total/main/sha1_shifts/empty 0.03 0.04 +31.9% PASS
total/main/snailtracer/benchmark 48.59 54.30 +11.8% PASS
total/main/structarray_alloc/nfts_rank 0.91 1.13 +24.7% PASS
total/main/swap_math/insufficient_liquidity 0.00 0.00 +25.5% PASS
total/main/swap_math/received 0.00 0.01 +27.7% PASS
total/main/swap_math/spent 0.00 0.00 +28.2% PASS
total/main/weierstrudel/1 0.23 0.29 +26.4% PASS
total/main/weierstrudel/15 2.49 3.18 +27.7% PASS
total/micro/JUMPDEST_n0/empty 1.22 1.30 +7.1% PASS
total/micro/jump_around/empty 0.04 0.09 +140.6% PASS
total/micro/loop_with_many_jumpdests/empty 18.48 19.91 +7.7% PASS
total/micro/memory_grow_mload/by1 0.08 0.09 +13.2% PASS
total/micro/memory_grow_mload/by16 0.10 0.10 +7.8% PASS
total/micro/memory_grow_mload/by32 0.10 0.12 +16.3% PASS
total/micro/memory_grow_mload/nogrow 0.08 0.09 +9.8% PASS
total/micro/memory_grow_mstore/by1 0.09 0.10 +15.3% PASS
total/micro/memory_grow_mstore/by16 0.10 0.11 +14.3% PASS
total/micro/memory_grow_mstore/by32 0.11 0.13 +17.0% PASS
total/micro/memory_grow_mstore/nogrow 0.08 0.10 +13.8% PASS
total/micro/signextend/one 0.23 0.27 +17.4% PASS
total/micro/signextend/zero 0.23 0.27 +20.3% PASS
total/synth/ADD/b0 1.35 1.95 +44.9% PASS
total/synth/ADD/b1 1.25 1.98 +58.0% PASS
total/synth/ADDRESS/a0 5.95 4.72 -20.6% PASS
total/synth/ADDRESS/a1 6.25 5.21 -16.5% PASS
total/synth/AND/b0 1.27 1.63 +27.9% PASS
total/synth/AND/b1 1.07 1.71 +59.8% PASS
total/synth/BYTE/b0 4.60 6.08 +32.2% PASS
total/synth/BYTE/b1 3.72 4.73 +27.3% PASS
total/synth/CALLDATASIZE/a0 2.95 3.31 +12.1% PASS
total/synth/CALLDATASIZE/a1 3.11 3.48 +11.6% PASS
total/synth/CALLER/a0 6.03 4.73 -21.6% PASS
total/synth/CALLER/a1 6.23 5.23 -16.1% PASS
total/synth/CALLVALUE/a0 3.10 3.43 +10.7% PASS
total/synth/CALLVALUE/a1 3.10 3.59 +16.0% PASS
total/synth/CODESIZE/a0 3.54 3.51 -0.9% PASS
total/synth/CODESIZE/a1 3.55 3.83 +7.9% PASS
total/synth/DUP1/d0 0.87 1.23 +41.0% PASS
total/synth/DUP1/d1 0.84 1.31 +56.5% PASS
total/synth/DUP10/d0 0.89 1.22 +38.0% PASS
total/synth/DUP10/d1 0.84 1.31 +57.1% PASS
total/synth/DUP11/d0 0.89 1.23 +38.1% PASS
total/synth/DUP11/d1 0.84 1.08 +28.4% PASS
total/synth/DUP12/d0 0.89 1.07 +20.5% PASS
total/synth/DUP12/d1 0.84 1.31 +56.4% PASS
total/synth/DUP13/d0 0.89 1.23 +38.0% PASS
total/synth/DUP13/d1 0.84 1.08 +28.3% PASS
total/synth/DUP14/d0 0.89 1.23 +37.6% PASS
total/synth/DUP14/d1 0.84 1.31 +56.7% PASS
total/synth/DUP15/d0 0.89 0.99 +10.8% PASS
total/synth/DUP15/d1 0.84 1.08 +28.1% PASS
total/synth/DUP16/d0 0.88 1.08 +22.6% PASS
total/synth/DUP16/d1 0.84 1.31 +56.8% PASS
total/synth/DUP2/d0 0.88 1.23 +39.7% PASS
total/synth/DUP2/d1 0.84 1.31 +56.7% PASS
total/synth/DUP3/d0 0.86 1.23 +42.3% PASS
total/synth/DUP3/d1 0.84 1.08 +28.2% PASS
total/synth/DUP4/d0 0.87 1.30 +48.6% PASS
total/synth/DUP4/d1 0.84 1.31 +56.7% PASS
total/synth/DUP5/d0 0.87 1.23 +41.3% PASS
total/synth/DUP5/d1 0.84 1.31 +57.2% PASS
total/synth/DUP6/d0 0.88 1.02 +15.0% PASS
total/synth/DUP6/d1 0.84 1.31 +56.6% PASS
total/synth/DUP7/d0 0.88 1.22 +39.2% PASS
total/synth/DUP7/d1 0.84 1.31 +56.6% PASS
total/synth/DUP8/d0 0.88 1.07 +21.8% PASS
total/synth/DUP8/d1 0.84 1.07 +28.0% PASS
total/synth/DUP9/d0 0.88 1.23 +40.1% PASS
total/synth/DUP9/d1 0.84 1.32 +56.9% PASS
total/synth/EQ/b0 2.30 2.69 +17.2% PASS
total/synth/EQ/b1 1.27 1.31 +3.1% PASS
total/synth/GAS/a0 3.39 3.75 +10.4% PASS
total/synth/GAS/a1 3.40 3.75 +10.3% PASS
total/synth/GT/b0 2.20 2.58 +17.0% PASS
total/synth/GT/b1 1.05 1.47 +39.7% PASS
total/synth/ISZERO/u0 0.81 1.14 +41.5% PASS
total/synth/JUMPDEST/n0 1.22 1.31 +7.3% PASS
total/synth/LT/b0 2.16 2.60 +20.2% PASS
total/synth/LT/b1 0.99 1.47 +49.2% PASS
total/synth/MSIZE/a0 4.14 4.27 +3.0% PASS
total/synth/MSIZE/a1 4.48 4.72 +5.5% PASS
total/synth/MUL/b0 4.45 5.31 +19.6% PASS
total/synth/MUL/b1 4.79 5.30 +10.6% PASS
total/synth/NOT/u0 1.12 1.67 +48.3% PASS
total/synth/OR/b0 1.30 1.63 +25.6% PASS
total/synth/OR/b1 1.09 1.71 +57.0% PASS
total/synth/PC/a0 3.07 3.41 +11.0% PASS
total/synth/PC/a1 3.11 3.51 +12.9% PASS
total/synth/PUSH1/p0 0.97 1.23 +26.5% PASS
total/synth/PUSH1/p1 1.03 1.30 +26.9% PASS
total/synth/PUSH10/p0 0.98 0.99 +0.8% PASS
total/synth/PUSH10/p1 1.05 1.32 +26.2% PASS
total/synth/PUSH11/p0 0.98 0.99 +1.1% PASS
total/synth/PUSH11/p1 1.04 1.33 +28.1% PASS
total/synth/PUSH12/p0 0.98 1.23 +25.3% PASS
total/synth/PUSH12/p1 1.05 1.32 +25.8% PASS
total/synth/PUSH13/p0 0.99 0.99 +0.4% PASS
total/synth/PUSH13/p1 1.05 1.31 +24.5% PASS
total/synth/PUSH14/p0 0.95 1.01 +6.7% PASS
total/synth/PUSH14/p1 1.05 1.33 +26.3% PASS
total/synth/PUSH15/p0 0.98 1.23 +24.8% PASS
total/synth/PUSH15/p1 1.04 1.44 +37.8% PASS
total/synth/PUSH16/p0 0.98 1.23 +24.8% PASS
total/synth/PUSH16/p1 1.06 1.31 +23.6% PASS
total/synth/PUSH17/p0 0.98 1.23 +25.4% PASS
total/synth/PUSH17/p1 1.06 1.33 +25.7% PASS
total/synth/PUSH18/p0 0.99 1.23 +23.9% PASS
total/synth/PUSH18/p1 1.06 1.32 +24.6% PASS
total/synth/PUSH19/p0 0.99 1.23 +24.5% PASS
total/synth/PUSH19/p1 1.06 1.33 +25.5% PASS
total/synth/PUSH2/p0 0.98 1.18 +20.9% PASS
total/synth/PUSH2/p1 1.03 1.31 +27.1% PASS
total/synth/PUSH20/p0 0.99 0.99 +0.1% PASS
total/synth/PUSH20/p1 1.06 1.33 +25.2% PASS
total/synth/PUSH21/p0 0.98 0.99 +0.5% PASS
total/synth/PUSH21/p1 1.07 1.34 +25.3% PASS
total/synth/PUSH22/p0 0.98 1.23 +25.5% PASS
total/synth/PUSH22/p1 1.07 1.33 +24.3% PASS
total/synth/PUSH23/p0 0.98 1.15 +16.8% PASS
total/synth/PUSH23/p1 1.07 1.33 +25.0% PASS
total/synth/PUSH24/p0 0.99 1.23 +24.5% PASS
total/synth/PUSH24/p1 1.07 1.33 +24.3% PASS
total/synth/PUSH25/p0 0.99 0.99 -0.0% PASS
total/synth/PUSH25/p1 1.08 1.31 +21.5% PASS
total/synth/PUSH26/p0 0.99 1.23 +23.9% PASS
total/synth/PUSH26/p1 1.08 1.33 +23.3% PASS
total/synth/PUSH27/p0 0.99 0.99 +0.4% PASS
total/synth/PUSH27/p1 1.08 1.32 +23.0% PASS
total/synth/PUSH28/p0 0.99 1.22 +23.7% PASS
total/synth/PUSH28/p1 1.08 1.33 +23.1% PASS
total/synth/PUSH29/p0 0.99 1.22 +23.9% PASS
total/synth/PUSH29/p1 1.09 1.34 +22.5% PASS
total/synth/PUSH3/p0 0.98 0.99 +1.0% PASS
total/synth/PUSH3/p1 1.04 1.31 +26.4% PASS
total/synth/PUSH30/p0 0.93 1.16 +24.8% PASS
total/synth/PUSH30/p1 1.09 1.34 +23.3% PASS
total/synth/PUSH31/p0 0.99 1.23 +24.3% PASS
total/synth/PUSH31/p1 1.06 1.43 +34.0% PASS
total/synth/PUSH32/p0 0.99 0.99 -0.4% PASS
total/synth/PUSH32/p1 1.10 1.34 +20.9% PASS
total/synth/PUSH4/p0 0.98 0.99 +0.8% PASS
total/synth/PUSH4/p1 1.04 1.32 +26.7% PASS
total/synth/PUSH5/p0 0.98 1.23 +26.1% PASS
total/synth/PUSH5/p1 1.04 1.31 +25.4% PASS
total/synth/PUSH6/p0 0.95 0.99 +3.8% PASS
total/synth/PUSH6/p1 1.04 1.32 +26.7% PASS
total/synth/PUSH7/p0 0.98 0.99 +1.0% PASS
total/synth/PUSH7/p1 1.03 1.31 +26.9% PASS
total/synth/PUSH8/p0 0.98 1.23 +25.7% PASS
total/synth/PUSH8/p1 1.05 1.32 +26.6% PASS
total/synth/PUSH9/p0 0.98 1.23 +25.7% PASS
total/synth/PUSH9/p1 1.10 1.33 +20.8% PASS
total/synth/RETURNDATASIZE/a0 3.54 3.45 -2.6% PASS
total/synth/RETURNDATASIZE/a1 3.60 3.75 +4.2% PASS
total/synth/SAR/b0 3.80 3.78 -0.5% PASS
total/synth/SAR/b1 4.00 4.31 +7.8% PASS
total/synth/SGT/b0 2.19 2.60 +18.6% PASS
total/synth/SGT/b1 1.14 1.55 +36.4% PASS
total/synth/SHL/b0 2.80 3.03 +8.2% PASS
total/synth/SHL/b1 1.29 1.67 +30.0% PASS
total/synth/SHR/b0 2.76 3.10 +12.3% PASS
total/synth/SHR/b1 1.26 1.62 +28.7% PASS
total/synth/SIGNEXTEND/b0 3.05 3.37 +10.7% PASS
total/synth/SIGNEXTEND/b1 2.95 3.43 +16.2% PASS
total/synth/SLT/b0 2.21 2.61 +18.2% PASS
total/synth/SLT/b1 1.14 1.56 +36.5% PASS
total/synth/SUB/b0 1.35 1.95 +44.3% PASS
total/synth/SUB/b1 1.24 1.97 +59.0% PASS
total/synth/SWAP1/s0 1.26 1.50 +19.0% PASS
total/synth/SWAP10/s0 1.24 1.52 +22.0% PASS
total/synth/SWAP11/s0 1.26 1.52 +20.4% PASS
total/synth/SWAP12/s0 1.27 1.52 +20.1% PASS
total/synth/SWAP13/s0 1.26 1.52 +20.1% PASS
total/synth/SWAP14/s0 1.25 1.52 +22.1% PASS
total/synth/SWAP15/s0 1.24 1.52 +23.0% PASS
total/synth/SWAP16/s0 1.24 1.53 +23.5% PASS
total/synth/SWAP2/s0 1.26 1.50 +18.9% PASS
total/synth/SWAP3/s0 1.26 1.50 +19.8% PASS
total/synth/SWAP4/s0 1.25 1.50 +20.3% PASS
total/synth/SWAP5/s0 1.24 1.51 +21.4% PASS
total/synth/SWAP6/s0 1.25 1.51 +21.2% PASS
total/synth/SWAP7/s0 1.25 1.52 +21.4% PASS
total/synth/SWAP8/s0 1.26 1.51 +20.4% PASS
total/synth/SWAP9/s0 1.26 1.52 +20.0% PASS
total/synth/XOR/b0 1.00 1.55 +54.1% PASS
total/synth/XOR/b1 1.04 1.55 +48.7% PASS
total/synth/loop_v1 3.64 4.77 +31.2% PASS
total/synth/loop_v2 3.64 4.74 +30.2% 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 1.58 1.57 -0.6% PASS
total/main/blake2b_huff/empty 0.07 0.03 -64.7% PASS
total/main/blake2b_shifts/8415nulls 6.45 7.67 +18.9% PASS
total/main/sha1_divs/5311 3.54 3.60 +1.7% PASS
total/main/sha1_divs/empty 0.05 0.04 -12.0% PASS
total/main/sha1_shifts/5311 3.72 3.76 +1.0% PASS
total/main/sha1_shifts/empty 0.05 0.05 -11.5% PASS
total/main/snailtracer/benchmark 58.21 54.72 -6.0% PASS
total/main/structarray_alloc/nfts_rank 0.30 0.29 -3.1% PASS
total/main/swap_math/insufficient_liquidity 0.02 0.00 -84.6% PASS
total/main/swap_math/received 0.02 0.00 -77.9% PASS
total/main/swap_math/spent 0.02 0.00 -79.9% PASS
total/main/weierstrudel/1 0.36 0.29 -19.9% PASS
total/main/weierstrudel/15 3.24 3.17 -2.3% PASS
total/micro/JUMPDEST_n0/empty 0.13 0.00 -99.0% PASS
total/micro/jump_around/empty 0.63 0.09 -86.3% PASS
total/micro/loop_with_many_jumpdests/empty 1.96 0.00 -99.8% PASS
total/micro/memory_grow_mload/by1 0.19 0.09 -54.5% PASS
total/micro/memory_grow_mload/by16 0.20 0.10 -51.4% PASS
total/micro/memory_grow_mload/by32 0.22 0.11 -47.1% PASS
total/micro/memory_grow_mload/nogrow 0.19 0.08 -56.3% PASS
total/micro/memory_grow_mstore/by1 0.19 0.10 -49.3% PASS
total/micro/memory_grow_mstore/by16 0.21 0.11 -49.1% PASS
total/micro/memory_grow_mstore/by32 0.22 0.12 -44.3% PASS
total/micro/memory_grow_mstore/nogrow 0.19 0.09 -51.8% PASS
total/micro/signextend/one 0.35 0.24 -32.6% PASS
total/micro/signextend/zero 0.35 0.28 -19.8% PASS
total/synth/ADD/b0 0.01 0.00 -89.0% PASS
total/synth/ADD/b1 0.01 0.00 -89.0% PASS
total/synth/ADDRESS/a0 0.16 0.15 -6.6% PASS
total/synth/ADDRESS/a1 0.16 0.15 -6.7% PASS
total/synth/AND/b0 0.01 0.00 -89.0% PASS
total/synth/AND/b1 0.01 0.00 -89.0% PASS
total/synth/BYTE/b0 1.95 1.95 -0.2% PASS
total/synth/BYTE/b1 2.32 2.27 -2.2% PASS
total/synth/CALLDATASIZE/a0 0.08 0.07 -10.8% PASS
total/synth/CALLDATASIZE/a1 0.08 0.07 -11.4% PASS
total/synth/CALLER/a0 0.16 0.15 -6.6% PASS
total/synth/CALLER/a1 0.16 0.15 -6.7% PASS
total/synth/CALLVALUE/a0 0.28 0.26 -4.1% PASS
total/synth/CALLVALUE/a1 0.28 0.26 -4.1% PASS
total/synth/CODESIZE/a0 0.08 0.07 -13.5% PASS
total/synth/CODESIZE/a1 0.08 0.07 -14.3% PASS
total/synth/DUP1/d0 0.01 0.00 -89.0% PASS
total/synth/DUP1/d1 0.01 0.00 -89.0% PASS
total/synth/DUP10/d0 0.01 0.00 -89.0% PASS
total/synth/DUP10/d1 0.01 0.00 -89.0% PASS
total/synth/DUP11/d0 0.01 0.00 -89.0% PASS
total/synth/DUP11/d1 0.01 0.00 -89.0% PASS
total/synth/DUP12/d0 0.01 0.00 -89.0% PASS
total/synth/DUP12/d1 0.01 0.00 -89.0% PASS
total/synth/DUP13/d0 0.01 0.00 -89.0% PASS
total/synth/DUP13/d1 0.01 0.00 -89.0% PASS
total/synth/DUP14/d0 0.01 0.00 -89.0% PASS
total/synth/DUP14/d1 0.01 0.00 -89.0% PASS
total/synth/DUP15/d0 0.01 0.00 -89.0% PASS
total/synth/DUP15/d1 0.01 0.00 -89.0% PASS
total/synth/DUP16/d0 0.01 0.00 -89.0% PASS
total/synth/DUP16/d1 0.01 0.00 -89.0% PASS
total/synth/DUP2/d0 0.01 0.00 -89.0% PASS
total/synth/DUP2/d1 0.01 0.00 -89.0% PASS
total/synth/DUP3/d0 0.01 0.00 -89.0% PASS
total/synth/DUP3/d1 0.01 0.00 -89.0% PASS
total/synth/DUP4/d0 0.01 0.00 -89.0% PASS
total/synth/DUP4/d1 0.01 0.00 -89.0% PASS
total/synth/DUP5/d0 0.01 0.00 -89.0% PASS
total/synth/DUP5/d1 0.01 0.00 -89.0% PASS
total/synth/DUP6/d0 0.01 0.00 -89.0% PASS
total/synth/DUP6/d1 0.01 0.00 -89.0% PASS
total/synth/DUP7/d0 0.01 0.00 -89.0% PASS
total/synth/DUP7/d1 0.01 0.00 -88.9% PASS
total/synth/DUP8/d0 0.01 0.00 -89.0% PASS
total/synth/DUP8/d1 0.01 0.00 -89.0% PASS
total/synth/DUP9/d0 0.01 0.00 -89.0% PASS
total/synth/DUP9/d1 0.01 0.00 -89.0% PASS
total/synth/EQ/b0 0.01 0.00 -89.0% PASS
total/synth/EQ/b1 0.01 0.00 -89.0% PASS
total/synth/GAS/a0 0.79 0.78 -1.5% PASS
total/synth/GAS/a1 0.79 0.78 -1.5% PASS
total/synth/GT/b0 0.01 0.00 -89.0% PASS
total/synth/GT/b1 0.01 0.00 -89.0% PASS
total/synth/ISZERO/u0 0.01 0.00 -89.6% PASS
total/synth/JUMPDEST/n0 0.13 0.00 -99.0% PASS
total/synth/LT/b0 0.01 0.00 -89.0% PASS
total/synth/LT/b1 0.01 0.00 -89.0% PASS
total/synth/MSIZE/a0 0.01 0.00 -89.6% PASS
total/synth/MSIZE/a1 0.01 0.00 -89.6% PASS
total/synth/MUL/b0 0.01 0.00 -89.0% PASS
total/synth/MUL/b1 0.01 0.00 -89.0% PASS
total/synth/NOT/u0 0.01 0.00 -89.6% PASS
total/synth/OR/b0 0.01 0.00 -89.0% PASS
total/synth/OR/b1 0.01 0.00 -89.0% PASS
total/synth/PC/a0 0.01 0.00 -89.6% PASS
total/synth/PC/a1 0.01 0.00 -89.6% PASS
total/synth/PUSH1/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH1/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH10/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH10/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH11/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH11/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH12/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH12/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH13/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH13/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH14/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH14/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH15/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH15/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH16/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH16/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH17/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH17/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH18/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH18/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH19/p0 0.01 0.00 -89.4% PASS
total/synth/PUSH19/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH2/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH2/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH20/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH20/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH21/p0 0.01 0.00 -89.4% PASS
total/synth/PUSH21/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH22/p0 1.33 1.23 -6.9% PASS
total/synth/PUSH22/p1 1.16 1.31 +13.2% PASS
total/synth/PUSH23/p0 1.32 1.23 -7.0% PASS
total/synth/PUSH23/p1 1.15 1.32 +14.8% PASS
total/synth/PUSH24/p0 1.32 1.23 -6.8% PASS
total/synth/PUSH24/p1 1.19 1.36 +13.9% PASS
total/synth/PUSH25/p0 1.32 1.23 -6.9% PASS
total/synth/PUSH25/p1 1.16 1.31 +13.0% PASS
total/synth/PUSH26/p0 1.03 1.23 +19.1% PASS
total/synth/PUSH26/p1 1.16 1.33 +15.1% PASS
total/synth/PUSH27/p0 1.32 1.23 -7.0% PASS
total/synth/PUSH27/p1 1.18 1.34 +13.7% PASS
total/synth/PUSH28/p0 1.33 1.23 -7.2% PASS
total/synth/PUSH28/p1 1.14 1.34 +17.4% PASS
total/synth/PUSH29/p0 1.32 1.22 -7.9% PASS
total/synth/PUSH29/p1 1.18 1.31 +11.3% PASS
total/synth/PUSH3/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH3/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH30/p0 1.33 1.24 -6.7% PASS
total/synth/PUSH30/p1 1.17 1.33 +13.8% PASS
total/synth/PUSH31/p0 1.25 1.23 -1.1% PASS
total/synth/PUSH31/p1 1.26 1.44 +14.1% PASS
total/synth/PUSH32/p0 1.33 1.23 -7.3% PASS
total/synth/PUSH32/p1 1.19 1.34 +12.2% PASS
total/synth/PUSH4/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH4/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH5/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH5/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH6/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH6/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH7/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH7/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH8/p0 0.01 0.00 -89.4% PASS
total/synth/PUSH8/p1 0.01 0.00 -89.3% PASS
total/synth/PUSH9/p0 0.01 0.00 -89.3% PASS
total/synth/PUSH9/p1 0.01 0.00 -89.3% PASS
total/synth/RETURNDATASIZE/a0 0.68 0.60 -12.3% PASS
total/synth/RETURNDATASIZE/a1 0.65 0.56 -13.0% PASS
total/synth/SAR/b0 3.78 3.78 +0.1% PASS
total/synth/SAR/b1 4.28 4.31 +0.7% PASS
total/synth/SGT/b0 0.01 0.00 -89.0% PASS
total/synth/SGT/b1 0.01 0.00 -89.0% PASS
total/synth/SHL/b0 3.07 3.02 -1.4% PASS
total/synth/SHL/b1 1.75 1.66 -4.8% PASS
total/synth/SHR/b0 3.10 3.10 +0.0% PASS
total/synth/SHR/b1 1.65 1.63 -1.1% PASS
total/synth/SIGNEXTEND/b0 3.11 3.11 +0.2% PASS
total/synth/SIGNEXTEND/b1 3.46 4.07 +17.9% PASS
total/synth/SLT/b0 0.01 0.00 -89.0% PASS
total/synth/SLT/b1 0.01 0.00 -89.0% PASS
total/synth/SUB/b0 0.01 0.00 -89.0% PASS
total/synth/SUB/b1 0.01 0.00 -89.0% PASS
total/synth/SWAP1/s0 0.01 0.00 -88.3% PASS
total/synth/SWAP10/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP11/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP12/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP13/s0 0.01 0.00 -88.5% PASS
total/synth/SWAP14/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP15/s0 0.01 0.00 -88.5% PASS
total/synth/SWAP16/s0 0.01 0.00 -88.5% PASS
total/synth/SWAP2/s0 0.01 0.00 -88.3% PASS
total/synth/SWAP3/s0 0.01 0.00 -88.3% PASS
total/synth/SWAP4/s0 0.01 0.00 -88.3% PASS
total/synth/SWAP5/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP6/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP7/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP8/s0 0.01 0.00 -88.4% PASS
total/synth/SWAP9/s0 0.01 0.00 -88.4% PASS
total/synth/XOR/b0 0.01 0.00 -89.0% PASS
total/synth/XOR/b1 0.01 0.00 -89.0% PASS
total/synth/loop_v1 1.41 1.19 -15.5% PASS
total/synth/loop_v2 1.41 1.20 -15.2% PASS

Summary: 194 benchmarks, 0 regressions


@ZR74 ZR74 marked this pull request as draft March 11, 2026 10:57
@ZR74 ZR74 marked this pull request as ready for review March 13, 2026 07:27
@zoowii zoowii requested a review from Copilot March 13, 2026 14:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.


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

Comment on lines +658 to +662
if (SuccInfo.ResolvedEntryStackDepth < 0) {
SuccInfo.ResolvedEntryStackDepth = ExitDepth;
WorkList.push(Succ);
} else if (SuccInfo.ResolvedEntryStackDepth != ExitDepth) {
SuccInfo.HasInconsistentEntryDepth = true;
Comment on lines 275 to 277
const auto *InstructionMetrics =
evmc_get_instruction_metrics_table(Revision);
const auto *InstructionNames = evmc_get_instruction_names_table(Revision);
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.


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

@ZR74 ZR74 marked this pull request as draft March 22, 2026 06:57
ZR74 added 3 commits March 22, 2026 15:57
Add compatibility shims for legacy frontend test builders so the SSA frontend changes still compile in evmJitFrontendTests.\n\nStop undefined-opcode analysis at the first undefined instruction and let the visitor trap at the real opcode position instead of rejecting the whole block at entry. This avoids bogus stack-overflow traps in multipass external_vm tests and keeps the frontend regressions covered with updated analyzer expectations and a new undefined-opcode test.
Replace the heavy compiler common header in the EVM analyzer with the lightweight common defines header. This keeps runtime-side users such as evm_module building in CI jobs that do not expose LLVM headers on the runtime compile path while preserving the analyzer behavior.
@ZR74 ZR74 changed the title feat: add conservative Phase-1 EVM stack lifting in multipass frontend feat(evm): implement true-SSA stack lifting for EVM multipass JIT Mar 22, 2026
@ZR74 ZR74 marked this pull request as ready for review March 22, 2026 10:43
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.

2 participants