-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Avoid conv.i opcodes in hot paths in CoreLib #51190
Avoid conv.i opcodes in hot paths in CoreLib #51190
Conversation
Is this worth a small perf analyzer? |
Maybe, but I'm really not sure what would be a good candidate for that analyzer. The best I can think of is any sign-extending conversion from a signed narrow type to an unsigned wide type. That is, |
I imagine it would be for well known cases, like |
There are definitely valid use cases for passing in negative |
Still weighing whether to add internal |
src/coreclr/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs
Outdated
Show resolved
Hide resolved
The jit can't be improved instead? |
There are different semantics here, and the JIT needs to respect the semantics the dev / C# compiler wrote, or else it would potentially introduce a bug. Levi is only changing places where it won't be a bug. Just as an example, if you have: int i = -1; and then do: nuint n = (nuint)i; then nuint n = (nuint)(uint)i; then you end up with |
We have several places in CoreLib where we sign-extend a non-negative 32-bit value to the native word size. Changing these to use zero-extensions is somewhat more efficient from a codegen perspective.
The methodology here was very simplistic: ildasm all of System.Private.CoreLib.dll and look for calls to
conv.i
. If the method fit on my screen or was marked aggressiveinlining, I assume it's potentially on a hot path, so it's a candidate for fixing in this PR. I intentionally excluded methods that were large or complex or where trying to avoid the sign extension would seem not worth the tradeoff. For example, with this PR there are still lots of places instring
andArray
that perform sign-extension, but those extensions are performed within a larger unit of work and I didn't believe addressing them would provide any measurable benefit.I also checked calls to
Unsafe.Add(..., int)
, rewriting them to useUnsafe.Add(..., nint)
(via zero-extension) following approximately the same criteria as above. Though TBH these would be a little cleaner if we were to add anUnsafe.Add(..., uint)
overload, but that seems out of scope for this.Andy offline helped me run a diff tool against the binaries. Most of the improvements are expected. Some (like
Unsafe.Add
) seem like false positives, since I'm not changing that code. The regressions I believe might be due to more leaf methods now being eligible candidates for inlining, but that's just a guess.