Skip to content

perf(compiler): thread ValueRange through OR/XOR/SHR_U + narrow U64/U128 compare paths#499

Open
abmcar wants to merge 6 commits into
DTVMStack:mainfrom
abmcar:g4-safe-valuerange
Open

perf(compiler): thread ValueRange through OR/XOR/SHR_U + narrow U64/U128 compare paths#499
abmcar wants to merge 6 commits into
DTVMStack:mainfrom
abmcar:g4-safe-valuerange

Conversation

@abmcar
Copy link
Copy Markdown
Contributor

@abmcar abmcar commented May 12, 2026

Summary

Extend the monotone-safe subset of ValueRange propagation in EVMMirBuilder so narrower-range information survives across more producers and is exploited by the unsigned-RHS compare consumers.

Producer side (commit 8b546b3)

  • OR / XOR (handleBitwiseOp): both Phase-1 u64-const fast path and Phase-5 general path now carry max(LHS.range, RHS.range). AND is unaffected — its monotone direction is min, already handled by its existing earlier returns.
  • Unsigned SHR (handleShift<BO_SHR_U>): result carries ValueOp.getRange() — right shift cannot widen. SHL widens by construction; SAR sign-fills; both keep the U256 default.

Consumer side (commits 8b546b3 + c0ae6aa)

handleCompareEqU64 / handleCompareLtRhsU64 / handleCompareGtRhsU64 short-circuit the upper-limbs check based on the LHS range tag:

LHS range Upper-limbs work emitted
ValueRange::U64 (commit 8b546b3) None — single-limb LHS[0] compare. Saves 2 OR + 1 CMP + 1 AND/Select.
ValueRange::U128 (commit c0ae6aa) Single LHS[1] != 0 check. The range tag proves limbs[2..3] are value-zero, so the generated consumer does not need to inspect them. Saves 2 OR vs U256 path.
ValueRange::U256 (unchanged) Full 3-limb OR-fold + zero-test.

The fast paths rely on the value-level ValueRange invariant: U64 means limbs[1..3] are zero at runtime, and U128 means limbs[2..3] are zero at runtime. Some producers, notably dynamic SHR_U, can establish that fact through selects/ORs rather than literal MIR zero instructions, so correctness is based on the range tag's soundness rather than structural literal-zero form.

Out of scope (deferred)

SUB (wraps to full U256), SHL (widens), SAR (sign-fills upper limbs), ADDMOD/MULMOD (need a richer range model than U64/U128/U256), EXP, signed compare. Rationale + verification in docs/changes/2026-05-12-g4-safe-valuerange/README.md.

Validation

Local (worktree built with CI-faithful flags incl. -DZEN_ENABLE_JIT_PRECOMPILE_FALLBACK=ON):

Gate Result
tools/format.sh check clean
cmake --build build --target dtvmapi green, no new warnings
evmone-unittests multipass (run list) 223 / 223
evmone-statetest -k fork_Cancun multipass 2723 / 2723

Performance — three layers of evidence

1. CI multipass regression check

Current PR HEAD: ad82eb5. CI is rerunning for this cleanup commit; do not treat the prior all-green status as current until the pending checks complete.

Previous performance run on the pre-cleanup implementation (c0ae6aa) covered 192 benches with a 25% threshold and passed. Wins were concentrated on macro / shift-heavy paths:

Bench Baseline Branch Δ
total/main/snailtracer/benchmark 32.01 us 30.92 us −3.40%
total/main/blake2b_shifts/8415nulls 4.41 us 4.33 us −1.80%
total/main/blake2b_huff/8415nulls 0.82 us 0.81 us −1.20%
total/main/structarray_alloc/nfts_rank 0.27 us 0.27 us −0.20%
total/main/weierstrudel/15 2.57 us 2.57 us +0.20%
total/main/weierstrudel/1 0.24 us 0.24 us +0.10%

192-bench median: +0.20%. Mean: +0.19%. The largest reported regressions are on pure-PUSH micro-benches (synth/PUSH26/PUSH28, ≤ +7.5%, sub-2us, never enter touched code paths).

2. Controlled microbench (narrow vs wide path, same loop shape)

Two hand-crafted EVM bytecodes with identical loop structure — same PUSH/ADD/AND/DUP/PUSH/GT/JUMPI gas costs per iteration. Only difference: the wide control inserts NOT NOT after AND to force the LHS range tag back to U256 (value preserved bit-identically), so both baseline and branch take the U256 fallback path on that variant.

Bench Baseline median Branch median Δ cv (B / Br)
narrow_compare_u64/loop (LHS range U64) 219.49 us 202.46 us −7.76% 0.32 / 0.27
wide_compare_u256_control/loop (LHS range U256, same loop body + 2 NOTs) 218.52 us 217.73 us −0.36% 0.07 / 0.15

Δ — Δ_control = −7.40 pp net signal, isolated to the narrow path. The control shows the bench-harness noise floor is ≤ 0.4%, so the −7.76% on the narrow bench cannot be explained by drift / cache / scheduling.

Microbench bytecodes (26 / 28 bytes):

narrow_compare_u64:        60005b6001018067ffffffffffffffff1661fde8116002575000
wide_compare_u256_control: 60005b60010167ffffffffffffffff1619198061fde8116002575000
                                                              ^^^^ NOT NOT inserted after AND

3. U128 narrow path — currently muted, full unlock pending cfg-join

narrow_compare_u128/loop shows only −1.90% because each EVM loop back-edge re-loads the running value from the stack with Range = U256, so commit c0ae6aa's U128 fast path fires only on the first iteration. The full U128 win will be unlocked when perf/value-range-cfg-join (which retrofits analyzer-derived ranges onto stack-popped operands at block entry) lands. The U128 narrow code is correct and dormant today — no regression risk, no behavior change for U256 fallback.

