Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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" + '
Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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('^' + ".*" + ' Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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('^' + ".*" + ' Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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" + ' Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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('^' + ".*" + ' Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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('^' + ".*" + ' Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion
, '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); } })(); })(); Fold "cns"[cns] for ROS<char> by EgorBo · Pull Request #78593 · dotnet/runtime · GitHub
Skip to content

Fold "cns"[cns] for ROS<char> - #78593

Merged
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index
Nov 21, 2022
Merged

Fold "cns"[cns] for ROS<char>#78593
EgorBo merged 15 commits into
dotnet:mainfrom
EgorBo:fold-str-const-index

Conversation

@EgorBo

Copy link
Copy Markdown
Member

Closes#78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6

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

Closes #78359
e.g.:

intTest()=>DoWork("D");[MethodImpl(MethodImplOptions.AggressiveInlining)]intDoWork(ReadOnlySpan<char>format){if(format.Length==1){switch(format[0]|0x20){case'a':return1;case'b':return2;case'c':return4;case'd':return8;case'e':return16;case'f':return32;}}thrownewException();}

Current codegen for Test:

; Method ConsoleApp8.C:Test():int:thisG_M000_IG01: ;; offset=0000H56pushrsi 4883EC20 subrsp,32G_M000_IG02: ;; offset=0005H 48B84023807D78020000 movrax,0x2787D802340 488B00 movrax, gword ptr [rax] 4883C00C addrax,12 0FB700 movzxrax, word ptr [rax] 83C820 oreax,32 83C09F addeax,-97 83F805 cmpeax,57746ja SHORT G_M000_IG10 8BC0 moveax,eax 488D0D63000000 learcx,[reloc @RWD00] 8B0C81 movecx, dword ptr [rcx+4*rax] 488D15CEFFFFFF leardx, G_M000_IG02 4803CA addrcx,rdx FFE1 jmprcxG_M000_IG03: ;; offset=003CH B801000000 moveax,1 EB21 jmp SHORT G_M000_IG09G_M000_IG04: ;; offset=0043H B802000000 moveax,2 EB1A jmp SHORT G_M000_IG09G_M000_IG05: ;; offset=004AH B804000000 moveax,4 EB13 jmp SHORT G_M000_IG09G_M000_IG06: ;; offset=0051H B808000000 moveax,8 EB0C jmp SHORT G_M000_IG09G_M000_IG07: ;; offset=0058H B810000000 moveax,16 EB05 jmp SHORT G_M000_IG09G_M000_IG08: ;; offset=005FH B820000000 moveax,32G_M000_IG09: ;; offset=0064H 4883C420 addrsp,32 5E poprsi C3 retG_M000_IG10: ;; offset=006AH 48B9582E82E0FA7F0000 movrcx,0x7FFAE0822E58 E84744AC5F call CORINFO_HELP_NEWSFAST 488BF0 movrsi,rax 488BCE movrcx,rsi FF153BB10800 call[System.Exception:.ctor():this] 488BCE movrcx,rsi E843509F5F call CORINFO_HELP_THROW CC int3RWD00 dd	00000037h ; case G_M000_IG03dd0000003Eh ; case G_M000_IG04dd00000045h ; case G_M000_IG05dd0000004Ch ; case G_M000_IG06dd00000053h ; case G_M000_IG07dd0000005Ah ; case G_M000_IG08; Total bytes of code: 142

New codegen for Test:

; Method ConsoleApp8.C:Test():int:this B808000000 moveax,8 C3 ret; Total bytes of code: 6
Author:EgorBo
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@EgorBo
EgorBo marked this pull request as ready for review November 19, 2022 19:56
@EgorBo

EgorBo commented Nov 19, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you please take a look at the VN side when you have time, we discussed this one yesterday. For the issue with the side-effects I decided to just call gtUpdateStmtSideEffects for current statement and it worked.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!varTypeIsShort(tree) || !vnStore->GetVNFunc(addrVN, &funcApp))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we interested in TYP_SHORT (signed) trees, since I assume this is a TP heuristic?

