Files
revive/CLAUDE.md
T
98d818f958 The new Yul optimizer toolkit (#519)
This PR introduces powerful code size optimizations. This is achieved
with an additional IR layer in between Yul and LLVM IR. It works quite
well (see below for a comparison) because it captures optimization gains
that neither solc nor LLVM can realize.

The feature is gated behind `--newyork` or a corresponding standard JSON
input setting and **off by default**.

### How it works

We implemented an SSA IR modelled after or inspired by the [MLIR SCF
dialect](https://mlir.llvm.org/docs/Dialects/SCFDialect/). Yul is
translated into this IR and the IR implements mainly the following
optimizations:

- **Type narrowing**: narrows 256-bit values to I1..I160 where provable
(bidirectional + interprocedural), so LLVM emits native 32/64-bit ops
instead
    of software 256-bit arithmetic.
- **FMP range proof**: exposes the `mload(0x40) < heap_size` bound to
LLVM
IPSCCP, eliminating trailing overflow checks on FMP-derived offsets.
Single
    largest code-size contributor.
- **Heap analysis**: skips big-endian byte-swaps where native
little-endian
    layout is safe.
  - **mem_opt / keccak fusion+folding**, **compound outlining** (mapping
sload/sstore), **guard narrowing**, **inlining** tuned for PolkaVM, and
    **exact + fuzzy function dedup**.

### Results
The optimizations implemented with the newyork IR bring substantial code
size improvements.
  - Integration contracts: approximately **-20% to -50%** code size.
  - OpenZeppelin Wizard corpus: around **-47%** code size.

This table shows the code size improvements on various OpenZeppelin ERC
implementations, taken from their [contracts
wizard](https://wizard.openzeppelin.com/), with almost all features
enabled.

| Contract | Default: (bytes) | With `--newyork`: (bytes) | Reduction |
|---|---:|---:|---:|
| erc1155 | 59,206 | 30,649 | -48.2% |
| erc20 | 81,697 | 42,893 | -47.5% |
| erc721 | 92,052 | 49,423 | -46.3% |
| oz_gov | 141,861 | 81,159 | -42.8% |
| oz_rwa | 77,274 | 37,975 | -50.9% |
| oz_simple_erc20 | 29,950 | 16,554 | -44.7% |
| oz_stable | 82,117 | 39,032 | -52.5% |
| **Total** | **564,157** | **297,685** | **-47.2%** |

We believe this to be a reasonably representative dataset and conclude
that the newyork IR achieves drastic code size reductions on real world
dApp implementations.

### Methodology, security and runtime performance

Since the main contributors to these improvements are the FMP range
proofs and the type narrowing, we don't expect big runtime performance
regressions (it may even benefit runtime performance in some cases).

The PR also includes docs
(`book/src/developer_guide/newyork_{optimizer,ir}.md`) and many new
integration tests, including regression tests for known FMP soundness
traps.

The PR was authored collaboratively and reviewed extensively by the
`revive` maintainers, as well as Claude Opus, Claude Fable, Qwen,
Minimax and Deepseek LLMs, over a span of many months.

The `newyork` compiler pipeline introduces no new regressions over our
integration and differential test suites (containing over 30000 test
cases). This was achieved by careful manual reviews and many LLM bughunt
loops. Additionally, a final security review by Anthropic's Fable 5 LLM
found no remaining soundness issues. Nonetheless, like any brand new
software, please consider this an experimental feature upon release.

---------

Signed-off-by: xermicus <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: neo <me@90f9.org>
Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
2026-06-17 12:35:16 +02:00

4.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Revive is a Solidity compiler targeting RISC-V on PolkaVM. It uses solc (Ethereum Solidity compiler) as the frontend and LLVM as the backend. The main compiler binary is resolc.

Compilation pipeline:

  1. solc lowers Solidity source to Yul IR
  2. revive lowers Yul IR to LLVM IR
  3. LLVM optimizes and emits RISC-V ELF via LLD
  4. PolkaVM linker creates the final PolkaVM blob

Build Commands

Prerequisites: Requires LLVM_SYS_221_PREFIX environment variable pointing to a compatible LLVM 18.1.8 build. Download from releases or build with make install-llvm.

# Install resolc binary
make install-bin

# Run all quality checks (format, clippy, machete, tests)
make test

# Individual test targets
make test-workspace      # All workspace tests (excludes llvm-builder)
make test-integration    # Integration tests (requires resolc + geth evm tool)
make test-resolc         # resolc package tests
make test-yul            # Yul parser tests

# Linting
make format              # Check formatting (cargo fmt --all --check)
make clippy              # Run clippy with --deny warnings

For verifying work, claiming a task done, or pre-commit checks: only ever run make test* targets — never raw cargo test. Integration and resolc tests invoke the installed resolc binary as a subprocess. Each make test* target already declares install-bin (or install) as a dependency, so it always rebuilds and installs a fresh binary before running tests. Raw cargo test does not — it builds the test binary but leaves system resolc stale, so it passes against code the test isn't actually exercising. That mismatch is exactly why raw cargo test is an anti-pattern for validation.

The one legitimate exception is actively debugging a single test for fast iteration: run make install-bin first to refresh the binary, then iterate with cargo test --package <crate> <test_name>, re-running make install-bin between code changes. Never use this exception for validation.

Crate Architecture

All crates live in crates/. Key crates:

  • resolc - Compiler driver binary and library; orchestrates the full pipeline
  • revive-yul - Yul lexer, parser, and LLVM IR lowering; implements visitor pattern for AST traversal
  • revive-llvm-context - LLVM code generation logic (decoupled from parser)
  • revive-linker - Links RISC-V ELF to PolkaVM blob via LLD and polkavm-linker
  • revive-runner - Executes contracts in simulated pallet-revive runtime; provides declarative test spec format
  • revive-integration - Integration test cases using revive-runner
  • revive-differential - Differential testing utilities against EVM
  • revive-runtime-api - Low-level runtime API bindings to pallet-revive
  • revive-stdlib - Compiler standard library components
  • revive-common - Shared constants and utilities
  • lld-sys - FFI bindings to LLVM's LLD linker

Testing Strategy

Integration tests use differential testing against the Ethereum solc/EVM stack. Test specs are declarative JSON that define contract actions:

{
    "differential": true,
    "actions": [
        {"Instantiate": {"code": {"Solidity": {"contract": "ContractName"}}}},
        {"Call": {"dest": {"Instantiated": 0}, "data": "..."}}
    ]
}

When differential: true, actions run on both EVM and PVM, asserting identical state changes.

Running integration tests requires the evm tool from go-ethereum in $PATH.

Code Style Requirements

  • Use BTreeMap instead of HashMap for deterministic iteration (reproducible builds)
  • Avoid magic numbers/strings; use module constants
  • Avoid abbreviated names; use meaningful, readable symbols
  • No unnecessary macros
  • Avoid import aliasing; use parent/qualified paths for conflicts
  • Public items must have doc comments
  • Comments should provide semantic meaning, not restate code

Dependencies

  • Add as workspace dependencies in root Cargo.toml
  • Avoid pinning when possible
  • Always include Cargo.lock in PRs
  • Don't run cargo update with other changes (separate PR)