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>
Prevents unused functions in the emitted ELF object. Drive-by add a
missing test case (which misses a relocation under `-Oz` when all
internal functions are marked as private).
---------
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
A maintainable and more precise version of what was a hacky but useful
script, exploring the compilers YUL lowering unit.
It analyzes a given shared objects from the debug dump and outputs:
- The count of each YUL statement translated.
- A per YUL statement break-down of bytecode size contributed per.
- Estimated `yul-phaser` cost parameters.
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
- Factor the YUL crate out of `revive-solidity`.
- `revive-solidity` is in reality not a Solidity implementation but the
revive solidity compiler driver (`resolc`). By renaming we not only get
this straight but also a binary with the same name as the crate which
should be less confusing.
---------
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Make the installation of `revive-runner` easier:
- Use locked dependencies to avoid issues with downstream crates
- Make the llvm-context crate an optional dependency to the runner
- Add it to the default `test` target ensuring that this actually works
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This pull request adds changes described in **this comment**:
- `.github/scripts/json_generator.py` - a small script that generates
several json files for different platforms.
-
[generate_versions.yml](https://github.com/paritytech/revive/compare/as-release-json?expand=1#diff-2aee05b96020ac60943e6dfcb30597e53898f31542aeb570468b970d9a13a5a6)
- the workflow that runs when release is published, creates info.json
files and pushes them into resolc-bin repo
- `js/build.js` is adjusted in order to set `RESOLC_WASM_URI` from env
variable
- ⚠️ Release workflow is changed:
- In PRs and main branch it'll only build artifacts
- Release will happen automatically only on the `v*` tag push. This is
needed for revive_web.js to have the necessary `RESOLC_WASM_URI`
- workflow will check that version in Cargo.toml is the same as the tag
when the new tag is pushed
cc https://github.com/paritytech/revive/issues/162
cc https://github.com/paritytech/devops/issues/3890
We only need LLD for cross compilation. This significantly reduces the LLVM build times in a cross compilation scenario. Update the README as a drive-by.
- Move the emscripten target flags into the target configuration.
- Improve the readability of the Makefile.
Signed-off-by: xermicus <cyrill@parity.io>
Pre-eliminary support for LLVM releases and resolc binary releases by streamlining the build process for all supported hosts platforms.
- Introduce the revive-llvm-builder crate with the revive-llvm builder utilty.
- Do not rely on the LLVM dependency in $PATH to decouple the system LLVM installation from the LLVM host dependency.
- Fix the emscripten build by decoupling the host and native LLVM dependencies. Thus allowing a single LLVM emscripten release that can be used on any host platform.
- An example Dockerfile building an alpine container with a fully statically linked resolc ELF binary.
- Remove the Debian builder utilities and workflow.
Makefile: Add target 'install-revive' to build revive with the
installation path specified by variable REVIVE_INSTALL_DIR.
Add utils directory with scripts for building revive in a container.
Add utils/build-revive.sh taking option argument '-o <install-dir>' to
build revive with the specified install directory.
Add utils/revive-builder-debian.dockerfile to make a docker container
for building revive in a Debian environment.
* feat: streamline bin updates during developement
Description
===========
This PR introduces a way for the 'zksolc' binary
to automatically be updated/copied to '.cargo/bin'
after each build to resolves the issue of having
to manually update the $PATH or each time keep
running `cargo install --path crates/solidity`,
which was a recurring annoyance during testing
and development.
Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>