Repository navigation
WASM: use relaxed_laneselect for Select in relaxed builds - #20
Merged
Merged
Conversation
FastSIMD masks are all ones or all zeros per lane, so i32x4.relaxed_laneselect matches v128.bitselect and is a single blend on x64 hosts instead of and/andnot/or. Strict builds keep bitselect.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change
In relaxed builds, the WASM
f32x4andi32x4Select(ToolSet/WASM/128/f32x4.h,i32x4.h) now usewasm_i32x4_relaxed_laneselectinstead ofwasm_v128_bitselect. Non relaxed builds still usebitselect, so their code doesn't change.Why
On x64, V8 compiles
v128.bitselecttoand,andnotandor.i32x4.relaxed_laneselectcan use just the top bit of each lane, so V8 compiles it to a singlevblendvps(blendvpswithout AVX). On arm64, V8 compiles both tobsl, so ARM hosts get the same code as before.The relaxed SIMD spec only leaves the result up to the engine when a mask lane is neither all ones nor all zeros. FastSIMD masks are always all ones or all zeros: they come from comparisons and mask logic, and
SelectHighBitbuilds its mask with>> 31. The SSE4.1Select(_mm_blendv_ps) already relies on this.Effect
In FastNoise2 master's WASM object (Emscripten 6.0.12,
-O3 -ffast-math -msimd128 -mrelaxed-simd),v128.bitselectgoes from 1712 to 90 andi32x4.relaxed_laneselectfrom 0 to 1622. The total instruction count stays at 118,596. LLVM emits the 90 bitselects left itself, for example forand/andnotmasking with a comparison. PerGenfunction (2D/3D/4D), bitselect count before → after:I built FastNoise2 master (8c2d080) for WASM against this branch and against FastSIMD master, each linked into a small benchmark that times
GenUniformGrid. I ran it in node 24.19 on a Ryzen 9 7950X, alternating the two builds across 15 node processes each, pinned to one core. Each figure is new/old of the fastest time across processes. Running master against itself the same way gave a geomean of 1.001, with all but one case within 1.5%.The geomean over all 36 cases is 0.954.
An earlier run on a FastNoise2 development branch (2D and 3D, 7 processes, on a busy machine) also gave a geomean of 0.954: Perlin 0.87-0.88, Simplex 0.91-0.92, FBm Simplex 0.92, Value/White/CellularDistance about 1.00. On that branch bitselect went from 3966 to 98.
I didn't measure on an ARM host, since node isn't installed on my M1. Going by V8's arm64 instruction selection, the code there is the same as before.
Testing
f32 select,f32 select high bit,f32 masked mul,f32 inv masked mul,f32 operators keep lhs, and the trig tests that go throughSelect(acos, asin, atan, atan2, cos, sin, tan).i32 select,i32 select int mask,i32 select high bit,i32 masked mul,i32 inv masked mulandi32 operators keep lhs.f32x4and 24 fori32x4, all in WASM RELAXED, at 128, 256, 512 and 1024 bit. The non relaxed WASM tier still passed.Other PRs
This only touches the two WASM headers. None of the other open performance PRs (#13, #14, #15, #16, #17, #18, #19) change WASM code. It merges cleanly with each of them (checked with
git merge-tree).