Uh oh!
There was an error while loading. Please reload this page.
JIT: Optimize "constant_string".Length - #1378
Conversation
Uh oh!
There was an error while loading. Please reload this page.
EgorBo
commented
Jan 7, 2020
hm.. "regression" example: staticStringBuilderTess(){returnnewStringBuilder("hello");}Diff (new codegen is on the right): https://www.diffchecker.com/QzLuLcFj |
Uh oh!
There was an error while loading. Please reload this page.
am11
commented
Jan 8, 2020
- 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: 83this 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: push5popr9the diff will go away (for same range 0:127 with both masm and nasm). |
AndyAyersMS
commented
Jan 8, 2020
@am11 On x64 (windows, at least) we generally can't change |
am11
commented
Jan 8, 2020
Other option was to use |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
AndyAyersMS
commented
Jan 8, 2020
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 🙂 |
AndyAyersMS
commented
Jan 10, 2020
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 |
Uh oh!
There was an error while loading. Please reload this page.
@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.Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
jkotas
commented
Jan 27, 2020
Did you drop all changes in ThunkInput.txt by accident? |
44336c1 to
becc851CompareEgorBo
commented
Jan 28, 2020
@jkotas oops, yes, reverted. |
Uh oh!
There was an error while loading. Please reload this page.
jkotas
commented
Jan 31, 2020
The VM side of the changes LGTM (modulo one nit). |
AndyAyersMS
left a comment
There was a problem hiding this comment.
JIT/SPMI side of changes looks fine.
@BruceForstall here's another jit GUID bump. Do you want us to hold off merging this?
BruceForstall
commented
Jan 31, 2020
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. |
stephentoub
commented
Feb 14, 2020
@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! |
BruceForstall
commented
Feb 14, 2020
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. |
stephentoub
commented
Feb 14, 2020
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
Testmethod:New codegen for
Testmethod:The optimization is now implemented in
importer.cppinstead ofmorph.cpp(according to feedback). Also, didn't forget about crossgen2.Jit-diff (see report with
--count 1000here):In some rare cases this opt can brake bound check elimination over string literals but it doesn't work well even today (see #1343).