[Wasm RyuJIT] Address block store issues from #125756#125770
[Wasm RyuJIT] Address block store issues from #125756#125770kg wants to merge 10 commits intodotnet:mainfrom
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
Pull request overview
This PR targets WebAssembly RyuJIT block-store lowering/codegen issues that are triggering asserts during crossgen/debug builds (per #125756), by adjusting how GT_STORE_BLK operands are represented/contained for memory.copy/memory.fill.
Changes:
- Update WASM
LowerBlockStoreto treatGT_INDsources as contained, and attempt to convert local sources to addresses for thememory.copyopcode path. - Add debug assertions in WASM codegen to validate containment expectations for native bulk-memory op emission (
memory.copy/memory.fill).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/coreclr/jit/lowerwasm.cpp | Changes block-store source handling/containment and attempts to convert local sources into address form for memory.copy. |
| src/coreclr/jit/codegenwasm.cpp | Adds debug assertions around contained operands for the native bulk-memory opcode path. |
You can also share your feedback on Copilot code review. Take the survey.
AndyAyersMS
left a comment
There was a problem hiding this comment.
This looks good to me overall.
There was a problem hiding this comment.
Pull request overview
This PR targets WASM RyuJIT block-store correctness by adjusting lowering/RA hints and consolidating codegen paths for different GT_STORE_BLK lowering kinds, aiming to address debug/assert failures reported in #125756.
Changes:
- Move
SetMultiplyUsedmarking inLowerBlockStoreso it applies consistently across block-store kinds. - Route
BlkOpKindNativeOpcodeblock stores throughgenCodeForCpObjto share logic with theCpObjUnrollpath. - Refactor
genCodeForCpObjoperand handling to support both cpobj and nativememory.copy/memory.fill.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/coreclr/jit/lowerwasm.cpp | Moves multiply-used marking to apply across cpobj and native-op block stores. |
| src/coreclr/jit/codegenwasm.cpp | Unifies NativeOpcode handling with CpObjUnroll and refactors operand decoding/emission. |
Checkpoint Update comment & run jit-format Update comments Refactoring Formatting jit-format Add missing genUpdateLife
|
Rewrote most of the codegen changes from scratch so I'm resolving all the old comments. |
|
Null checks are missing because they unbalance the stack: Not sure what's going on there. |
|
I still need to do the optimization in lowering that singleaccretion suggested, but I think this is done otherwise now after the rewrite... |
| regNumber destReg = genConsumeReg(dest); | ||
| regNumber srcReg = genConsumeReg(src); | ||
| unsigned destOffset = 0; | ||
| unsigned srcOffset = 0; | ||
|
|
There was a problem hiding this comment.
genCodeForStoreBlk now calls genConsumeReg(dest) / genConsumeReg(src) up front. For contained operands (e.g., src is often a contained GT_IND for copyblk), this bypasses genConsumeRegs recursion and fails to consume the actual address operand (and doesn't follow the required execution-order consumption pattern used elsewhere, e.g. genCodeForStoreInd). This can leave operand liveness/GC tracking inconsistent and can break the Wasm evaluation stack invariants for block ops.
Consider switching back to genConsumeOperands(blkOp) (or explicitly genConsumeAddress(dest) + genConsumeRegs(src) with the same contained-node handling as genConsumeRegs), and only call genConsumeReg on the specific non-contained nodes you truly consume (e.g., the unwrapped GT_IND address node).
| regNumber destReg = genConsumeReg(dest); | |
| regNumber srcReg = genConsumeReg(src); | |
| unsigned destOffset = 0; | |
| unsigned srcOffset = 0; | |
| // Consume the destination address and source operands in proper evaluation order. | |
| genConsumeAddress(dest); | |
| genConsumeRegs(src); | |
| regNumber destReg = dest->isContained() ? REG_NA : dest->GetRegNum(); | |
| regNumber srcReg = src->isContained() ? REG_NA : src->GetRegNum(); | |
| unsigned destOffset = 0; | |
| unsigned srcOffset = 0; |
There was a problem hiding this comment.
genConsumeOperands isn't usable here (it breaks) nor is genConsumeAddress (it breaks)
|
The proposed lowering optimization breaks codegen somehow, I'm not sure why. Will poke at it more later. |
Fixes some of the issues from #125756 , at least based on my isolated repros.
cc @AndyAyersMS still figuring this out, don't completely understand it.