Skip to content

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
JIT: Run full liveness in MinOpts for async by jakobbotsch · Pull Request #123500 · dotnet/runtime · GitHub
Skip to content

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

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

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

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

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

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

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

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

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' JIT: Run full liveness in MinOpts for async by jakobbotsch · Pull Request #123500 · dotnet/runtime · GitHub
Skip to content

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

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

JIT: Run full liveness in MinOpts for async - #123500

Merged
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set
Feb 6, 2026
Merged

JIT: Run full liveness in MinOpts for async#123500
jakobbotsch merged 21 commits into
dotnet:mainfrom
jakobbotsch:minopts-async-live-set

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jan 22, 2026

Copy link
Copy Markdown
Member

For MinOpts codegen we used to consider all locals to be live across async suspensions. That results in a lot of extra lifted state. This PR starts to run full liveness to determine this. It turns out that the IR we avoid creating when we do so more than makes up for the cost of running the liveness.

Fix#116370

@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

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

Purpose: This PR optimizes the size of async continuations in MinOpts (unoptimized) code by avoiding the capture of unnecessary JIT-created temporary variables. Previously, all locals (including JIT temps) were considered live across async calls in MinOpts. This change leverages the same invariant used by EnC and OSR: in MinOpts, the JIT only creates a specific set of long-lived state (IL locals and spilled IL stack entries).

Changes:

  • Adds a new lvLiveAcrossAsync bit field to LclVarDsc to mark locals that must be preserved across async suspension points in MinOpts
  • Updates async call setup to aggressively spill IL stack entries to temps and mark them with lvLiveAcrossAsync when compiling in MinOpts
  • Modifies AsyncLiveness::IsLive to check the new field when liveness information is unavailable, returning true only for IL locals or temps marked as live across async

Reviewed changes

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

FileDescription
src/coreclr/jit/compiler.hAdds lvLiveAcrossAsync bit field to LclVarDsc and updates impSetupAsyncCall signature to accept numILArgs parameter
src/coreclr/jit/importercalls.cppUpdates impSetupAsyncCall to spill IL stack entries around async calls in MinOpts and marks the resulting temps with lvLiveAcrossAsync; passes numILArgs from call signature to impSetupAsyncCall
src/coreclr/jit/async.cppMarks async ExecutionContext and SynchronizationContext variables with lvLiveAcrossAsync; updates AsyncLiveness::IsLive to check the new field when liveness is unavailable

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotschjakobbotsch changed the title JIT: Optimize continuation sizes in MinOptsJIT: Run full liveness in MinOpts for asyncFeb 4, 2026
CopilotAI review requested due to automatic review settings February 5, 2026 10:39

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 4 out of 4 changed files in this pull request and generated no new comments.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch marked this pull request as ready for review February 5, 2026 18:38
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS

Diffs. Large tier0/minopts improvements.
The tier1 regressions are because we stopped running DCE in the async liveness. Since the regressions are so small it seemed unnecessary to run DCE + rerun liveness in those cases.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch
jakobbotsch merged commit b7d32ac into dotnet:mainFeb 6, 2026
128 of 138 checks passed
@jakobbotsch
jakobbotsch deleted the minopts-async-live-set branch February 6, 2026 11:26
jakobbotsch added a commit that referenced this pull request Feb 9, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on #123500
lewing pushed a commit to lewing/runtime that referenced this pull request Feb 9, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
For MinOpts codegen we used to consider all locals to be live across
async suspensions. That results in a lot of extra lifted state. This PR
starts to run full liveness to determine this. It turns out that the IR
we avoid creating when we do so more than makes up for the cost of
running the liveness.
Fixdotnet#116370
iremyux pushed a commit to iremyux/dotnet-runtime that referenced this pull request Mar 2, 2026
This should still give correct liveness at async suspension points given
that local addresses cannot be taken across those.
Based on dotnet#123500
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 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: Avoid capturing all jit temps in debug for runtime async

3 participants

@jakobbotsch@AndyAyersMS