Reject folding local addresses the emitter cannot encode#130990
Open
tannergooding wants to merge 4 commits into
Open
Reject folding local addresses the emitter cannot encode#130990tannergooding wants to merge 4 commits into
tannergooding wants to merge 4 commits into
Conversation
The emitter only supports byte-sized offsets for locals numbered 32768 or greater (see emitLclVarAddr::initLclVarAddr). IsValidLclAddr did not account for this, so a struct block-init at such a local with an offset >= 256 could be folded into the stack addressing form and hit an IMPL_LIMITATION, surfacing as an InvalidProgramException under MinOpts. 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 |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the CoreCLR JIT’s Compiler::IsValidLclAddr to account for an additional emitter encoding constraint: when a local number is >= 32768, the emitter can only encode byte-sized offsets (< 256). The intent is to prevent IR forms like LCL_ADDR / LCL_FLD from being produced in cases the emitter can’t encode, avoiding emit-time failures.
Changes:
- Extend
IsValidLclAddrto reject(lclNum >= 32768 && offset >= 256). - Update the function’s header comment to document the emitter’s large-varnum offset encoding restriction.
Show a summary per file
| File | Description |
|---|---|
src/coreclr/jit/compiler.hpp |
Adds an IsValidLclAddr guard for the emitter’s “large varnum => byte offset only” encoding limitation and documents it. |
Copilot's findings
- Files reviewed: 1/1 changed files
- Comments generated: 2
fgOptimizeAddition folds ADD(LCL_ADDR(off), const) into LCL_ADDR(off+const) but validated only the addend against IsValidLclAddr, not the resulting offset. Repeated folds (or a fold onto an already-offset LCL_ADDR) could accumulate an offset the emitter cannot encode. Validate the computed offset instead. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Builds a method with more than 32768 locals via Reflection.Emit so the struct local's number crosses the emitter's large-varnum boundary, then block-inits it in-body reaching an offset >= 256 under MinOpts. Skips where dynamic code isn't supported. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bound the addend to [0, UINT16_MAX] before adding it to the existing offset so the sum is computed in an unsigned domain that cannot overflow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Open
3 tasks
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 #126584.
The emitter only supports byte-sized offsets (
< 256) for local variable numbers>= 32768-- seeemitLclVarAddr::initLclVarAddr, which otherwise hitsIMPL_LIMITATION("JIT doesn't support offsets larger than 255 into valuetypes for local vars > 32767").Compiler::IsValidLclAddralready encodes the other emitter limits (16-bit offset, in-bounds) but didn't account for this one.As a result, a struct block-init of a local numbered
>= 32768whose access reaches offset>= 256could be contained/folded into the stack (S_R) addressing form byContainBlockStoreAddress, and then fail at emit time. Since the fold only happens under MinOpts here, it surfaced as anInvalidProgramExceptionin Debug but not Release. The IL is valid (ILVerify agrees); the JIT was simply generating an address form the emitter can't encode.The fix rejects that case in
IsValidLclAddr. Returningfalsethere declines only the fold --lclmorphthen keeps the access as an explicit address computation and codegen materializes it into a register (theARXform, which uses a real base register + 32-bit displacement and has no varNum-encoding limit). This also covers directLCL_FLDaccesses at offset>= 256for such locals, not just the block-init path.The constants
32768and256mirroremitLclVarAddr::initLclVarAddrexactly.fgOptimizeAdditionfoldsADD(LCL_ADDR, const)into a singleLCL_ADDR. That is a FullOpts-only sibling of the same problem: it previously validated only the addend, so repeated folds could accumulate an offset the emitter can't encode. It now validates the resulting offset throughIsValidLclAddr, with the addend bounded to[0, UINT16_MAX]first so the sum is computed without signed overflow.Added a regression test (
Runtime_126584). It usesReflection.Emitto build a MinOpts method with >32768 IL locals plus a>= 256-byte struct block-init, which is the minimal shape that reproduces the emitter limit without carrying a ~1.5MB source file. It is gated onIsReflectionEmitSupported, so it skips on NativeAOT and other no-dynamic-code scenarios. Harness-validated both directions: it fails against the baseline JIT (InvalidProgramExceptioninM0) and passes with the fix.The repro is CPU-independent -- despite the issue title, the bug isn't AVX-512-specific; those ISAs just perturbed the local numbering/codegen enough to expose it.
Note
This PR was authored with the assistance of GitHub Copilot.