JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

JIT: Handle writes to promoted locals in AliasSet::AddNode - #126645

Merged
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414
Apr 15, 2026
Merged

JIT: Handle writes to promoted locals in AliasSet::AddNode#126645
jakobbotsch merged 3 commits into
dotnet:mainfrom
jakobbotsch:fix-126414

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Apr 8, 2026

Copy link
Copy Markdown
Member

Fix#126414

No test since the repro case requires reverting unrelated changes that hid the issue on main.

Codegen diff (with some PRs reverted to repro the original problem on main):

@@ -1,71 +1,72 @@
; Assembly listing for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; Emitting BLENDED_CODE for arm64 + SVE on Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No matching PGO data
; 0 inlinees with PGO data; 9 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
; V00 this [V00,T00] ( 8, 8 ) ref -> x0 this class-hnd single-def <Range>
;* V01 arg1 [V01 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;* V02 arg2 [V02 ] ( 0, 0 ) struct (16) zero-ref do-not-enreg[SA] multireg-arg single-def <Endpoint>
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;* V04 tmp1 [V04 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
;* V05 tmp2 [V05 ] ( 0, 0 ) struct (16) zero-ref ld-addr-op "NewObj constructor temp" <Endpoint>
; V06 tmp3 [V06 ] ( 5, 10 ) struct (16) [fp+0x20] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
; V07 tmp4 [V07 ] ( 5, 10 ) struct (16) [fp+0x10] do-not-enreg[SF] ld-addr-op "Inlining Arg" <Endpoint>
;* V08 tmp5 [V08 ] ( 0, 0 ) int -> zero-ref "field V04.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V09 tmp6 [V09 ] ( 0, 0 ) int -> zero-ref "field V04.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V10 tmp7 [V10 ] ( 0, 0 ) int -> zero-ref "field V04.<C>k__BackingField (fldOffset=0x8)" P-INDEP
;* V11 tmp8 [V11 ] ( 0, 0 ) int -> zero-ref "field V05.<A>k__BackingField (fldOffset=0x0)" P-INDEP
;* V12 tmp9 [V12 ] ( 0, 0 ) int -> zero-ref "field V05.<B>k__BackingField (fldOffset=0x4)" P-INDEP
;* V13 tmp10 [V13 ] ( 0, 0 ) int -> zero-ref "field V05.<C>k__BackingField (fldOffset=0x8)" P-INDEP
; V14 tmp11 [V14,T07] ( 2, 3 ) int -> [fp+0x20] do-not-enreg[] "field V06.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V15 tmp12 [V15,T08] ( 2, 3 ) int -> [fp+0x24] do-not-enreg[] "field V06.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V16 tmp13 [V16,T01] ( 3, 4 ) int -> [fp+0x28] do-not-enreg[] "field V06.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V17 tmp14 [V17,T09] ( 2, 3 ) int -> [fp+0x10] do-not-enreg[] "field V07.<A>k__BackingField (fldOffset=0x0)" P-DEP
; V18 tmp15 [V18,T10] ( 2, 3 ) int -> [fp+0x14] do-not-enreg[] "field V07.<B>k__BackingField (fldOffset=0x4)" P-DEP
; V19 tmp16 [V19,T02] ( 3, 4 ) int -> [fp+0x18] do-not-enreg[] "field V07.<C>k__BackingField (fldOffset=0x8)" P-DEP
; V20 tmp17 [V20,T11] ( 2, 2 ) int -> x2 "V01.[008..012)"
; V21 tmp18 [V21,T12] ( 2, 2 ) int -> x4 "V02.[008..012)"
; V22 rat0 [V22,T03] ( 3, 3 ) long -> x2 "V01.x2"
; V23 rat1 [V23,T04] ( 3, 3 ) long -> x4 "V02.x4"
; V24 rat2 [V24,T05] ( 3, 3 ) long -> x1 "V01.x1"
; V25 rat3 [V25,T06] ( 3, 3 ) long -> x3 "V02.x3"
;
; Lcl frame size = 32
G_M49258_IG01:
stp fp, lr, [sp, #-0x30]!
mov fp, sp
;; size=8 bbWeight=1 PerfScore 1.50
G_M49258_IG02:
str w2, [fp, #0x28]	// [V16 tmp13]
str x1, [fp, #0x20]	// [V06 tmp3]
ldp w1, w2, [fp, #0x20]	// [V14 tmp11], [V15 tmp12]
stp w1, w2, [x0, #0x08]
ldr w1, [fp, #0x28]	// [V16 tmp13]
- ldr w2, [fp, #0x10]	// [V17 tmp14] // this read stack garbage before- stp w1, w2, [x0, #0x10]+ str w1, [x0, #0x10]
str w4, [fp, #0x18]	// [V19 tmp16]
str x3, [fp, #0x10]	// [V07 tmp4]
- ldp w1, w2, [fp, #0x14]	// [V18 tmp15], [V19 tmp16]- stp w1, w2, [x0, #0x18]- ;; size=44 bbWeight=1 PerfScore 15.00+ ldp w1, w2, [fp, #0x10]	// [V17 tmp14], [V18 tmp15]+ stp w1, w2, [x0, #0x14]+ ldr w1, [fp, #0x18]	// [V19 tmp16]+ str w1, [x0, #0x1C]+ ;; size=48 bbWeight=1 PerfScore 16.00
G_M49258_IG03:
ldp fp, lr, [sp], #0x30
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
-; Total bytes of code 60, prolog size 8, PerfScore 18.50, instruction count 15, allocated bytes for code 60 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)+; Total bytes of code 64, prolog size 8, PerfScore 19.50, instruction count 16, allocated bytes for code 64 (MethodHash=bb583f95) for method Range:.ctor(Endpoint,Endpoint):this (FullOpts)
; ============================================================

CopilotAI review requested due to automatic review settings April 8, 2026 14:01
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT alias tracking so that writes involving promoted locals (and their promoted field locals) are treated as interfering with related locals, preventing incorrect transformations that can lead to wrong codegen on arm64 (as in #126414).

Changes:

  • Extend AliasSet::AddNode to treat writes to promoted struct-field locals as writes to the parent promoted local.
  • Extend AliasSet::AddNode to treat writes to a promoted parent local as writes to all of its promoted field locals.

Comment threadsrc/coreclr/jit/sideeffects.cpp
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
jakobbotsch requested a review from EgorBoApril 9, 2026 12:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings April 10, 2026 07:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No diffs

@jakobbotsch
jakobbotsch merged commit 7af0c70 into dotnet:mainApr 15, 2026
139 of 142 checks passed
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

JulieLeeMSFT pushed a commit that referenced this pull request Apr 16, 2026
…dNode` (#126939)
Backport of #126645 to release/10.0
/cc @jakobbotsch
## Customer Impact
- [x] Customer reported
- [ ] Found internally
The JIT may incorrectly reorder two stores in a way that results in
computing a wrong result. This was observed on arm64 during its
optimization that tries to combine adjacent stores, but the bug is in a
common helper function and can potentially be hit on all targets.
Reported by customer in #126414.
## Regression
- [X] Yes
- [ ] No
The bug is in a common helper function, but the arm64 adjacent store
optimization that exposed it was introduced in .NET 10.
## Testing
Unit test added.
## Risk
Low. Tighten the utility function that determines reordering legality.
---------
Co-authored-by: Jakob Botsch Nielsen <jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JIT] Incorrect code generation for readonly struct copy constructor on arm64

3 participants

@jakobbotsch@EgorBo