JIT: Fix register move ordering in genConsumeBlockOp when srcAddr is in dstReg#126133
JIT: Fix register move ordering in genConsumeBlockOp when srcAddr is in dstReg#126133
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
When the LSRA allocates the source address to the same register that
the destination address needs (dstReg), the original code would
incorrectly clobber the source address by copying the destination first:
mov rdi, rax ; dst -> dstReg (CLOBBERS srcAddr already in rdi!)
mov rsi, rdi ; src -> srcReg (copies destination, not source!)
Fix by detecting this case and moving the source to srcReg first when
srcAddr is currently in dstReg. Also update the existing comment which
incorrectly claimed the LSRA always guarantees safe copy ordering, and
add an assert to catch the unhandled swap case (srcAddr in dstReg AND
dstAddr in srcReg simultaneously) which would produce incorrect code.
Fixes: System.Diagnostics.Metrics.Tests.MetricsTests.PassingVariableTagsParametersTest
under JitStress=2 + JitStressRegs={2,0x80} on Linux x64.
Co-authored-by: mangod9 <61718172+mangod9@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/1b13221b-a0c1-4742-8445-5ada9974b0de
|
I don't think this is the right fix. Likely what I am working on in #125333 will fix this in a better way. |
|
Ok will close this PR then if you are already working on a fix. Thx! |
|
btw @jakobbotsch is the analysis on the issue incorrect or the proposed fix is not complete. Looks like as part of the analysis it validated the fix worked for a sample test case it had built. |
The fix is not sufficient -- there is nothing that prevents the case that the comment is mentioning:
|
MetricsTests.PassingVariableTagsParametersTestfails underJitStress=2 + JitStressRegs={2,0x80}on Linux x64 because the JIT emits incorrect code for GC-aware block copies (CpObjUnroll) when the LSRA allocates the source address to the same register required for the destination (rdi).Description
Bug:
genConsumeBlockOpunconditionally performs the destination move before the source move. When the source address is indstReg, this silently overwrites it:Fix (
src/coreclr/jit/codegenlinear.cpp,genConsumeBlockOp):GT_INDCopyBlk) is currently indstReg, emit the source move tosrcRegfirst, then move the destination todstReg.assert(dstAddr->GetRegNum() != srcReg)to guard the unhandled cyclic-swap case (srcAddr in dstReg and dstAddr in srcReg simultaneously), which would need a temp register. The assert makes this fail loudly rather than silently corrupting data.The fix is generic: it applies to all architectures that use
genConsumeBlockOpwith fixed destination/source register requirements (REG_RDI/REG_RSIon x64,REG_WRITE_BARRIER_DST_BYREF/REG_WRITE_BARRIER_SRC_BYREFon ARM64/LoongArch64/RISCV64).Original prompt
This section details on the original issue you should resolve
<issue_title>Test failure: System.Diagnostics.Metrics.Tests.MetricsTests.PassingVariableTagsParametersTest</issue_title>
<issue_description>Failed in: runtime-coreclr libraries-jitstress2-jitstressregs 20260307.1
Failed tests:
Error message:
Stack trace: