From 1a64d6e724d6215070996c89d6adbb3d747b0b5e Mon Sep 17 00:00:00 2001 From: jotabulacios Date: Wed, 9 Sep 2026 12:46:07 -0300 Subject: [PATCH 1/3] Let the guest's memcpy use unaligned word loads compiler_builtins enables its mem-unaligned feature for x86, aarch64 and bpf only, so on RISC-V every misaligned word inside memcpy and memmove is reassembled with a load, two shifts, an or and a store. This VM does not need that: #864 already builds guests with +unaligned-scalar-mem because the executor byte-assembles an unaligned doubleword host-side at the same one-instruction cost as an aligned one, so the rest of the guest has been emitting unaligned loads since July and only these two functions avoided them. memcpy is the largest leaf in an ethrex block profile at 25.15% of guest cycles, and its biggest caller is rkyv deserializing the witness trie. On the real mainnet block 25368371 this is -8.33% guest cycles, 8 epochs down to 7, -6.33% proving time, -8.57% proof size, -9.47% verify and -4.78% base-field-equivalent cells; keccak and ecsm call counts are unchanged. tooling/ethrex-tests passes 6/6 including the two --ignored cases, and both arms of every A/B verify OK. Unaligned accesses land on the more expensive MEMW table rather than MEMW_A, so prover area was measured rather than assumed. The key is scoped to the guest target, so host builds read the file and take nothing from it. Cargo joins rustflags arrays across ancestor config files, so each guest crate keeps its own flags and gains this one. The feature cannot be reached through -Z build-std-features: that chain only forwards compiler-builtins-mem and no compiler-builtins-mem-unaligned exists. --- .cargo/config.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..c6a3276db --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,13 @@ +# Guest-only build flags. The key is scoped to the guest target, so host builds +# (the prover, the CLI, the tooling) read this file and take nothing from it. +[target.riscv64im-lambda-vm-elf] +# `compiler_builtins` turns its `mem-unaligned` feature on for x86, aarch64 and +# bpf only, so on RISC-V every misaligned word inside `memcpy`/`memmove` is +# reassembled with a load, two shifts, an or and a store. This VM does unaligned +# scalar accesses natively (#864 already builds guests with +# `unaligned-scalar-mem`), so that detour buys nothing: the rest of the guest was +# already emitting unaligned loads and only these two functions avoided them. +# +# Cargo joins `rustflags` arrays across ancestor config files, so each guest +# crate's own `.cargo/config.toml` keeps its flags and gains this one. +rustflags = ["--cfg", "feature=\"mem-unaligned\""] From 6b479e86c50a205cc1b19d8905d6b4975d321691 Mon Sep 17 00:00:00 2001 From: jotabulacios Date: Fri, 11 Sep 2026 17:11:28 -0300 Subject: [PATCH 2/3] Hash the guest cargo config in the ELF cache keys --- .github/workflows/hyperfine.yaml | 4 ++-- .github/workflows/pr_main.yaml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/hyperfine.yaml b/.github/workflows/hyperfine.yaml index b52241fc2..70f99e1d2 100644 --- a/.github/workflows/hyperfine.yaml +++ b/.github/workflows/hyperfine.yaml @@ -40,7 +40,7 @@ jobs: id: cache with: path: ${{ matrix.branch }}_programs/*.elf - key: benchmarks-${{ matrix.branch }}-${{ hashFiles( 'executor/programs/bench/**', 'syscalls/**' ) }} + key: benchmarks-${{ matrix.branch }}-${{ hashFiles( 'executor/programs/bench/**', 'syscalls/**', '.cargo/config.toml' ) }} restore-keys: benchmarks-${{ matrix.branch }}- - name: Setup Rust Environment @@ -56,7 +56,7 @@ jobs: - name: Export benchmark hashes id: export-hashes - run: echo "benchmark-hashes-${{ matrix.branch }}=${{ hashFiles( 'executor/programs/bench/**', 'syscalls/**' ) }}" >> "$GITHUB_OUTPUT" + run: echo "benchmark-hashes-${{ matrix.branch }}=${{ hashFiles( 'executor/programs/bench/**', 'syscalls/**', '.cargo/config.toml' ) }}" >> "$GITHUB_OUTPUT" build-binaries: strategy: diff --git a/.github/workflows/pr_main.yaml b/.github/workflows/pr_main.yaml index 89bff2b03..7fa77ba22 100644 --- a/.github/workflows/pr_main.yaml +++ b/.github/workflows/pr_main.yaml @@ -103,7 +103,7 @@ jobs: path: | executor/program_artifacts/rust executor/shared_target - key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile') }} + key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile', '.cargo/config.toml') }} restore-keys: | rust-elf-artifacts- @@ -275,7 +275,7 @@ jobs: path: | executor/program_artifacts/rust executor/shared_target - key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile') }} + key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile', '.cargo/config.toml') }} restore-keys: | rust-elf-artifacts- @@ -391,7 +391,7 @@ jobs: path: | executor/program_artifacts/rust executor/shared_target - key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile') }} + key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile', '.cargo/config.toml') }} restore-keys: | rust-elf-artifacts- @@ -409,7 +409,7 @@ jobs: uses: actions/cache@v4 with: path: executor/program_artifacts/recursion - key: recursion-elf-artifacts-${{ hashFiles('bench_vs/lambda/**', 'prover/src/**', 'prover/Cargo.toml', 'crypto/**/src/**', 'crypto/**/Cargo.toml', 'executor/src/**', 'executor/Cargo.toml', 'syscalls/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'Makefile') }} + key: recursion-elf-artifacts-${{ hashFiles('bench_vs/lambda/**', 'prover/src/**', 'prover/Cargo.toml', 'crypto/**/src/**', 'crypto/**/Cargo.toml', 'executor/src/**', 'executor/Cargo.toml', 'syscalls/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'Makefile', '.cargo/config.toml') }} restore-keys: | recursion-elf-artifacts- @@ -480,7 +480,7 @@ jobs: path: | executor/program_artifacts/rust executor/shared_target - key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile') }} + key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile', '.cargo/config.toml') }} restore-keys: | rust-elf-artifacts- @@ -508,7 +508,7 @@ jobs: uses: actions/cache@v4 with: path: executor/program_artifacts/recursion - key: recursion-elf-artifacts-${{ hashFiles('bench_vs/lambda/**', 'prover/src/**', 'prover/Cargo.toml', 'crypto/**/src/**', 'crypto/**/Cargo.toml', 'executor/src/**', 'executor/Cargo.toml', 'syscalls/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'Makefile') }} + key: recursion-elf-artifacts-${{ hashFiles('bench_vs/lambda/**', 'prover/src/**', 'prover/Cargo.toml', 'crypto/**/src/**', 'crypto/**/Cargo.toml', 'executor/src/**', 'executor/Cargo.toml', 'syscalls/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'Makefile', '.cargo/config.toml') }} restore-keys: | recursion-elf-artifacts- @@ -564,7 +564,7 @@ jobs: path: | executor/program_artifacts/rust executor/shared_target - key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile') }} + key: rust-elf-artifacts-${{ hashFiles('executor/programs/rust/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'syscalls/**', 'Makefile', '.cargo/config.toml') }} restore-keys: | rust-elf-artifacts- @@ -581,7 +581,7 @@ jobs: uses: actions/cache@v4 with: path: executor/program_artifacts/recursion - key: recursion-elf-artifacts-${{ hashFiles('bench_vs/lambda/**', 'prover/src/**', 'prover/Cargo.toml', 'crypto/**/src/**', 'crypto/**/Cargo.toml', 'executor/src/**', 'executor/Cargo.toml', 'syscalls/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'Makefile') }} + key: recursion-elf-artifacts-${{ hashFiles('bench_vs/lambda/**', 'prover/src/**', 'prover/Cargo.toml', 'crypto/**/src/**', 'crypto/**/Cargo.toml', 'executor/src/**', 'executor/Cargo.toml', 'syscalls/**', 'executor/programs/riscv64im-lambda-vm-elf.json', 'Makefile', '.cargo/config.toml') }} restore-keys: | recursion-elf-artifacts- From d97faba020465838251c02d7965f4bf537804e53 Mon Sep 17 00:00:00 2001 From: jotabulacios Date: Fri, 11 Sep 2026 17:11:38 -0300 Subject: [PATCH 3/3] Note the cfg's reach and its nightly pin --- .cargo/config.toml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index c6a3276db..33342ff82 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,13 +1,12 @@ -# Guest-only build flags. The key is scoped to the guest target, so host builds -# (the prover, the CLI, the tooling) read this file and take nothing from it. +# Guest-only build flags: the key is scoped to the guest target, so host builds +# read this file and take nothing from it. Cargo joins `rustflags` across +# ancestor configs, so each guest crate keeps its own flags and gains this one. [target.riscv64im-lambda-vm-elf] -# `compiler_builtins` turns its `mem-unaligned` feature on for x86, aarch64 and -# bpf only, so on RISC-V every misaligned word inside `memcpy`/`memmove` is -# reassembled with a load, two shifts, an or and a store. This VM does unaligned -# scalar accesses natively (#864 already builds guests with -# `unaligned-scalar-mem`), so that detour buys nothing: the rest of the guest was -# already emitting unaligned loads and only these two functions avoided them. -# -# Cargo joins `rustflags` arrays across ancestor config files, so each guest -# crate's own `.cargo/config.toml` keeps its flags and gains this one. +# `compiler_builtins` turns `mem-unaligned` on for x86, aarch64 and bpf only, so +# on RISC-V `memcpy`/`memmove` reassemble every misaligned word by hand; this VM +# does unaligned scalar accesses natively (#864). The cfg reaches every crate in +# the guest graph, but only `compiler-builtins` reads that name, and it declares +# the value in its own check-cfg. It lives in that crate's `build.rs` with no +# stability guarantee: bumping the `nightly-2026-02-01` pin in the Makefile can +# turn this into a silent no-op. rustflags = ["--cfg", "feature=\"mem-unaligned\""]