References

  • Change doc: docs/changes/2026-05-12-g4-safe-valuerange/README.md
  • Spec + impl reviews (Opus + Codex R1, both PASS): docs/changes/2026-05-12-g4-safe-valuerange/reviews/
  • Analysis backing this work: docs/research/directions/u256-strength-reduction/analysis/2026-05-12-verified-opportunities.md § 1.G4 (in DTVM-Papers, commit e104583)

Commits in this PR

  • 8b546b3 — producer threading (OR/XOR/SHR_U) + U64 narrow compare consumer
  • c0ae6aa — U128 narrow compare consumer (extends U64 fast path to U128 tier; full win pending cfg-join)
  • ad82eb5 — refactor cleanup from /simplify review (drop maxRange helper for std::max; drop cargo-cult nullptr init; trim comments; document ValueRange enum ordering invariant)

Test plan

  • CI Performance Regression Check (multipass) for ad82eb5 — pending; previous c0ae6aa run passed (median +0.20%, snailtracer −3.40%)
  • CI Performance Regression Check (interpreter) for ad82eb5 — pending
  • Test DTVM-EVM multipass evmtestsuite with gas register in release mode for ad82eb5 — pending
  • Test DTVM-EVM multipass and interpreter using evmone statetests in release mode for ad82eb5 — pending
  • Test DTVM-EVM multipass and interpreter using evmone unit tests in release mode for ad82eb5 — pending
  • Full CI green for ad82eb5 — pending
  • No new clang-tidy warnings in evm_mir_compiler.{cpp,h} (manual confirm by reviewer)

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 12, 2026 08:29
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

Note

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

Extends monotone-safe ValueRange propagation through additional MIR builder sites to preserve U64/U128 ranges longer, and uses those annotations to simplify certain U64 compare helpers.

Changes:

  • Thread ValueRange through OR/XOR results (u64-const fast path and general path) using a monotone join (max).
  • Thread ValueRange through SHR_U (unsigned right shift) by carrying the shifted value’s range.
  • Optimize U64-constant compare helpers by skipping upper-limb OR-folds/selects when the wide operand is tagged ValueRange::U64.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