This shouldn't have to recompute addrVN + GetVNFunc, since the caller already did that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@SingleAccretion can you point me where exactly caller already did it? it seems like other paths also compute it

elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic))
{
fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[2]);
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */nullptr, fldSeq, offset);
}
elseif (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
elseif (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
}
.

Changed to TYP_SHORT (yes, it was a TP fast-out path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you point me where exactly caller already did it? it seems like other paths also compute it

else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) computes it. It would be good to change this to compute the thing once like ASG numbering does.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

do you mind if I leave it as is, I've just pushed a change to extract vnfunc only after TP-oriented checks. I tried to re-organize code to save these two existing lookups and didn't like the outcome, feel free to file a PR to clean it up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure.

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
EgorBoand others added 2 commits November 19, 2022 23:41
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
@am11

am11 commented Nov 19, 2022

Copy link
Copy Markdown
Member
switch(format[0]|0x20)

Looks like with char.ToLowerInvariant() it emits an extra mov and a jmp.

+ switch (char.ToLowerInvariant(value[0]))- switch (value[0] | 0x20)
C.M2()
+ L0000: mov rcx, 0x207d38020d8+ L000a: mov rcx, [rcx]+ L000d: jmp 0x00007ff863530090- L0000: mov eax, 8- L0005: ret

and gets worse with value.ToLowerInvariant()[0]. Maybe importer can normalize them to | 0x20 equivalent for ASCII / A-Za-z values (since ToLowerInvariant() is more common than | 0x20).

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@am11 good point! That jump is a tail call to TextInfo:ToLowerInvariant which is not inlined, I've pushed a change that fixes that - 369179d, e.g.:

charfoo()=>char.ToLowerInvariant('B');

Was:

; Method Prog:foo():ushort:this B942000000 movecx,66 ; 'B' FF25556B1500 tail.jmp[System.Globalization.TextInfo:ToLowerInvariant(ushort):ushort]; Total bytes of code: 11

Now:

; Method Prog:foo():ushort:this B862000000 moveax,98 ; 'b' C3 ret; Total bytes of code: 6

I think it's fine to mark those as AggressiveInlining: Invariant is folded always (inliner has no chance to know it in advance) and IsAsciiCodePoint and ToUpperAsciiInvariant are single instructions basically.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@jkotas does VM side look good to you?

@jkotas

Copy link
Copy Markdown
Member

The VM side looks good.

@EgorBo

EgorBo commented Nov 20, 2022

Copy link
Copy Markdown
MemberAuthor

@SingleAccretion can you take a look again? 🙂

As I said in some of the comments, I decided to avoid assertprop changes in this PR - so it still folds everything, but might leave nullchecks in some cases. I'll work separately (once this lands and collections are updated) to see if it's worth the effort and JIT-TP to clean them up (local runs of jit-diff state that there are not so many hits)

@SingleAccretionSingleAccretion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jit side changes LGTM.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch Can you please sign off the jit side (if it looks good to you)

Comment threadsrc/coreclr/jit/valuenum.cpp Outdated
@EgorBo
EgorBo merged commit 0ff0f7d into dotnet:mainNov 21, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Merging to have a new collection by Monday.
Two CI failures are unrelated because they're Mono only, e.g. iOS seems to be struggling connecting to a test device in that test (infra issue)

@jkotas

Copy link
Copy Markdown
Member

Two CI failures are unrelated because they're Mono only

We still want to keep track of the unrelated intermittent failures to ensure that they are getting fixed: https://github.com/dotnet/runtime/blob/main/docs/pr-builds.md#what-to-do-if-you-determine-the-failure-is-unrelated

Both of the failures are known - I have added comments to the tracking issues for you.

@EgorBo

EgorBo commented Nov 22, 2022

Copy link
Copy Markdown
MemberAuthor

@EgorBoEgorBo mentioned this pull request Nov 22, 2022
@ghostghost locked as resolved and limited conversation to collaborators Dec 29, 2022
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.

Inlined ReadOnlySpan<char> parameter lacks string-like optimizations

5 participants

@EgorBo@am11@jkotas@jakobbotsch@SingleAccretion