You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[JIT] Elide bounds check for reverse iteration over arrays and spans #9505
It would help certain tight loops if the JITter could also recognize the reverse-iteration pattern and elide the bounds checks in that scenario as well.
byte[]array;for(inti=array.Length-1;i>=0/* or any non-negative const */;i--){// consume array[i]}
This optimization would save a cmp and jae instruction in these tight loops, and in certain cases it would also allow omitting the stack frame setup that normally accompanies methods that might throw exceptions.
It turns out the JIT can correctly elide checks in one particular variant of this access pattern.
inti=arr.Length;while((uint)(--i)<(uint)arr.Length){// accesses to arr[i] won't incur additional checks here}
I've been using this in some of my code, but it's somewhat unnatural. It also doesn't support terminating the loop at an arbitrary non-negative const; it always iterates all the way to the very first element.
This and 15476 are sort of related, if they're implemented that will probably happen in the RangeCheck phase. I'm looking into this but it's probably going to take a while, the rangecheck phase is a bit of a mess and it is difficult and risky to extend it to handle new patterns.
@mikedn maybe we could compare what has change since then? In nearly all examples (excluding the static variable access as it seems trickier) the author provided possible optimizations.
To an extent the simplest and shortest answer is that not a lot has changed. Here are the cases where something did change:
staticint[]Test_ArrayCopy1(intn){int[]ia=newint[n];for(inti=0;i<n;i++)ia[i]=i;// Bound check eliminated via loop cloning, far from ideal, should be fixablereturnia;}
staticint[]v;staticvoidTest_ArrayInGlobal(){for(inti=0;i<v.Length;i++)// This might have worked until recently when a bug fix made this case more conservativev[i]=i;}
staticintTest_TwoArrays(int[]ia1,int[]ia2){// The programmer knows a precondition: ia1.Length == ia2.Lengthintsum=0;for(inti=0;i<ia1.Length;i++)// This one works via loop cloning. There's not much else the JIT can do here// because the precondition is not known to the JIT.sum+=(ia1[i]+ia2[i]);returnsum;}
staticint[]Test_ArrayCopy2(int[]ia1){// An array copy loop operation.int[]res=newint[ia1.Length];for(inti=0;i<res.Length;i++)res[i]=ia1[i];// Loop cloning again, meh. This one should be returnres;}
Activity
Therzok commentedon Jan 4, 2018
That should be i--.
GrabYourPitchforks commentedon Jan 4, 2018
@Therzok Serves me right for writing the code in notepad. :) I've fixed the sample.
GrabYourPitchforks commentedon Jan 12, 2018
It turns out the JIT can correctly elide checks in one particular variant of this access pattern.
I've been using this in some of my code, but it's somewhat unnatural. It also doesn't support terminating the loop at an arbitrary non-negative const; it always iterates all the way to the very first element.
benaadams commentedon Jan 12, 2018
There are some weirder patterns: https://github.com/dotnet/coreclr/issues/15476
mikedn commentedon Jan 12, 2018
This and 15476 are sort of related, if they're implemented that will probably happen in the RangeCheck phase. I'm looking into this but it's probably going to take a while, the rangecheck phase is a bit of a mess and it is difficult and risky to extend it to handle new patterns.
ViktorHofer commentedon Apr 24, 2018
This pattern and others are described in https://blogs.msdn.microsoft.com/clrcodegeneration/2009/08/13/array-bounds-check-elimination-in-the-clr/.
@mikedn maybe we could compare what has change since then? In nearly all examples (excluding the static variable access as it seems trickier) the author provided possible optimizations.
mikedn commentedon Apr 24, 2018
To an extent the simplest and shortest answer is that not a lot has changed. Here are the cases where something did change:
Help jIt elide bounds check
jakobbotsch commentedon Dec 15, 2022
We handle this with loop cloning today (after #67930), so we get the following codegen:
Of course it would be better if we could just prove it to be safe and avoid this code duplication.
EgorBo commentedon Mar 19, 2025
I think it's fine to close this given bounds checks are removed