Uh oh!
There was an error while loading. Please reload this page.
Implement wasm codegen for sub-16 SIMD load/store - #131000
Conversation
Vector2 (TYP_SIMD8) and Vector3 (TYP_SIMD12) have no native wasm valtype, so they live as a v128 with the low 8/12 bytes populated. Emit the split lane loads/stores instead of bailing out via the ins_Load/ins_Store NYIs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 5 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
Pull request overview
This PR extends the WASM JIT’s SIMD codegen to handle sub-16-byte SIMD memory operations by emitting lane-based load/store sequences for TYP_SIMD8 (Vector2) and TYP_SIMD12 (Vector3), and updates lowering/regalloc to ensure required multi-use addressing and internal v128 temporaries are available.
Changes:
- Add SIMD8 load support via
v128.load64_zeroand route SIMD12 loads/stores through new split-lane helper sequences in WASM codegen. - Force multiply-use of SIMD12 addresses in lowering where codegen needs to re-materialize/re-push the address.
- Ensure regalloc requests an internal v128 temp for SIMD12 stores (including the local-to-stack store rewrite path).
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/jit/regallocwasm.cpp | Requests an internal v128 register for SIMD12 store indirections (including rewrite-introduced STOREIND). |
| src/coreclr/jit/lowerwasm.cpp | Forces multiply-use of SIMD12 indir addresses when codegen needs to reuse/re-materialize them. |
| src/coreclr/jit/instr.cpp | Implements ins_Load(TYP_SIMD8) as INS_v128_load64_zero for WASM. |
| src/coreclr/jit/codegenwasm.cpp | Implements split-lane load/store sequences for SIMD12 and lane store for SIMD8 storeind; adds helper routines. |
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 2
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Casting the frame offset to unsigned before passing it as a wasm memarg defeated the emitter's offset >= 0 invariant, silently turning an unexpected negative offset into a large positive one. Compute a signed offset and noway_assert it, matching emitter::emitIns_S. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Assert the wasm frame address is FP-based before re-emitting the frame pointer in the simd12 lane helpers, matching the block-copy codegen. Update the multiply-use DEBUGARG reasons since simd12 now forces it regardless of faulting. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
lewing
commented
Jul 18, 2026
End-to-end validation on the wasm R2R prototype tree (which actually runs wasm R2R crossgen, complementary to the SuperPMI assert numbers): Stacked this on #130866 with a matched crossgen2 + wasm cross-jit and crossgen'd the built
The 2 still-failing are unrelated to this PR: one harness/reference artifact, and one nested try/catch-with-filter EH case ( LGTM from the end-to-end side. Note This comment (and its validation run) was generated with GitHub Copilot. |
Uh oh!
There was an error while loading. Please reload this page.
…Shuffle (Adam's shuffle-mask fix) Fixes the invalid i8x16.shuffle immediate (out-of-range lane) that made the SIMD composite fail wasm validation. Resolved 2 conflicts vs dotnet#130866/dotnet#131000: - codegenwasm.cpp: dropped redundant ins local (superseded by dotnet#131000 store restructure) - lowerwasm.cpp: took shuffle case + IsCnsVec() immediate handling from dotnet#130991
Vector2(TYP_SIMD8) andVector3(TYP_SIMD12) have no native wasm valtype, so they live as av128with the low 8/12 bytes populated. Previously the wasm JIT bailed out via theins_Load/ins_StoreNYIs for these types; this implements the split lane load/store sequences instead.The emitted sequences are:
v128.load64_zero 0v128.store64_lane 0, lane 0local.get addr; v128.load64_zero 0; v128.load32_lane 8, lane 2v128temporary,v128.store64_lane 0, lane 0for the low 8 bytes, then re-materialize the address andv128.store32_lane 8, lane 2for the upper 4 bytesv128.load64_zerofills lanes 0-1 (zeroing the rest); the trailing lane store/load handles bytes 8-11 for theVector3case.The
TYP_SIMD12address is forced multiply-used (loads and heap stores re-materialize it for the trailing lane op). The local-to-stack store rewrite (RewriteLocalStackStore) produces aSTOREIND(LCL_ADDR, value)whose address is a re-materializableGT_LCL_ADDR, so that case is excluded from multiply-use and codegen re-emits the frame pointer directly. Because that synthesizedSTOREINDis not revisited by the main collection walk, its internalv128tee register is requested inRewriteLocalStackStore.Measured on the corelib crossgen2 browser SuperPMI collection (27,540 contexts): hard asserts drop from 403 to 30, eliminating 373
SIMD8/SIMD12load/store asserts with no regressions. The residual 30 are the pre-existingNYIRAWoper catch-all, unrelated to this change.Full effectiveness requires #130866 (which removes the shadowing SIMD-ABI bailouts for SIMD params/locals/stores/call-args); standalone, this change already clears the 373 asserts above on that collection.
Note
This PR description was drafted with the assistance of GitHub Copilot.