File Description
src/compiler/evm_frontend/evm_mir_compiler.h Adds a range-join helper and preserves ranges through OR/XOR and SHR_U producers.
src/compiler/evm_frontend/evm_mir_compiler.cpp Adds U64-range fast paths for EQ/LT/GT helpers to avoid redundant upper-limb checks.
docs/changes/2026-05-12-g4-safe-valuerange/README.md Documents the change, invariants, and trust-chain considerations.
docs/changes/2026-05-12-g4-safe-valuerange/reviews/* Adds review artifacts for spec + implementation.

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

Comment thread docs/changes/2026-05-12-g4-safe-valuerange/README.md Outdated
Comment thread src/compiler/evm_frontend/evm_mir_compiler.cpp
Comment thread src/compiler/evm_frontend/evm_mir_compiler.h Outdated
@abmcar abmcar changed the title perf(compiler): thread ValueRange through OR/XOR/SHR_U and skip OR-fold in U64 compares perf(compiler): thread ValueRange through OR/XOR/SHR_U + narrow U64/U128 compare paths May 12, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 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 2.60 2.61 +0.2% PASS
total/main/blake2b_huff/empty 0.04 0.04 -0.0% PASS
total/main/blake2b_shifts/8415nulls 21.47 20.80 -3.1% PASS
total/main/sha1_divs/5311 8.58 8.57 -0.2% PASS
total/main/sha1_divs/empty 0.11 0.11 +0.1% PASS
total/main/sha1_shifts/5311 6.36 6.36 -0.1% PASS
total/main/sha1_shifts/empty 0.08 0.08 -0.0% PASS
total/main/snailtracer/benchmark 76.27 75.53 -1.0% PASS
total/main/structarray_alloc/nfts_rank 1.40 1.39 -0.7% PASS
total/main/swap_math/insufficient_liquidity 0.00 0.00 +0.2% PASS
total/main/swap_math/received 0.01 0.01 +0.0% PASS
total/main/swap_math/spent 0.01 0.01 +0.5% PASS
total/main/weierstrudel/1 0.29 0.29 +0.9% PASS
total/main/weierstrudel/15 3.22 3.23 +0.3% PASS
total/micro/JUMPDEST_n0/empty 2.85 2.85 -0.0% PASS
total/micro/jump_around/empty 0.09 0.09 +0.7% PASS
total/micro/loop_with_many_jumpdests/empty 43.49 43.50 +0.0% PASS
total/micro/memory_grow_mload/by1 0.12 0.13 +3.9% PASS
total/micro/memory_grow_mload/by16 0.14 0.13 -2.6% PASS
total/micro/memory_grow_mload/by32 0.15 0.14 -1.2% PASS
total/micro/memory_grow_mload/nogrow 0.13 0.13 -1.7% PASS
total/micro/memory_grow_mstore/by1 0.12 0.13 +1.3% PASS
total/micro/memory_grow_mstore/by16 0.13 0.13 +0.1% PASS
total/micro/memory_grow_mstore/by32 0.15 0.15 -0.3% PASS
total/micro/memory_grow_mstore/nogrow 0.12 0.12 +0.6% PASS
total/micro/signextend/one 0.28 0.28 -0.0% PASS
total/micro/signextend/zero 0.28 0.28 -0.4% PASS
total/synth/ADD/b0 3.16 3.19 +0.7% PASS
total/synth/ADD/b1 3.82 3.81 -0.1% PASS
total/synth/ADDRESS/a0 4.88 4.88 -0.0% PASS
total/synth/ADDRESS/a1 5.35 5.35 +0.0% PASS
total/synth/AND/b0 3.08 3.10 +0.8% PASS
total/synth/AND/b1 3.68 3.64 -1.0% PASS
total/synth/BYTE/b0 6.19 6.19 -0.0% PASS
total/synth/BYTE/b1 5.14 5.11 -0.5% PASS
total/synth/CALLDATASIZE/a0 3.51 3.51 +0.0% PASS
total/synth/CALLDATASIZE/a1 3.56 3.56 -0.1% PASS
total/synth/CALLER/a0 4.81 4.81 -0.1% PASS
total/synth/CALLER/a1 5.32 5.32 -0.1% PASS
total/synth/CALLVALUE/a0 3.75 3.75 -0.0% PASS
total/synth/CALLVALUE/a1 3.77 3.76 -0.3% PASS
total/synth/CODESIZE/a0 3.99 4.00 +0.0% PASS
total/synth/CODESIZE/a1 4.01 4.00 -0.3% PASS
total/synth/DUP1/d0 1.39 1.39 -0.0% PASS
total/synth/DUP1/d1 1.76 1.76 -0.2% PASS
total/synth/DUP10/d0 1.39 1.39 +0.1% PASS
total/synth/DUP10/d1 1.73 1.73 +0.1% PASS
total/synth/DUP11/d0 1.39 1.39 +0.0% PASS
total/synth/DUP11/d1 1.73 1.73 +0.1% PASS
total/synth/DUP12/d0 1.39 1.39 +0.1% PASS
total/synth/DUP12/d1 1.73 1.73 +0.1% PASS
total/synth/DUP13/d0 1.39 1.39 +0.0% PASS
total/synth/DUP13/d1 1.73 1.73 -0.0% PASS
total/synth/DUP14/d0 1.15 1.39 +20.6% PASS
total/synth/DUP14/d1 1.73 1.74 +0.1% PASS
total/synth/DUP15/d0 1.39 1.39 -0.0% PASS
total/synth/DUP15/d1 1.73 1.73 +0.0% PASS
total/synth/DUP16/d0 1.39 1.16 -17.0% PASS
total/synth/DUP16/d1 1.74 1.73 -0.2% PASS
total/synth/DUP2/d0 1.39 1.15 -17.4% PASS
total/synth/DUP2/d1 1.73 1.73 -0.1% PASS
total/synth/DUP3/d0 1.39 1.39 -0.0% PASS
total/synth/DUP3/d1 1.73 1.73 -0.1% PASS
total/synth/DUP4/d0 1.39 1.26 -9.4% PASS
total/synth/DUP4/d1 1.73 1.73 -0.1% PASS
total/synth/DUP5/d0 1.39 1.15 -17.4% PASS
total/synth/DUP5/d1 1.74 1.73 -0.5% PASS
total/synth/DUP6/d0 1.39 1.34 -3.4% PASS
total/synth/DUP6/d1 1.73 1.73 -0.2% PASS
total/synth/DUP7/d0 1.39 1.39 -0.0% PASS
total/synth/DUP7/d1 1.73 1.73 -0.1% PASS
total/synth/DUP8/d0 1.39 1.39 +0.0% PASS
total/synth/DUP8/d1 1.73 1.73 -0.1% PASS
total/synth/DUP9/d0 1.39 1.39 -0.1% PASS
total/synth/DUP9/d1 1.73 1.73 +0.0% PASS
total/synth/EQ/b0 5.37 5.37 +0.0% PASS
total/synth/EQ/b1 5.59 5.59 -0.0% PASS
total/synth/GAS/a0 3.92 3.92 -0.1% PASS
total/synth/GAS/a1 4.01 3.97 -0.9% PASS
total/synth/GT/b0 5.38 5.38 -0.1% PASS
total/synth/GT/b1 5.36 5.36 +0.1% PASS
total/synth/ISZERO/u0 8.34 8.34 +0.0% PASS
total/synth/JUMPDEST/n0 2.85 2.85 -0.1% PASS
total/synth/LT/b0 5.39 5.38 -0.1% PASS
total/synth/LT/b1 5.36 5.36 -0.0% PASS
total/synth/MSIZE/a0 4.33 4.33 -0.1% PASS
total/synth/MSIZE/a1 4.84 4.84 -0.0% PASS
total/synth/MUL/b0 5.50 5.49 -0.1% PASS
total/synth/MUL/b1 5.93 5.91 -0.3% PASS
total/synth/NOT/u0 4.87 4.87 -0.1% PASS
total/synth/OR/b0 3.02 3.02 -0.0% PASS
total/synth/OR/b1 3.65 3.62 -0.8% PASS
total/synth/PC/a0 3.51 3.51 -0.1% PASS
total/synth/PC/a1 3.56 3.55 -0.4% PASS
total/synth/PUSH1/p0 1.39 1.39 +0.0% PASS
total/synth/PUSH1/p1 1.82 1.82 -0.0% PASS
total/synth/PUSH10/p0 1.39 1.39 +0.1% PASS
total/synth/PUSH10/p1 1.82 1.83 +0.6% PASS
total/synth/PUSH11/p0 1.40 1.40 -0.3% PASS
total/synth/PUSH11/p1 1.83 1.83 +0.0% PASS
total/synth/PUSH12/p0 1.39 1.40 +0.1% PASS
total/synth/PUSH12/p1 1.83 1.83 +0.4% PASS
total/synth/PUSH13/p0 1.39 1.40 +0.1% PASS
total/synth/PUSH13/p1 1.82 1.82 +0.1% PASS
total/synth/PUSH14/p0 1.43 1.44 +0.3% PASS
total/synth/PUSH14/p1 1.83 1.84 +0.6% PASS
total/synth/PUSH15/p0 1.40 1.40 -0.1% PASS
total/synth/PUSH15/p1 1.91 1.89 -1.1% PASS
total/synth/PUSH16/p0 1.40 1.40 +0.0% PASS
total/synth/PUSH16/p1 1.83 1.83 +0.0% PASS
total/synth/PUSH17/p0 1.40 1.40 +0.2% PASS
total/synth/PUSH17/p1 1.83 1.83 +0.3% PASS
total/synth/PUSH18/p0 1.40 1.39 -0.1% PASS
total/synth/PUSH18/p1 1.83 1.86 +1.6% PASS
total/synth/PUSH19/p0 1.40 1.39 -0.1% PASS
total/synth/PUSH19/p1 1.83 1.87 +2.1% PASS
total/synth/PUSH2/p0 1.39 1.39 -0.1% PASS
total/synth/PUSH2/p1 1.82 1.82 -0.2% PASS
total/synth/PUSH20/p0 1.40 1.40 +0.1% PASS
total/synth/PUSH20/p1 1.83 1.83 -0.1% PASS
total/synth/PUSH21/p0 1.40 1.39 -0.1% PASS
total/synth/PUSH21/p1 1.83 1.84 +0.4% PASS
total/synth/PUSH22/p0 1.39 1.40 +0.4% PASS
total/synth/PUSH22/p1 1.83 1.87 +1.9% PASS
total/synth/PUSH23/p0 1.40 1.39 -0.1% PASS
total/synth/PUSH23/p1 1.83 1.84 +0.4% PASS
total/synth/PUSH24/p0 1.40 1.40 -0.1% PASS
total/synth/PUSH24/p1 1.83 1.84 +0.2% PASS
total/synth/PUSH25/p0 1.39 1.39 +0.0% PASS
total/synth/PUSH25/p1 1.83 1.83 -0.1% PASS
total/synth/PUSH26/p0 1.40 1.40 +0.2% PASS
total/synth/PUSH26/p1 1.83 1.84 +0.6% PASS
total/synth/PUSH27/p0 1.40 1.40 -0.0% PASS
total/synth/PUSH27/p1 1.83 1.85 +1.4% PASS
total/synth/PUSH28/p0 1.39 1.40 +0.1% PASS
total/synth/PUSH28/p1 1.84 1.83 -0.2% PASS
total/synth/PUSH29/p0 1.39 1.40 +0.1% PASS
total/synth/PUSH29/p1 1.83 1.84 +0.7% PASS
total/synth/PUSH3/p0 1.39 1.40 +0.1% PASS
total/synth/PUSH3/p1 1.82 1.82 -0.0% PASS
total/synth/PUSH30/p0 1.48 1.60 +8.1% PASS
total/synth/PUSH30/p1 1.85 1.85 -0.1% PASS
total/synth/PUSH31/p0 1.40 1.39 -0.0% PASS
total/synth/PUSH31/p1 1.95 2.00 +2.9% PASS
total/synth/PUSH32/p0 1.39 1.41 +0.9% PASS
total/synth/PUSH32/p1 1.85 1.83 -0.9% PASS
total/synth/PUSH4/p0 1.40 1.39 -0.1% PASS
total/synth/PUSH4/p1 1.83 1.82 -0.2% PASS
total/synth/PUSH5/p0 1.39 1.39 -0.0% PASS
total/synth/PUSH5/p1 1.82 1.82 +0.1% PASS
total/synth/PUSH6/p0 1.39 1.39 +0.0% PASS
total/synth/PUSH6/p1 1.86 1.86 +0.2% PASS
total/synth/PUSH7/p0 1.39 1.39 -0.0% PASS
total/synth/PUSH7/p1 1.85 1.83 -1.2% PASS
total/synth/PUSH8/p0 1.40 1.40 -0.0% PASS
total/synth/PUSH8/p1 1.83 1.83 -0.1% PASS
total/synth/PUSH9/p0 1.39 1.39 +0.1% PASS
total/synth/PUSH9/p1 1.83 1.83 -0.1% PASS
total/synth/RETURNDATASIZE/a0 4.08 4.08 -0.0% PASS
total/synth/RETURNDATASIZE/a1 4.09 4.08 -0.2% PASS
total/synth/SAR/b0 4.03 4.23 +5.0% PASS
total/synth/SAR/b1 4.64 5.06 +9.0% PASS
total/synth/SGT/b0 4.60 4.60 +0.1% PASS
total/synth/SGT/b1 4.13 4.13 -0.0% PASS
total/synth/SHL/b0 3.61 3.62 +0.2% PASS
total/synth/SHL/b1 3.77 3.74 -0.7% PASS
total/synth/SHR/b0 3.40 3.38 -0.5% PASS
total/synth/SHR/b1 3.69 3.71 +0.5% PASS
total/synth/SIGNEXTEND/b0 3.43 3.43 +0.0% PASS
total/synth/SIGNEXTEND/b1 3.82 3.81 -0.1% PASS
total/synth/SLT/b0 4.29 4.29 +0.0% PASS
total/synth/SLT/b1 4.12 4.13 +0.3% PASS
total/synth/SUB/b0 3.17 3.17 -0.1% PASS
total/synth/SUB/b1 3.79 3.79 -0.0% PASS
total/synth/SWAP1/s0 3.34 3.34 -0.0% PASS
total/synth/SWAP10/s0 3.36 3.39 +1.2% PASS
total/synth/SWAP11/s0 3.36 3.36 +0.2% PASS
total/synth/SWAP12/s0 3.36 3.37 +0.2% PASS
total/synth/SWAP13/s0 3.36 3.36 -0.0% PASS
total/synth/SWAP14/s0 3.36 3.38 +0.5% PASS
total/synth/SWAP15/s0 3.90 3.91 +0.2% PASS
total/synth/SWAP16/s0 3.37 3.38 +0.3% PASS
total/synth/SWAP2/s0 3.34 3.35 +0.2% PASS
total/synth/SWAP3/s0 3.34 3.34 -0.1% PASS
total/synth/SWAP4/s0 3.35 3.37 +0.6% PASS
total/synth/SWAP5/s0 3.35 3.35 -0.1% PASS
total/synth/SWAP6/s0 3.35 3.36 +0.2% PASS
total/synth/SWAP7/s0 3.35 3.35 +0.0% PASS
total/synth/SWAP8/s0 3.37 3.39 +0.5% PASS
total/synth/SWAP9/s0 3.35 3.35 +0.0% PASS
total/synth/XOR/b0 3.11 3.10 -0.1% PASS
total/synth/XOR/b1 3.66 3.63 -0.9% PASS
total/synth/loop_v1 6.75 6.90 +2.2% PASS
total/synth/loop_v2 6.76 6.74 -0.4% 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.03 1.03 -0.1% PASS
total/main/blake2b_huff/empty 0.02 0.02 -0.6% PASS
total/main/blake2b_shifts/8415nulls 4.91 4.62 -6.0% PASS
total/main/sha1_divs/empty 0.01 0.01 -0.9% PASS
total/main/sha1_shifts/empty 0.01 0.01 +0.4% PASS
total/main/snailtracer/benchmark 35.83 35.22 -1.7% PASS
total/main/structarray_alloc/nfts_rank 0.29 0.28 -1.3% PASS
total/main/swap_math/insufficient_liquidity 0.00 0.00 -0.1% PASS
total/main/swap_math/received 0.00 0.00 -0.9% PASS
total/main/swap_math/spent 0.00 0.00 -2.8% PASS
total/main/weierstrudel/1 0.25 0.25 +0.4% PASS
total/main/weierstrudel/15 2.99 2.99 +0.0% PASS
total/micro/JUMPDEST_n0/empty 0.00 0.00 +1.6% PASS
total/micro/jump_around/empty 0.04 0.04 -2.0% PASS
total/micro/loop_with_many_jumpdests/empty 0.00 0.00 +0.5% PASS
total/micro/memory_grow_mload/by1 0.01 0.01 +0.4% PASS
total/micro/memory_grow_mload/by16 0.01 0.01 +0.1% PASS
total/micro/memory_grow_mload/by32 0.01 0.01 +0.8% PASS
total/micro/memory_grow_mload/nogrow 0.01 0.01 +0.6% PASS
total/micro/memory_grow_mstore/by1 0.01 0.01 +0.1% PASS
total/micro/memory_grow_mstore/by16 0.01 0.01 +0.5% PASS
total/micro/memory_grow_mstore/by32 0.01 0.01 -0.1% PASS
total/micro/memory_grow_mstore/nogrow 0.01 0.01 +0.3% PASS
total/micro/signextend/one 0.09 0.09 -2.4% PASS
total/micro/signextend/zero 0.09 0.09 -1.7% PASS
total/synth/ADD/b0 0.00 0.00 +0.6% PASS
total/synth/ADD/b1 0.00 0.00 +0.2% PASS
total/synth/ADDRESS/a0 0.15 0.15 -0.1% PASS
total/synth/ADDRESS/a1 0.15 0.15 -0.0% PASS
total/synth/AND/b0 0.00 0.00 -3.5% PASS
total/synth/AND/b1 0.00 0.00 -1.5% PASS
total/synth/BYTE/b0 0.00 0.00 +2.6% PASS
total/synth/BYTE/b1 0.00 0.00 -1.3% PASS
total/synth/CALLDATASIZE/a0 0.07 0.07 +0.0% PASS
total/synth/CALLDATASIZE/a1 0.07 0.07 -0.0% PASS
total/synth/CALLER/a0 0.20 0.20 +0.6% PASS
total/synth/CALLER/a1 0.20 0.20 +0.4% PASS
total/synth/CALLVALUE/a0 0.19 0.19 -0.1% PASS
total/synth/CALLVALUE/a1 0.19 0.19 +0.2% PASS
total/synth/CODESIZE/a0 0.07 0.07 +0.0% PASS
total/synth/CODESIZE/a1 0.07 0.07 +0.1% PASS
total/synth/DUP1/d0 0.00 0.00 +1.4% PASS
total/synth/DUP1/d1 0.00 0.00 -2.3% PASS
total/synth/DUP10/d0 0.00 0.00 -1.4% PASS
total/synth/DUP10/d1 0.00 0.00 -0.0% PASS
total/synth/DUP11/d0 0.00 0.00 +1.8% PASS
total/synth/DUP11/d1 0.00 0.00 +0.6% PASS
total/synth/DUP12/d0 0.00 0.00 -2.1% PASS
total/synth/DUP12/d1 0.00 0.00 -1.3% PASS
total/synth/DUP13/d0 0.00 0.00 +1.9% PASS
total/synth/DUP13/d1 0.00 0.00 +2.1% PASS
total/synth/DUP14/d0 0.00 0.00 -1.0% PASS
total/synth/DUP14/d1 0.00 0.00 -2.2% PASS
total/synth/DUP15/d0 0.00 0.00 -0.3% PASS
total/synth/DUP15/d1 0.00 0.00 +1.1% PASS
total/synth/DUP16/d0 0.00 0.00 +3.7% PASS
total/synth/DUP16/d1 0.00 0.00 +1.6% PASS
total/synth/DUP2/d0 0.00 0.00 -1.9% PASS
total/synth/DUP2/d1 0.00 0.00 -1.2% PASS
total/synth/DUP3/d0 0.00 0.00 +0.0% PASS
total/synth/DUP3/d1 0.00 0.00 +0.4% PASS
total/synth/DUP4/d0 0.00 0.00 +0.2% PASS
total/synth/DUP4/d1 0.00 0.00 -0.5% PASS
total/synth/DUP5/d0 0.00 0.00 -0.5% PASS
total/synth/DUP5/d1 0.00 0.00 +0.4% PASS
total/synth/DUP6/d0 0.00 0.00 +0.6% PASS
total/synth/DUP6/d1 0.00 0.00 +0.2% PASS
total/synth/DUP7/d0 0.00 0.00 -1.0% PASS
total/synth/DUP7/d1 0.00 0.00 -0.2% PASS
total/synth/DUP8/d0 0.00 0.00 +0.5% PASS
total/synth/DUP8/d1 0.00 0.00 +3.1% PASS
total/synth/DUP9/d0 0.00 0.00 +0.4% PASS
total/synth/DUP9/d1 0.00 0.00 +4.4% PASS
total/synth/EQ/b0 0.00 0.00 +1.2% PASS
total/synth/EQ/b1 0.00 0.00 -1.4% PASS
total/synth/GAS/a0 0.86 0.86 +0.0% PASS
total/synth/GAS/a1 0.86 0.86 +0.0% PASS
total/synth/GT/b0 0.00 0.00 -1.0% PASS
total/synth/GT/b1 0.00 0.00 +0.8% PASS
total/synth/ISZERO/u0 0.00 0.00 -0.4% PASS
total/synth/JUMPDEST/n0 0.00 0.00 -0.9% PASS
total/synth/LT/b0 0.00 0.00 +3.1% PASS
total/synth/LT/b1 0.00 0.00 +2.0% PASS
total/synth/MSIZE/a0 0.00 0.00 -0.1% PASS
total/synth/MSIZE/a1 0.00 0.00 +0.1% PASS
total/synth/MUL/b0 0.00 0.00 +1.6% PASS
total/synth/MUL/b1 0.00 0.00 +0.6% PASS
total/synth/NOT/u0 0.00 0.00 -0.9% PASS
total/synth/OR/b0 0.00 0.00 +1.5% PASS
total/synth/OR/b1 0.00 0.00 +0.4% PASS
total/synth/PC/a0 0.00 0.00 -1.4% PASS
total/synth/PC/a1 0.00 0.00 +2.5% PASS
total/synth/PUSH1/p0 0.00 0.00 +0.2% PASS
total/synth/PUSH1/p1 0.00 0.00 +0.9% PASS
total/synth/PUSH10/p0 0.00 0.00 -3.5% PASS
total/synth/PUSH10/p1 0.00 0.00 -0.2% PASS
total/synth/PUSH11/p0 0.00 0.00 -1.8% PASS
total/synth/PUSH11/p1 0.00 0.00 -1.3% PASS
total/synth/PUSH12/p0 0.00 0.00 -3.9% PASS
total/synth/PUSH12/p1 0.00 0.00 -1.0% PASS
total/synth/PUSH13/p0 0.00 0.00 -2.7% PASS
total/synth/PUSH13/p1 0.00 0.00 -4.0% PASS
total/synth/PUSH14/p0 0.00 0.00 -1.3% PASS
total/synth/PUSH14/p1 0.00 0.00 -3.6% PASS
total/synth/PUSH15/p0 0.00 0.00 -1.2% PASS
total/synth/PUSH15/p1 0.00 0.00 -2.6% PASS
total/synth/PUSH16/p0 0.00 0.00 -0.7% PASS
total/synth/PUSH16/p1 0.00 0.00 +0.1% PASS
total/synth/PUSH17/p0 0.00 0.00 +0.2% PASS
total/synth/PUSH17/p1 0.00 0.00 +0.1% PASS
total/synth/PUSH18/p0 0.00 0.00 -0.1% PASS
total/synth/PUSH18/p1 0.00 0.00 +1.2% PASS
total/synth/PUSH19/p0 0.00 0.00 -2.1% PASS
total/synth/PUSH19/p1 0.00 0.00 +0.6% PASS
total/synth/PUSH2/p0 0.00 0.00 -1.0% PASS
total/synth/PUSH2/p1 0.00 0.00 -2.7% PASS
total/synth/PUSH20/p0 0.00 0.00 -1.1% PASS
total/synth/PUSH20/p1 0.00 0.00 +0.1% PASS
total/synth/PUSH21/p0 0.00 0.00 -1.3% PASS
total/synth/PUSH21/p1 0.00 0.00 -1.8% PASS
total/synth/PUSH22/p0 1.52 1.51 -1.2% PASS
total/synth/PUSH22/p1 1.81 1.81 -0.2% PASS
total/synth/PUSH23/p0 1.53 1.52 -0.7% PASS
total/synth/PUSH23/p1 1.81 1.81 +0.2% PASS
total/synth/PUSH24/p0 1.53 1.51 -1.1% PASS
total/synth/PUSH24/p1 1.81 1.80 -0.5% PASS
total/synth/PUSH25/p0 1.53 1.51 -1.1% PASS
total/synth/PUSH25/p1 1.81 1.80 -0.8% PASS
total/synth/PUSH26/p0 1.51 1.51 +0.3% PASS
total/synth/PUSH26/p1 1.81 1.81 -0.1% PASS
total/synth/PUSH27/p0 1.51 1.52 +0.3% PASS
total/synth/PUSH27/p1 1.82 1.81 -0.4% PASS
total/synth/PUSH28/p0 1.52 1.51 -0.5% PASS
total/synth/PUSH28/p1 1.88 1.81 -4.0% PASS
total/synth/PUSH29/p0 1.53 1.53 +0.1% PASS
total/synth/PUSH29/p1 1.82 1.80 -1.0% PASS
total/synth/PUSH3/p0 0.00 0.00 +2.2% PASS
total/synth/PUSH3/p1 0.00 0.00 -1.3% PASS
total/synth/PUSH30/p0 1.58 1.52 -3.7% PASS
total/synth/PUSH30/p1 1.81 1.80 -0.7% PASS
total/synth/PUSH31/p0 1.52 1.51 -0.3% PASS
total/synth/PUSH31/p1 1.87 1.84 -1.6% PASS
total/synth/PUSH32/p0 1.52 1.51 -0.5% PASS
total/synth/PUSH32/p1 1.82 1.80 -0.9% PASS
total/synth/PUSH4/p0 0.00 0.00 -1.2% PASS
total/synth/PUSH4/p1 0.00 0.00 +3.5% PASS
total/synth/PUSH5/p0 0.00 0.00 -0.6% PASS
total/synth/PUSH5/p1 0.00 0.00 +2.0% PASS
total/synth/PUSH6/p0 0.00 0.00 -0.8% PASS
total/synth/PUSH6/p1 0.00 0.00 -2.0% PASS
total/synth/PUSH7/p0 0.00 0.00 -0.5% PASS
total/synth/PUSH7/p1 0.00 0.00 +0.9% PASS
total/synth/PUSH8/p0 0.00 0.00 +0.9% PASS
total/synth/PUSH8/p1 0.00 0.00 +0.1% PASS
total/synth/PUSH9/p0 0.00 0.00 +1.2% PASS
total/synth/PUSH9/p1 0.00 0.00 +0.6% PASS
total/synth/RETURNDATASIZE/a0 0.03 0.03 +0.1% PASS
total/synth/RETURNDATASIZE/a1 0.03 0.03 +0.1% PASS
total/synth/SAR/b0 0.00 0.00 +0.1% PASS
total/synth/SAR/b1 0.00 0.00 +0.0% PASS
total/synth/SGT/b0 0.00 0.00 +1.2% PASS
total/synth/SGT/b1 0.00 0.00 +0.0% PASS
total/synth/SHL/b0 0.00 0.00 -1.9% PASS
total/synth/SHL/b1 0.00 0.00 -0.9% PASS
total/synth/SHR/b0 0.00 0.00 -2.6% PASS
total/synth/SHR/b1 0.00 0.00 -3.2% PASS
total/synth/SIGNEXTEND/b0 0.00 0.00 +4.5% PASS
total/synth/SIGNEXTEND/b1 0.00 0.00 -1.4% PASS
total/synth/SLT/b0 0.00 0.00 -0.6% PASS
total/synth/SLT/b1 0.00 0.00 +0.5% PASS
total/synth/SUB/b0 0.00 0.00 +0.0% PASS
total/synth/SUB/b1 0.00 0.00 +2.5% PASS
total/synth/SWAP1/s0 0.00 0.00 +1.5% PASS
total/synth/SWAP10/s0 0.00 0.00 +0.4% PASS
total/synth/SWAP11/s0 0.00 0.00 -2.7% PASS
total/synth/SWAP12/s0 0.00 0.00 -0.6% PASS
total/synth/SWAP13/s0 0.00 0.00 +4.0% PASS
total/synth/SWAP14/s0 0.00 0.00 -1.8% PASS
total/synth/SWAP15/s0 0.00 0.00 +3.5% PASS
total/synth/SWAP16/s0 0.00 0.00 -0.2% PASS
total/synth/SWAP2/s0 0.00 0.00 +2.2% PASS
total/synth/SWAP3/s0 0.00 0.00 -0.5% PASS
total/synth/SWAP4/s0 0.00 0.00 -0.9% PASS
total/synth/SWAP5/s0 0.00 0.00 -1.3% PASS
total/synth/SWAP6/s0 0.00 0.00 -1.5% PASS
total/synth/SWAP7/s0 0.00 0.00 +2.1% PASS
total/synth/SWAP8/s0 0.00 0.00 +2.9% PASS
total/synth/SWAP9/s0 0.00 0.00 -1.1% PASS
total/synth/XOR/b0 0.00 0.00 +0.5% PASS
total/synth/XOR/b1 0.00 0.00 -0.6% PASS
total/synth/loop_v1 1.71 1.66 -3.0% PASS
total/synth/loop_v2 1.60 1.63 +1.8% PASS

Summary: 192 benchmarks, 0 regressions


abmcar added a commit to abmcar/DTVM that referenced this pull request May 13, 2026
Cleanup pass on PR DTVMStack#499 from /simplify review:

- Drop the Operand::maxRange one-line helper; use std::max at the single
  call site to match the existing std::min precedent for AND narrowing.
- Add a "ordering is load-bearing" invariant note above the ValueRange
  enum to guard against silent breakage from future reorderings.
- Drop the defensive `MInstruction *FinalResult = nullptr;` init in the
  three compare helpers; the if/else-if/else cascade already assigns on
  every path, and removing the nullptr lets the compiler warn loudly if a
  future branch addition skips assignment.
- Trim Phase 5 OR/XOR comment from 3 lines to 1 (the AND-returns-earlier
  half is already encoded by the if constexpr guard).
- Drop the WHAT-style trailing comments in the U256 fallback paths
  ("// Final: low matches AND upper is zero", "// result = hasUpper ? ...")
  that restate the next assignment.

No behavior change. Local validation: format clean, dtvmapi builds, 223 /
223 multipass unittests pass. Statetest skipped (diff is structurally
equivalent — only comment/init/helper-naming changes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
abmcar added a commit to abmcar/DTVM that referenced this pull request May 15, 2026
- Static-assert ValueRange enum ordering (U64 < U128 < U256) so the
  std::min/std::max contract in AND/OR/XOR can't be silently broken.
- Add isLiteralZero debug helper and assert it on the upper limbs of
  the U64/U128 fast paths in handleCompareEqU64, handleCompareLtRhsU64,
  handleCompareGtRhsU64 — promotes the producer-side invariant from
  prose to a runtime check (ZEN_ASSERT, zero cost in release).
- Fix README wording: 4-limb OR-fold -> 3-upper-limb OR-fold.

Addresses Copilot review on DTVMStack#499.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
abmcar and others added 5 commits May 15, 2026 20:24
…ld in U64 compares

Extend the monotone-safe subset of G4 ValueRange propagation:

- handleBitwiseOp<BO_OR|BO_XOR> Phase 1 u64-const fast path now carries
  OtherOp.getRange() (limbs[1..3] pass through as identical MInstruction
  pointers, so the value-range claim is preserved bit-identically).
- handleBitwiseOp<BO_OR|BO_XOR> Phase 5 general path now carries
  max(LHS.range, RHS.range) — OR/XOR are monotone joins on bit width.
  AND is excluded (its monotone direction is min, already handled by its
  own earlier returns).
- handleShift<BO_SHR_U> now carries ValueOp.getRange() — unsigned right
  shift cannot widen. SHL widens; SHR_S sign-fills; both keep U256.
- handleCompareEqU64 / LtRhsU64 / GtRhsU64 skip the 3-upper-limb OR-fold
  and the boolean select when the wide operand carries ValueRange::U64.
  Every existing U64 producer materializes literal MIR zero in
  limbs[1..3], so the new fast path's runtime safety is structural.

Out of scope per docs/research/directions/u256-strength-reduction/
analysis/2026-05-12-verified-opportunities.md §1.G4 verdict: SUB (wraps),
SHL (widens), SAR (sign-fills), ADDMOD/MULMOD (need richer model), EXP,
signed compare.

Validation (worktree g4-safe-valuerange):
- tools/format.sh check: clean
- evmone-unittests multipass run list: 223/223 pass
- evmone-statetest -k fork_Cancun multipass: 2723/2723 pass

Spec + review artifacts: docs/changes/2026-05-12-g4-safe-valuerange/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For LHS operands tagged ValueRange::U128, limbs[2..3] are provably zero
(every existing U128 producer materializes literal MIR Zero in those
positions — see invariant chain in 2026-05-12-g4-safe-valuerange/README.md).
The previous U256 fallback in handleCompareEqU64 / LtRhsU64 / GtRhsU64
emitted a 3-limb OR-fold (LHS[1] | LHS[2] | LHS[3]); for U128 inputs that
collapses to a single LHS[1] vs Zero check.

Per-helper savings vs the U256 fallback path:
- handleCompareEqU64: 2 OR instructions saved (single CMP + AND remains).
- handleCompareLtRhsU64: 2 OR saved (single NE-CMP + Select remains).
- handleCompareGtRhsU64: 2 OR saved (single NE-CMP + Select remains).

Also initialize FinalResult to nullptr in all three helpers as defensive
practice against future branch additions (no behavior change today).

Local validation on g4-safe-valuerange:
- tools/format.sh check clean
- multipass unittests 223/223
- multipass statetest -k fork_Cancun 2723/2723
- 27-bench local ping-pong is too noisy on this machine (baseline drifts
  ~10pp between back-to-back runs); deferring perf judgment to the CI
  multipass regression check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cleanup pass on PR DTVMStack#499 from /simplify review:

- Drop the Operand::maxRange one-line helper; use std::max at the single
  call site to match the existing std::min precedent for AND narrowing.
- Add a "ordering is load-bearing" invariant note above the ValueRange
  enum to guard against silent breakage from future reorderings.
- Drop the defensive `MInstruction *FinalResult = nullptr;` init in the
  three compare helpers; the if/else-if/else cascade already assigns on
  every path, and removing the nullptr lets the compiler warn loudly if a
  future branch addition skips assignment.
- Trim Phase 5 OR/XOR comment from 3 lines to 1 (the AND-returns-earlier
  half is already encoded by the if constexpr guard).
- Drop the WHAT-style trailing comments in the U256 fallback paths
  ("// Final: low matches AND upper is zero", "// result = hasUpper ? ...")
  that restate the next assignment.

No behavior change. Local validation: format clean, dtvmapi builds, 223 /
223 multipass unittests pass. Statetest skipped (diff is structurally
equivalent — only comment/init/helper-naming changes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Static-assert ValueRange enum ordering (U64 < U128 < U256) so the
  std::min/std::max contract in AND/OR/XOR can't be silently broken.
- Add isLiteralZero debug helper and assert it on the upper limbs of
  the U64/U128 fast paths in handleCompareEqU64, handleCompareLtRhsU64,
  handleCompareGtRhsU64 — promotes the producer-side invariant from
  prose to a runtime check (ZEN_ASSERT, zero cost in release).
- Fix README wording: 4-limb OR-fold -> 3-upper-limb OR-fold.

Addresses Copilot review on DTVMStack#499.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@abmcar abmcar force-pushed the g4-safe-valuerange branch from 33db54c to 8e0cd91 Compare May 15, 2026 12:27
The isLiteralZero ZEN_ASSERTs in the U64/U128 compare fast paths were
checking a producer-side structural invariant ("upper limbs are literal
MIR Zero constants"). PR DTVMStack#493 (EVMRangeAnalyzer cfg-join) widened the
Range contract from "literal-zero MIR" to "value-level zero" — the
analyzer now retrofits Range = U64 onto operands whose backing variables
hold any MIR that evaluates to a u64-fitting value. The old assertions
fired on analyzer-narrowed operands and crashed the JIT (CI hit SIGABRT
on stEIP1153_transientStorage.transStorageReset).

Remove the helper and the six ZEN_ASSERTs; the surrounding comments now
say "value-zero by Range contract" instead of "provably zero (literal
MIR)". The fast paths themselves are unchanged and still correct under
the new contract — they read Range and elide reading upper limbs, which
is sound for both producer-direct and analyzer-derived U64 tags.

Update the change-doc's "Invariant chain" section to reflect the two
producer paths (direct materialization + analyzer narrowing) now in
effect, instead of the old "today vs. with-cfg-join" framing.

Local validation: format clean, dtvmapi builds, 223/223 multipass
unittests pass, 2723/2723 statetest -k fork_Cancun pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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