Skip to content

perf(recursion): size-oriented spill splitting and no RISC-V register cost-per-use in the verifier guest build (57,813,912 rows at inner 2^12) - #2153

Closed
Acentelles wants to merge 22 commits into
a16z:feat/fast-recursionfrom
Acentelles:recursion-guest-codegen-spill-costperuse
Closed

Acentelles wants to merge 22 commits into
a16z:feat/fast-recursionfrom
Acentelles:recursion-guest-codegen-spill-costperuse

Conversation

@Acentelles

Copy link
Copy Markdown
Collaborator

Summary

This PR adds two LLVM options to the guest-codegen build defaults of the recursion verifier guest:

  • -Cllvm-args=-split-spill-mode=size: the register allocator splits live ranges around spills in the mode that minimises code size.
  • -Cllvm-args=-riscv-disable-cost-per-use=true: the RISC-V register allocator stops weighting registers by their encoding cost.

Both go into the same default string as the existing inline threshold, GVN hoisting, DFA jump threading, ExtTSP block placement and no-tail-merging flags, still with one codegen unit. A caller value for ZEROOS_GUEST_RUSTFLAGS still wins, and RECURSION_GUEST_CODEGEN=off restores the stock guest build. This is a host-side source change only: the inner guests, the Jolt proof format and the Akita proof are unchanged.

This PR stacks on #2143. Please review only the last two commits. GitHub also shows #2143's commits until #2143 merges.

Measured effect

These are total trace rows (real plus virtual) of the recursion example's verifier guest, which verifies one Akita proof of an inner Jolt proof.

Both changes together, on this public tree. "Without" is #2143's published head 85bee6f27. "With" is this branch, built from a fresh clone with Akita fetched by Cargo from the pin.

