perf: patch ruint to open-code U256 equality (avoids memcmp)#655
perf: patch ruint to open-code U256 equality (avoids memcmp)#655Qumeric wants to merge 1 commit into
Conversation
3a92135 to
4c9a8f3
Compare
4c9a8f3 to
2fc5839
Compare
|
this is a really good catch but i think we should wait for it to get merged upstream instead of patching here |
|
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. |
|
Oh wow they just addressed it in LLVM: llvm/llvm-project#209738 |
|
nice! i guess we just wait for the next llvm and rust release then |
|
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. |
|
i'll leave that to the judgement of the ruint authors. for 2.1, we're anyways going to add |
ruint'sUintderivesPartialEq, which compares the[u64; LIMBS]limb array; on rv32 that lowers to abcmp/memcmplibcall. Full-stack guest flamegraphs attributed a large share of the remainingmemcmpcost to U256 comparisons in the EVM interpreter (JUMPI/ISZERO/EQand many smaller sites), andis_zeroadditionally materialized aZEROon the stack just to compare against it.This patches ruint (fork
qumeric/uint, branched off thev1.17.2tag the guest resolves) to open-codePartialEqas a branchless limb XOR-accumulate andis_zeroas 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/uintis 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
memcmpoverride #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):U256 equality/
is_zeroturned out far more pervasive than the flamegraph's memcmp-self attribution suggested — the cost was spread across many small call sites plus the uncountedis_zeromaterialization overhead.