Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

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

Late cast expansion: remove the null check if possible - #97234

Merged
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts
Feb 7, 2024
Merged

Late cast expansion: remove the null check if possible#97234
EgorBo merged 13 commits into
dotnet:mainfrom
EgorBo:nonnul-profiled-casts

Conversation

@EgorBo

@EgorBoEgorBo commented Jan 19, 2024

Copy link
Copy Markdown
Member

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags we can remove it in favor of _NONNULL helpers.

@ghostghost assigned EgorBoJan 19, 2024
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 19, 2024
@ghost

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

If assertionprop sees that input object is already having a nonnull assertion we can give fgLateCastExpand a hint that we don't need a nullcheck, example:

// PGO warmupfor(inti=0;i<200;i++){Test(newProgram());Thread.Sleep(10);}[MethodImpl(MethodImplOptions.NoInlining)]voidTest(object?o){if(o!=null){if(oisProgram){Console.WriteLine();}}}

Diff: https://www.diffchecker.com/JkdxRigp/

Initially, I wanted to just introduce new _NONNULL cast helpers, but this change seems to be a lot smaller. In case if we run out of bits in gtMoreCallFlags in can be removed in favor of _NONNULL helpers.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review January 20, 2024 00:42
@EgorBo

EgorBo commented Jan 20, 2024

Copy link
Copy Markdown
MemberAuthor

@dotnet/jit-contrib @jakobbotsch PTAL

gtMoreFlags has 5 spare bits and this PR uses 1 of them. An alternative option is to introduce new fake *_NONNULL cast helpers - but that is a bit more changes + JIT-EE update (and R2R bump?)

Overall it looks like if we run out of spare bits we can move some rare things to side dictionaries or make some of them context-dependent. E.g. 3 GDV flags are only needed for virtual calls and only during early phases. GTF_CALL_M_EXP_RUNTIME_LOOKUP is only used in Debug and GTF_CALL_M_CAST_CAN_BE_EXPANDED will be hopefully removed next week.

Diffs aren't too big, but they will be a lot bigger once I move non-profiled (regular) casts to the late phase.

Build failures are known.

@jakobbotsch

jakobbotsch commented Jan 22, 2024

Copy link
Copy Markdown
Member

I definitely think having separate helpers would be better, especially since it would be slightly better for unprofiled casts too (assuming we would have cast variants that skip the null check inside them).

I'm ok with using a flag, but note that having flags that alter the semantics of nodes is IMO bad IR design. It's super easy to forget to check for. For example, shouldn't this PR check for the new flag inside GenTreeCall::Equals?

@EgorBo

EgorBo commented Jan 22, 2024

Copy link
Copy Markdown
MemberAuthor

I don't have a strong preference here, I'll see what it will take to use the helpers, but I am guessing it's a copy-paste of all 8 helpers everywhere + R2R version bump + JIT-EE bump.

assuming we would have cast variants that skip the null check inside them

I thought about it too, but sounds like adding extra several kb to CastHelpers.cs to skip a nullcheck so unlikely worth the effort.

the semantics of nodes is IMO bad IR design

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

@jakobbotsch

Copy link
Copy Markdown
Member

I agree generally, but looks like some of the existing flags already do similar things? e.g. tail call

Yes, we have a number of flags that alter semantics, GTF_UNSIGNED being one of the big ones. I think GenTreeCall::Equals is also missing the checks for tail call flags (IIRC we talked about this one before).

I'm ok with merging this as is (with the GenTreeCall::Equals fix). If we think about a new representation it doesn't necessarily have to be via a different helper num if we do not think that's beneficial in the unprofiled case (in fact, I think it shouldn't be then). For example, we could have GT_ISCLASS, GT_ISCLASS_NONULL, GT_TLSLOOKUP, GT_RUNTIMELOOKUP when optimizing and create the GT_CALL only later.

@EgorBoEgorBo closed this Feb 5, 2024
@EgorBoEgorBo reopened this Feb 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch I've fixed the GenTreeCall::Equals case + I addressed your other feedback regarding removing the debug only flag and gtGetEffectiveValue

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Failure is #97049

@EgorBo
EgorBo merged commit 5501afd into dotnet:mainFeb 7, 2024
@EgorBo
EgorBo deleted the nonnul-profiled-casts branch February 7, 2024 17:42
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Mar 9, 2024
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.

2 participants

@EgorBo@jakobbotsch