Inner proof Without (#2143) With (this PR) Difference
$2^{12}$ 58,017,123 57,813,912 -203,211
$2^{20}$ 148,001,352 147,659,408 -341,944

Each change alone. These were measured on the equivalent build that uses a local Akita checkout. That build runs a constant 14 rows above the public tree at both sizes, with the same proofs.

Change Inner proof Without With Difference Hosts
-split-spill-mode=size $2^{12}$ 58,017,137 57,927,886 -89,251 Ryzen 9 5900XT, Ryzen 9 5950X
$2^{20}$ 148,001,366 147,794,518 -206,848 same
-riscv-disable-cost-per-use=true (on top of the first) $2^{12}$ 57,927,886 57,813,926 -113,960 Ryzen 9 5950X (two hosts), EPYC 9124, Ryzen 9 7950X
$2^{20}$ 147,794,518 147,659,422 -135,096 same

The Akita proof size is unchanged for each change.

How to reproduce

git clone -b recursion-guest-codegen-spill-costperuse https://github.com/Acentelles/jolt
cd jolt
cargo build --locked --profile ci -p recursion --features akita,field-inline,ntt-inline
target/ci/recursion generate --example fibonacci --workdir wd
RAYON_NUM_THREADS=1 target/ci/recursion trace --embed --expect accept --example fibonacci --workdir wd

This is #2143's command with this branch. Inner $2^{12}$ is the example's default input. The $2^{20}$ figures used the same host-only input override as #2143 (RECURSION_FIB_N=74858), which is not in this branch.

Acentelles and others added 22 commits October 20, 2026 20:14
l3-compression-weights on jolt-akita, the recursion host and the recursion
guest selects Akita's factored evaluation of the compression relation
weights (same field values). Feature-off guests compile byte for byte as
before: only Cargo feature tables and host-only code change.
The recursion example enables l3-compression-weights by default. The feature
forwards weakly (jolt-akita?/l3-compression-weights) and the host adds the
guest feature only together with akita, so Dory builds are unchanged.
--no-default-features turns it off. Host-side Cargo and cfg changes only.
Adds l2-terminal-quotient to jolt-akita (enabling akita-pcs's feature), the
recursion host and the verifier guest, the host's guest-feature line, and a
tamper-l2 tool for the rejection fixtures (quotient flip, noncanonical,
extra, short, response flip). Feature-off guest sources are untouched.
The recursion example enables l2-terminal-quotient by default next to
l3-compression-weights. The feature forwards weakly
(jolt-akita?/l2-terminal-quotient), and the host's guest-feature line, the
tamper-l2 command and its helpers are compiled only together with akita, so
Dory builds are unchanged and Akita builds prove and verify with the
quotient certificate. --no-default-features turns both off. Host-side Cargo
and cfg changes only.
Adds the word-decode and word-transcript features: Fp128 proof elements are
deserialized from fixed 16-byte tuples with register-sized accumulators, and
transcript scalars can be absorbed as whole words. Both are off by default.
The recursion example enables word-decode by default next to the factored
compression weights and the terminal quotient certificate. The feature
forwards weakly (jolt-akita?/word-decode) and the host forwards it to the
guest only together with akita, so Dory builds are unchanged.
--no-default-features turns all three off. Host-side Cargo and cfg changes
only.
The recursion example enables word-memory by default next to the factored
compression weights, the terminal quotient certificate and word decoding.
The host forwards it to the guest only together with akita, so Dory builds
are unchanged. --no-default-features turns all four off. Host-side Cargo and
cfg changes only.
The recursion example's default features use Akita changes that are not in
LayerZero-Labs/akita yet. Pin the Akita crates to the fork commit that carries
them so a fresh checkout builds the measured configuration.
…hold 1000 and one codegen unit by default

The recursion host now builds the verifier guest with
ZEROOS_GUEST_RUSTFLAGS=-Cllvm-args=-inline-threshold=1000 and
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 (new default feature guest-codegen).
The settings apply to the verifier guest build only; the inner guests and
their proofs are unchanged. A value the caller already set for either
variable wins. RECURSION_GUEST_CODEGEN=off, or building without the
feature (--no-default-features), restores the stock guest build. Host-side
Cargo and source changes only.
…to 1750

The guest-codegen default for the recursion verifier guest build moves
from -Cllvm-args=-inline-threshold=1000 to -Cllvm-args=-inline-threshold=1750,
still with one codegen unit. Thresholds of 2000 and above fail to link the
guest. A caller value for ZEROOS_GUEST_RUSTFLAGS still wins, and
RECURSION_GUEST_CODEGEN=off restores the stock guest build. Host-side source
change only; the inner guests and their proofs are unchanged.
…cursion verifier guest build

The guest-codegen default for the recursion verifier guest build adds
-Cllvm-args=-enable-gvn-hoist and -Cllvm-args=-enable-dfa-jump-thread to
-Cllvm-args=-inline-threshold=1750, still with one codegen unit. A caller
value for ZEROOS_GUEST_RUSTFLAGS still wins, and RECURSION_GUEST_CODEGEN=off
restores the stock guest build. Host-side source change only; the inner
guests and their proofs are unchanged.
…he recursion verifier guest build

The guest-codegen default for the recursion verifier guest build adds
-Cllvm-args=-enable-ext-tsp-block-placement and
-Cllvm-args=-enable-tail-merge=false to the existing inline threshold,
GVN hoisting and DFA jump threading flags, still with one codegen unit.
A caller value for ZEROOS_GUEST_RUSTFLAGS still wins, and
RECURSION_GUEST_CODEGEN=off restores the stock guest build. Host-side
source change only; the inner guests and their proofs are unchanged.
The verifier_api test verifies Dory fixtures with VerifierPCS (Dory). With
jolt-sdk's akita feature, jolt_verifier::verify is the Akita path, whose
OneHotTrace metadata bounds Dory does not implement, so the test target
failed to compile (E0277) whenever akita was unified into jolt-sdk, for
example through the recursion example's akita feature. Gate the test to
builds without akita, like verifier_preprocessing_from_prover.
…erifier guest build

The guest-codegen default for the recursion verifier guest build adds
-Cllvm-args=-split-spill-mode=size to the existing inline threshold,
GVN hoisting, DFA jump threading, ExtTSP block placement and no tail
merging flags, still with one codegen unit. A caller value for
ZEROOS_GUEST_RUSTFLAGS still wins, and RECURSION_GUEST_CODEGEN=off
restores the stock guest build. Host-side source change only; the inner
guests and their proofs are unchanged.
…e recursion verifier guest build

The guest-codegen default for the recursion verifier guest build adds
-Cllvm-args=-riscv-disable-cost-per-use=true to the existing inline
threshold, GVN hoisting, DFA jump threading, ExtTSP block placement, no
tail merging and size-oriented spill splitting flags, still with one
codegen unit. A caller value for ZEROOS_GUEST_RUSTFLAGS still wins, and
RECURSION_GUEST_CODEGEN=off restores the stock guest build. Host-side
source change only; the inner guests and their proofs are unchanged.
@Acentelles

Copy link
Copy Markdown
Collaborator Author

Folded into #2143.

@Acentelles Acentelles closed this Oct 26, 2026
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