-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Difference in codegen of string.IsNullOrEmpty()
#63116
Comments
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsI was playing with JIT a little bit recently, and found the below scenario where I am checking does give string is
But the collagen is a little different for both cases! using System;
public class C {
public void M() {
var someString = "";
if(someString == null || someString.Length == 0) {
Console.Write("hello");
}
}
public void T() {
string someString = "";
if(string.IsNullOrEmpty(someString)) {
Console.Write("hello");
}
}
} Following is the resulting codegen C.M()
L0000: push ebp
L0001: mov ebp, esp
L0003: mov ecx, [0x8d72018]
L0009: cmp dword ptr [ecx+4], 0
L000d: jne short L001a
L000f: mov ecx, [0x8dce1d8]
L0015: call System.Console.Write(System.String)
L001a: pop ebp
L001b: ret
C.T()
L0000: mov ecx, [0x8dce1d8]
L0006: call System.Console.Write(System.String)
L000b: ret As we can see above, codegen for
|
I can see your PR linked to the issue, will that PR will fix this issue!? |
@ShreyasJejurkar in your |
Thanks @EgorBo for the reply! Won't JIT see same thing for method |
Ah, I missed that part. |
Even more what got me into thinking that, the |
It's because JIT actually supports "Forward substitution" but only when it inlines functions. |
I created a new version of the same using System;
using System.Runtime.CompilerServices;
public class C {
public void M() {
var someString = "";
if(IsNullOrEmptyVer(someString)) {
Console.Write("hello");
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsNullOrEmptyVer(string s) {
return s == null || s.Length == 0;
}
public void T() {
string someString = "";
if(string.IsNullOrEmpty(someString)) {
Console.Write("hello");
}
}
} |
I saw this issue about "Forward Substitution", but it's dead I guess! #6973 |
@ShreyasJejurkar it's Roslyn - it decided to save your "" into a temp. Make your
but when you make it static:
|
Thanks @EgorBo , it did. SharpLab link |
NOTE: I am not blaming Roslyn here 🙂 - it's a correct IL and it's jit's fault that it doesn't do forward sub. |
@EgorBo ahh, it's ok. No one to blame here, just an opportunity. |
Soon or later 🙂 |
Extend ref counting done by local morph so that we can determine single-def single-use locals. Add a phase that runs just after local morph that will attempt to forward single-def single-use local defs to uses when they are in adjacent statements. Fix or work around issues uncovered elsewhere: * `gtFoldExprCompare` might fold "identical" volatile subtrees * `fgGetStubAddrArg` cannot handle complex trees * some simd/hw operations can lose struct handles * some calls cannot handle struct local args Addresses dotnet#6973 and related issues. Still sorting through exactly which ones are fixed, so list below may need revising. Fixes dotnet#48605. Fixes dotnet#51599. Fixes dotnet#55472. Improves some but not all cases in dotnet#12280 and dotnet#62064. Does not fix dotnet#33002, dotnet#47082, or dotnet#63116; these require handling multiple uses or bypassing statements.
Extend ref counting done by local morph so that we can determine single-def single-use locals. Add a phase that runs just after local morph that will attempt to forward single-def single-use local defs to uses when they are in adjacent statements. Fix or work around issues uncovered elsewhere: * `gtFoldExprCompare` might fold "identical" volatile subtrees * `fgGetStubAddrArg` cannot handle complex trees * some simd/hw operations can lose struct handles * some calls cannot handle struct local args * morph expects args not to interfere * fix arm; don't forward sub no return calls * update debuginfo test (we may want to revisit this) * handle subbing past normalize on store assignment * clean up nullcheck of new helper Addresses #6973 and related issues. Still sorting through exactly which ones are fixed, so list below may need revising. Fixes #48605. Fixes #51599. Fixes #55472. Improves some but not all cases in #12280 and #62064. Does not fix #33002, #47082, or #63116; these require handling multiple uses or bypassing statements.
Closing since it has expected codegen now (apparently, via Fsub) |
I was playing with JIT a little bit recently, and found the below scenario where I am checking does give string is
null
or empty with two different styles,string.IsNullOrEmpty()
built-in method, which does the same raw null and length check behind the scenes.But the collagen is a little different for both cases!
For given a program below (corresponding sharplab link)
Following is the resulting codegen
As we can see above, codegen for
string.IsNullOrEmpty(string)
is quite optimized, so my question is can we do the same optimization for the raw null check call as well (OR maybe fold that raw call with the built-in method by the compiler), given the fact that the built-in also does the same behind the scenes, but still codegen is quite different!The text was updated successfully, but these errors were encountered: