Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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" + '
RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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('^' + ".*" + ' RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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('^' + ".*" + ' RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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" + ' RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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('^' + ".*" + ' RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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('^' + ".*" + ' RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid
, '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); } })(); })(); RangeCheck: Don't create invalid ranges by EgorBo · Pull Request #113935 · dotnet/runtime · GitHub
Skip to content

RangeCheck: Don't create invalid ranges - #113935

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges
Jun 13, 2025
Merged

RangeCheck: Don't create invalid ranges#113935
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:fix-invalid-ranges

Conversation

@EgorBo

@EgorBoEgorBo commented Mar 26, 2025

Copy link
Copy Markdown
Member

Fixes a bug @amanasifkhalid hit in #113709

It is possible to create ranges where their lower limit is greater than the upper in MergeEdgeAssertions. E.g.

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

Some of our range operations (RangeOps::Merge specifically) do invalid operations on such ranges, so instead of fixing such places, I propose we don't create them in the first place (give up on them).

Normally, this should not cause issues as such array accesses likely will never be accessible anyway, but we now use range analysis in assertprop

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 26, 2025
@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.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp list

@azure-pipelines

This comment was marked as resolved.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr pgo, runtime-coreclr libraries-pgo, runtime-coreclr pgostress

@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 27, 2025
@EgorBoEgorBo reopened this Jun 6, 2025
@EgorBo
EgorBo marked this pull request as ready for review June 9, 2025 12:20
CopilotAI review requested due to automatic review settings June 9, 2025 12:20
@EgorBo

EgorBo commented Jun 9, 2025

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @amanasifkhalid PTAL

In theory, invalid ranges are fine to have e.g.:

if (i > 10 && i < 5)
{
arr[i] = 0; // never reachable in fact.
}

and we still may extract useful info from that, but looks like many existing Range operations do not expect them so it's safer to just give up on them. They used to be not a problem when we used Range only for bounds checks, but we now use it for actual transformations in AssertProp as well.

@dotnetdotnet unlocked this conversation Jun 9, 2025
CopilotAI reviewed Jun 9, 2025

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@am11

am11 commented Jun 9, 2025

Copy link
Copy Markdown
Member

Were we expecting regressions? e.g. linux arm64 seeing +1.22% in

privatestaticvoidInsertionSort(Span<T>keys,Comparison<T>comparer)

@tannergooding

Copy link
Copy Markdown
Member

In theory, invalid ranges are fine to have e.g.:

Are we currently dead code eliminating these cases?

@amanasifkhalid

Copy link
Copy Markdown
Contributor

@EgorBo have you had a chance to look at the insertion sort regression?

@EgorBo

EgorBo commented Jun 12, 2025

Copy link
Copy Markdown
MemberAuthor

Sorry for the delayed response.

Are we currently dead code eliminating these cases?

RangeCheck uses a powerful and slow "Assertions + SSA-based analysis" mechanism and we don't use the same thing to fold unreachable branches. We re-use a limited form of it in the Global Assertion prop, but we don't use SSA-based analysis there because it's too slow (adds >1% TP regression), we only use assertions.

Were we expecting regressions?

I've looked at those and while they look unfortunate (just a few functions), JIT had no right to optimize them based on what it analyzed: https://www.diffchecker.com/53WlCbZL/
e.g.

Tightening pRange: [<Dependent, -1>] with assertedRange: [<0, -1>] into [<0, -1>]

privatestaticvoidInsertionSort(Span<TKey>keys,Span<TValue>values)
{
for(inti=0;i<keys.Length-1;i++)
{
TKeyt=keys[i+1];
TValuetValue=values[i+1];
intj=i;
while(j>=0&&(t==null||LessThan(reft,refkeys[j])))
{
keys[j+1]=keys[j];
values[j+1]=values[j];
j--;
}
keys[j+1]=t!;
values[j+1]=tValue;
}
}

This is just too complex flow for current jit's BCE to properly analyze it.

Given that this PR unlocks @amanasifkhalid PR and fixes access violation in #116571 I think we should just accept it.

I might still allow these functions to report "invalid" ranges like this, but at the moment I think various RangeOps:: simply don't expect them and produce invalid results.

Also, for e.g. [10..-10] assertprop might assume that the value is never negative since the lower bound is > 0.

@amanasifkhalidamanasifkhalid 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.

LGTM. CI is in pretty rough shape, so we might want to wait for the next run before merging. Thanks!

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.

5 participants

@EgorBo@am11@tannergooding@amanasifkhalid