Fix codegen assert reloading a spilled signed small cast source#130985
Open
tannergooding wants to merge 2 commits into
Open
Fix codegen assert reloading a spilled signed small cast source#130985tannergooding wants to merge 2 commits into
tannergooding wants to merge 2 commits into
Conversation
A cast whose operand is used from memory (`castIsLoad`) computed its load type from `src->TypeGet()`. For an LSRA spill temp holding a signed small load (e.g. a sign-extended `sbyte`) that feeds a zero-extending cast to `ushort`, that reported the small signed type, asserting in `GenIntCastDesc` and -- absent asserts -- emitting a byte `movzx` that drops the sign bits the 4-byte temp actually holds. Reload a spill temp as its actual type instead. 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. |
Contributor
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
Member
Author
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a CoreCLR JIT codegen issue where casts that reload from memory could treat an LSRA spill temp as a “small” memory operand, leading to incorrect reload sizing (and a checked-build assert) for certain signed-small-source → zero-extending-cast cases.
Changes:
- Adjust
GenIntCastDescto compute the reload/load type from the operand’s actual type when the operand is used from an LSRA spill temp. - Add a new JitBlue regression test project (
Runtime_124508) with a Fuzzlyn-derived repro.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/jit/codegenlinear.cpp | Use genActualType(src) for srcLoadType when src->isUsedFromSpillTemp() to avoid treating spill temps like small memory operands. |
| src/tests/JIT/Regression/JitBlue/Runtime_124508/Runtime_124508.csproj | Adds a new xUnit-based JitBlue regression test project with process isolation and tiered compilation disabled. |
| src/tests/JIT/Regression/JitBlue/Runtime_124508/Runtime_124508.cs | Adds the Fuzzlyn-derived test case intended to compile the problematic cast/spill shape. |
Copilot's findings
- Files reviewed: 3/3 changed files
- Comments generated: 1
jakobbotsch
reviewed
Jul 17, 2026
Comment on lines
+2558
to
+2562
| // A spill temp holds the full actual-type value, already extended per the source's own | ||
| // signedness, so it must be reloaded as that actual type rather than as a small memory | ||
| // operand -- otherwise a signed small source (e.g. TYP_BYTE) reloaded under a zero-extending | ||
| // cast would drop the sign bits it actually holds. | ||
| const var_types srcLoadType = src->isUsedFromSpillTemp() ? srcType : src->TypeGet(); |
Member
There was a problem hiding this comment.
Perhaps castIsLoad should instead be false for this case? cc @SingleAccretion
jakobbotsch
reviewed
Jul 17, 2026
EgorBo
reviewed
Jul 17, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This was referenced Jul 18, 2026
Open
Open
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.
Fixes #124508.
A cast whose operand is used from memory (
castIsLoad) computed its load type inGenIntCastDescfromsrc->TypeGet(). That is correct for a genuine small memory operand, but wrong for an LSRA spill temp: a spill temp always holds the register-materialized, already-extended actual-type value, not a small memory operand.In the repro (x86,
FullOpts), a signedsbyteload (s_1[0], materialized viamovsxto a fullint) feeds a cast toushort. The(short)inVector128.CreateScalar((short)(s_1[0] << ...))is relaxed toushortduring lowering becauseCreateScalar<short>only consumes the low 16 bits. Under x86 register pressure LSRA spills the sign-extendedintto a 4-byte temp.GenIntCastDescthen readsrcLoadType = src->TypeGet()=TYP_BYTE(signed, size 1)< ushort(size 2), which:assert(varTypeIsUnsigned(srcLoadType) || (genTypeSize(srcLoadType) >= genTypeSize(castType))), andmovzxthat incorrectly zeroes bits 8-15 -- the bits that actually hold the sign extension. So the assert is guarding a real correctness bug.This is x86-only: on x64 the value stays in a register, and the register path already
movzxes the 16-bit register correctly.ContainCheckCastalready forbids containing a signed small load under a zero-extending cast (varTypeIsUnsigned(castOp) == node->IsZeroExtending()), so the spill temp is the only path that reaches the assert -- makingGenIntCastDescthe correct layer for the fix.The fix reloads a spill temp as its actual type (
srcType=genActualType(src)=TYP_INT) rather than as a small memory operand, som_extendSrcSizebecomesmin(4, 2) = 2and codegen emitsmovzx wordfrom the 4-byte temp (correct low 16 bits). Genuine small memory operands still usesrc->TypeGet()and are unaffected.Verification
movsx eax, byte ptr[...]-> 4-byte spill ->movzx ecx, word ptr[TEMP].jitformat.py -r . -o windows -a x64: clean.Test note
The added
Runtime_124508regression test is the faithful Fuzzlyn repro (seed12192374036514626124). Note that under the merged test harness the byte-identical IL happens to compile without the spilled-signed-byte-under-ushort-cast shape (a deterministic token-layout-driven codegen divergence from the standalone console repro), so in that specific harness the test passes both with and without the fix. It still provides compile + execution coverage of the shape; the standalone console program is the reliable reproduction. Happy to drop or adjust the test if preferred.Note
This PR description was drafted by GitHub Copilot.