-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Codegen improvements (removed unnecessary movsxd ops) #3378
Codegen improvements (removed unnecessary movsxd ops) #3378
Conversation
Thanks Sergio0694 for opening a Pull Request! The reviewers will test the PR and highlight if there is any conflict or changes required. If the PR is approved we will proceed to merge the pull request 🙌 |
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.
LGTM
(shame no C#9 nint
yet tho 😭 )
@john-h-k Ahahah we'll get there! 🤣 |
I have no idea how I managed to close this by accident, sorry for the dummy notifications to who is subscribed 😅 |
The CI failed with a seemingly unrelated error after the last merge from
The CI in |
Alright that worked 🎉 |
@Sergio0694 is there an open issue on the dotnet team about this and if this could be a future compiler optimization? 🙂 |
@michael-hawker I've opened a related issue here, which is currently marked as Future, so no guarantees on when it would eventually be done. The changes on this PR though would enable this optimization on all runtimes, so even existing ones would get the same performance benefits here. Also not all the changes here are ones that could necessarily be done by the JIT in all cases, so this way we're just ensuring a better codegen in all scenarios 😊 |
PR Type
What kind of change does this PR introduce?
What is the current behavior?
The
ReadOnlySpanExtensions.DangerousGetLookupReferenceAt
and other extensions introduce an unnecessarymovsxd
instruction on x86-64, due to theUnsafe.Add<T>(ref T, int)
overload being used. This is a (small) overhead that can be avoided.Consider
ReadOnlySpanExtensions.DangerousGetLookupReferenceAt
, this method is currently JITed like so:You can see that
movsxd rax, eax
at offset4863C0
which is not needed: that's just the offset and we don't really want to treat that as a signed integer, especially becausemovsxd
has more overhead compared to eg. just doing amovzx
.What is the new behavior?
By changing the internal temp variables to be
uint
and by switching to theUnsafe.Add<T>(ref T, IntPtr)
overload, we now get:The codegen is a bit smaller and in particular that
movsxd
is completely gone, as the JIT can see the upper 32 bits ofrax
have already been zeroed by that firstmovzx rax, cx
at the start of the method. We're now longer bothering to track the sign.Other examples
One common extension (at least, personally) is the
DangerousGetReferenceAt
extension. This currently has an unnecessarymovsxd
instruction as well, again due to theUnsafe.Add<T>(ref T, int)
overload being used (the input index is anint
).Here's the original codegen:
And here's after this PR:
In this case we've removed the extension entirely, on both x86 and x86-64. We're doing so by using:
Somewhat verbose, but it does the trick on both archs. It first does an unchecked conversion to
uint
(which is just a reinterpret-cast). We then first cast tovoid*
, which lets the followingIntPtr
cast avoid the range check on x86 (sinceuint
could be out of range there if the original index was negative). The final result is a cleanmov
, which automatically clears the upper 32 bits on x64.PR Checklist
Please check if your PR fulfills the following requirements:
Pull Request has been submitted to the documentation repository instructions. Link:Sample in sample app has been added / updated (for bug fixes / features)Icon has been created (if new sample) following the Thumbnail Style Guide and templates