Skip to content

perf: patch ruint to open-code U256 equality (avoids memcmp)#655

Draft
Qumeric wants to merge 1 commit into
mainfrom
valery/ruint-inline-eq
Draft

perf: patch ruint to open-code U256 equality (avoids memcmp)#655
Qumeric wants to merge 1 commit into
mainfrom
valery/ruint-inline-eq

Conversation

@Qumeric

@Qumeric Qumeric commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

ruint's Uint derives PartialEq, which compares the [u64; LIMBS] limb array; on rv32 that lowers to a bcmp/memcmp libcall. Full-stack guest flamegraphs attributed a large share of the remaining memcmp cost to U256 comparisons in the EVM interpreter (JUMPI/ISZERO/EQ and many smaller sites), and is_zero additionally materialized a ZERO on the stack just to compare against it.

This patches ruint (fork qumeric/uint, branched off the v1.17.2 tag the guest resolves) to open-code PartialEq as a branchless limb XOR-accumulate and is_zero as a direct limb OR-accumulate. On x86/aarch64 this vectorizes to the same code as the derive; on rv32 it drops the libcall and its length-generic dispatch, and inlines a fixed 4-limb compare at every call site. All 119 upstream ruint tests pass on the fork.

An upstream PR to recmo/uint is here alloy-rs/ruint#604.

I am not sure if we want to merge this PR or wait until it's merged to upstream.

Benchmark results

Measured as the marginal gain on top of the full six-PR stack (which already includes the guest memcmp override #650), so this is the true additional win, not the inflated figure a bare-develop base would show. Single-branch run 28942176920 vs the all-opts base (block 23992138, prove-stark, g7e.2xlarge):

metric base (6 PRs) + this patch delta
execute_metered_insns 698,982,806 672,824,032 −26,158,774 (−3.74%)
rows 1,308,779,167 1,251,889,640 −4.35%
total_cells 63,352,511,270 61,582,827,847 −2.79%
app segments 76 73 −3
total_proof_time_ms 77,832 76,058 −2.28%

U256 equality/is_zero turned out far more pervasive than the flamegraph's memcmp-self attribution suggested — the cost was spread across many small call sites plus the uncounted is_zero materialization overhead.

@Qumeric
Qumeric force-pushed the valery/ruint-inline-eq branch from 3a92135 to 4c9a8f3 Compare July 8, 2026 13:42
Base automatically changed from develop-v2.0.0-rc.3 to main July 9, 2026 00:53
@Qumeric
Qumeric force-pushed the valery/ruint-inline-eq branch from 4c9a8f3 to 2fc5839 Compare July 9, 2026 12:56
@shuklaayush

shuklaayush commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

this is a really good catch but i think we should wait for it to get merged upstream instead of patching here
it might also make sense to open an issue in llvm that the memcmp expansion pass is too conservative because it assumes memory accesses can be misaligned and this isn't the case for things like [u64; 4] which are always naturally aligned
also noting that this isn't an issue when the target supports misaligned access and enables the +unaligned-scalar-mem flag

@Qumeric

Qumeric commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

@shuklaayush

I opened LLVM issue . Would be good if you could check it as I am not very knowledgeable in this area.

I agree we can wait for upstreaming in ruint. Preliminary it looks like they don't mind this change, I will ping them if they will not review in a week.

@Qumeric

Qumeric commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Oh wow they just addressed it in LLVM: llvm/llvm-project#209738

@shuklaayush

Copy link
Copy Markdown
Collaborator

nice! i guess we just wait for the next llvm and rust release then

@Qumeric

Qumeric commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Unfortunately it missed LLVM 23 cutoff by just 3 days, so it will only be included in LLVM 24. Claude's estimate it will get released around March 2027 and will be in first nightly rust in April 2027. So maybe ruint change still makes sense.

@shuklaayush

Copy link
Copy Markdown
Collaborator

i'll leave that to the judgement of the ruint authors. for 2.1, we're anyways going to add +unaligned-scalar-mem so this doesn't matter that much

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