-
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
JIT: Optimize "constant_string".Length #1378
Conversation
hm.. "regression" example: static StringBuilder Tess()
{
return new StringBuilder("hello");
} Diff (new codegen is on the right): https://www.diffchecker.com/QzLuLcFj |
- mov r9d, dword ptr [rcx+8]
- ;; bbWeight=0.25 PerfScore 0.50
+ mov r9d, 5
+ ;; bbWeight=0.25 PerfScore 0.06
...
- ; Total bytes of code: 81
+ ; Total bytes of code: 83 this is because immediate value for mov is always 32 bit (and there is no 8 bit counterpart, imm8), so the instruction takes 6 bytes. otoh, if it instead emits: push 5
pop r9 the diff will go away (for same range 0:127 with both masm and nasm). |
@am11 On x64 (windows, at least) we generally can't change |
Other option was to use |
I wonder how many of these come from inlining? The jit inliner currently doesn't consider a constant string passed as an argument to be noteworthy. Perhaps it should (or should, if that arg ends up in a bounds check...).
Is this representative of what causes the actual regressions? I realize there aren't that many but wonder if anything else is going on that we should investigate. |
looks so, here is the biggest "regression" (Microsoft.CodeAnalysis.CSharp.Binder:BindIntegralMinValConstants): https://www.diffchecker.com/5ttTCfO4
If I read the diff correctly - none of them were inlined but maybe I am wrong. I understand what you mean but I guess tweaking the jit heuristics (better multiplier for cns strings) is too complicated for this PR 🙂 |
Looks like we are now missing some CSEs and so re-fetching strings from their handles, which is what leads to the size increase. Can you investigate?
You could run diffs with inlining disabled (say via |
@AndyAyersMS jit-diff results with
see https://gist.github.com/EgorBo/4110b359ed109ea4ef198250aee3d3da so it's -30053 (default) diff vs -804 (noinline). Should I try to check for |
```csharp static int Test() => "Hello".Length; // replace with just `5` ``` Before: ```asm movabs rax,0x7fd6c1758160 mov eax,DWORD PTR [rax] ret ``` Now: ```asm mov eax,0x5 ret ``` Also, handles cases after inlining, e.g.: ```csharp bool Validate(string str) { return str.Length > 0 && str.Length <= 100; } bool Test() { return Validate("Hello"); // Validate() will be inlined } ``` New codegen for `Test`: ```asm mov eax, 1 ; return true ret ``` I have a similar PR for CoreCLR: dotnet#1378 jit-diff report found >30k bytes of improvements.
Did you drop all changes in ThunkInput.txt by accident? |
44336c1
to
becc851
Compare
@jkotas oops, yes, reverted. |
The VM side of the changes LGTM (modulo one nit). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JIT/SPMI side of changes looks fine.
@BruceForstall here's another jit GUID bump. Do you want us to hold off merging this?
Could we hold off a couple weeks? And merge it approximately the same time as #2249? We're just today starting to get some long-awaited (internal only) SuperPMI collections that I'd like to be able to use before requiring a recollection. |
@BruceForstall, can you please post back here when we can take this? Not sure how precise a "couple" was in your comments, and it's been two weeks 😄 Thanks! |
We're ready to take JIT-EE interface changes now (some internal processes dependent on the JIT-EE interface GUID are now stable). I'll go ahead and merge this. |
Thanks, Bruce. And Egor :) |
A similar optimization for RyuJIT was quite profitable judging by the jit-diff: dotnet/runtime#1378 Example: ```csharp static int Test() { return "hello".Length; } ``` Current `MONO_VERBOSE_METHOD=Test` output: ``` IR_0000: ldstr 0 IR_0002: strlen IR_0003: ret ``` New output: ``` IR_0000: ldc.i4.5 IR_0001: ret ```
Resurrects dotnet/coreclr#26000
Example (showcases why it's better to have this opt in JIT rather than in Roslyn)
Current codegen for
Test
method:New codegen for
Test
method:The optimization is now implemented in
importer.cpp
instead ofmorph.cpp
(according to feedback). Also, didn't forget about crossgen2.Jit-diff (see report with
--count 1000
here):In some rare cases this opt can brake bound check elimination over string literals but it doesn't work well even today (see #1343).