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
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>
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>
|
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. |
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.