Open colejohnson66 opened 2 days ago
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch See info in area-owners.md if you want to be subscribed.
As far as I know, we don't yet do any analysis to prove that an execution that might do some things and then throw is equivalent to doing an up-front check and just throwing. Typically, there other are observable side effects from the "things" so these are not equivalent.
It would be interesting to try and figure out how often we see this. Something like: if we have two bounds checks A and B, where A dominates B, and B implies A (eg n > 3
implies n > 2
), and there are no other observable side effects between A and B, then we can change the check at A to be B, and remove B. Repeated application of this (or starting with the most dominated check and pushing it up as far as it can go) would get us the "optimized" version above.
Description
Given the following code:
The only way for this method to fail a bounds/range check is if
span.Length < 4
. As such, I'd expect the runtime to optimize to something like this:Instead, the runtime generates this:
Note the four range checks against
esi
. Failures all call intoCORIFNO_HELP_RNGCHKFAIL
with no indication of which failed. As such, I'd expect the four compare+branch blocks to collapse into a singular one like this:Configuration
Godbolt Compiler Explorer against "trunk" (e33be4d53ab951272c9161c50b549e5e7db60262)
Regression?
No. Present in net7.0.19 and net8.0.5.
Notes
Interestingly, a naive loop generates nearly the same assembly, but sets up and tears down a frame: