Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak
, '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: Remove GT_NULLCHECK by jakobbotsch · Pull Request #71707 · dotnet/runtime · GitHub
Skip to content

JIT: Remove GT_NULLCHECK - #71707

Closed
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK
Closed

JIT: Remove GT_NULLCHECK#71707
jakobbotsch wants to merge 6 commits into
dotnet:mainfrom
jakobbotsch:remove-GT_NULLCHECK

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jul 6, 2022

Copy link
Copy Markdown
Member

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here. It comes with some TP cost, but not too much,
and I did some TP work in #71767 and #73919 that more than pays for this. We've seen frequent issues with keeping these flags up to date so I think it is worth it for the small cost in TP. I will remove these flags completely in a follow-up.

@ghostghost assigned jakobbotschJul 6, 2022
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 6, 2022
@ghost

ghost commented Jul 6, 2022

Copy link
Copy Markdown

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

Issue Details

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.

To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.

I am also removing the checks for the BBF_HAS_NULLCHECK flags here to see the TP diff. If it is too expensive (which it probably is) then I think the best way is to compute it in one of the full IR walks right before early prop, since keeping it up to date is even harder than it was before now.

Author:jakobbotsch
Assignees:jakobbotsch
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotsch
jakobbotsch marked this pull request as draft July 6, 2022 11:13
@EgorBo

Copy link
Copy Markdown
Member

consider doing the same for BBF_HAS_IDX_LEN - it also caused pain few times already

Previously the JIT had two ways of representing null checks, either
through GT_NULLCHECK or through any indirection node with an unused
value. This is somewhat problematic since early prop supports only the
former while CSE supports only the latter, so converting between them
always results in improvements and regressions.
To alleviate the problem remove GT_NULLCHECK entirely and switch to
unused indirections to represent null checks. Add the necessary support
for efficient codegen for these to the backend, and add support for
early prop to recognize and fold these away.
Always use EAX as the non-memory operand to the comparison. EAX is
always addressable as al, ax and eax which is not true for all registers
on x86.
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr superpmi-diffs

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

I've verified that the improvements seen in #68588 do not regress from this. @kunalspathak, did you have a simple example you were using there that I can double check the exact codegen for to make even more sure that it is not badly impacted by this change?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

As a general note I will keep PR as a draft until we snap for rc1.

@kunalspathak

Copy link
Copy Markdown
Contributor

ping @kunalspathak, do you remember what case you were using to evaluate #68588?

Sorry, I missed this. I do not recall the exact example and this came to my notice while working on hoisting expressions out of multi-nested loop. But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

But looking at the improvements (e.g. dotnet/perf-autofiling-issues#5096), you can try one of that example to see.

Yeah, I verified that these benchmarks do not regress with the change, but I wasn't totally sure where the logic was kicking in for them. I guess I can go investigate in further detail.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Couple of things I need to check/address:

  1. This is changing unused indirs to be emitted as cmp byte ptr [reg], al on xarch instead of the previous mov <some byte register>, byte ptr [reg]. Since null checks become unused indirs now it also changes those from cmp byte ptr [reg], bytereg to cmp byte ptr [reg], al. That might be affected by dependencies if rax was loaded recently. It would be nice to do a byte compare with the lower byte of esp, but that is not addressable on x86 (and requires rex prefix on x64). We can also emit test byte ptr [reg], 0 instead, but it is one byte larger than cmp byte ptr [reg], al.
  2. While this allows certain indirs/nullchecks to be CSE'd together, there is still the consideration that unused indirs can hoisted regardless of the memory they are pointing at changing. Today, we will bail on hoisting due to IsTreeVNInvariant return false. Probably solvable in a relatively simple manner from hoisting.

@ghost

Copy link
Copy Markdown

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

@ghostghost locked as resolved and limited conversation to collaborators Nov 15, 2022
This pull request was closed.
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.

3 participants

@jakobbotsch@EgorBo@kunalspathak