-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Simplify some if tests #27462
Simplify some if tests #27462
Conversation
|
Can the JIT still not optimise these sorts of range checks?! |
| { | ||
| ThrowInvalidOperationIfDefault(); | ||
| if (index < 0 || index >= _count) | ||
| if ((uint)index >= (uint)_count) |
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.
The JIT would not be able to optimize cases like this. It does not know that _count is not negative.
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.
@jkotas what about array.Length? Does JIT know it can't be negative? (e.g. mono/mono#16948)
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.
Also, clang still is able to optimize it: https://godbolt.org/z/nmC3c6
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.
Clang's Isn't as optimized as the changed C#?
cmp edi, esi
setg al
shr edi, 31
or rdi, rax
jne .LBB0_1vs sharplab.io
cmp edx, r8d
ja L001aThere 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.
clang doesn't know our integer is actually a positive number :-)
|
I agree that it would be nice for the toolchain to optimize this for you. On the other hand, this became a CoreLib idiom used in hundreds of places, so one hundred more is not a big deal. |
|
So when we change the JIT to recognize this pattern what do we do? Go and cleanup all the FX that has now become riddled with this hack? I almost regret adding this to the JIT. |
I'd be more than happy to do so. |
|
UPD Total bytes of diff: -2569 (-0.01% of base) |
|
Need to access the array and eliminate the bounds check for if (i < 0 || i >= array.Length)
{
throw new Exception();
}
i = array[i]; |
|
Also this pattern if (i >= 0 && i < array.Length)
{
i = array[i];
} |
| } | ||
|
|
||
| if (startIndex < 0 || startIndex > array.Length) | ||
| if ((uint)startIndex > (uint)array.Length) |
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.
@benaadams um.. shouldn't it be >= here ?
It's currently incorrect (even before your PR)
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.
No, >= fails for Fill(empty, default, 0, 0) (Or any Fill(arr, default, arr.Length, 0)
|
@benaadams I've updated #27462 (comment) (now the diff is -2569) |
|
cc @dotnet/jit-contrib |
|
Thank you for your contribution. As announced in dotnet/coreclr#27549 this repository will be moving to dotnet/runtime on November 13. If you would like to continue working on this PR after this date, the easiest way to move the change to dotnet/runtime is:
|
GrabYourPitchforks
left a comment
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.
Only one thing that needs to be fixed, the rest are just random comments.
| public override int IndexOf(object? value, int startIndex, int count) | ||
| { | ||
| if (startIndex < 0 || startIndex > Count) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); | ||
| if ((uint)startIndex > (uint)Count) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); |
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.
Technically a breaking change since the get_Count virtual method is now always called, even if startIndex is negative. Honestly I don't care, but wanted to point it out since it's an example of something the JIT wouldn't be able to optimize automatically since it'd likely pessimistically assume the get_Count virtual method might have side effects.
(This same comment applies to a few other places in this file.)
|
|
||
| // Make sure n is legal | ||
| if (n < 0 || n > 0x10ffff || (n >= 0xD800 && n <= 0xDFFF)) | ||
| if ((uint)n > 0x10ffff || (n >= 0xD800 && n <= 0xDFFF)) |
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.
Hooray, a simplification! 😀
if (!Rune.IsValid(n))
Perhaps out of scope here, but there's likely some low-hanging fruit throughout the Framework that could be touched up in this manner.
| throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); | ||
|
|
||
| if (count < 0 || startIndex > this.Length - count) | ||
| if ((uint)startIndex > (uint)(this.Length - count)) |
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.
This optimization isn't valid. Still need to check count for a negative value.
|
I'll follow up with this one post consolidation |
|
Thank you for your contribution. As announced in #27549 the dotnet/runtime repository will be used going forward for changes to this code base. Closing this PR as no more changes will be accepted into master for this repository. If you’d like to continue working on this change please move it to dotnet/runtime. |


Noticed a change for
Dictionary.KeyCollectionand got a bit carried away.../cc @jkotas