-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Ensure loops respect dominators #84458
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
Ensure loops respect dominators #84458
Conversation
When a loop has a single exit, the loop table stores a pointer to the loop exit block. Ideally, we would have the property that the loop entry block dominates the single exit block, and you could thus walk up the IDom list from the exit the the entry block. A peculiar loop structure on x86 only was preventing this: an "infinite" loop with a "try/catch" where the only "exit" was from the "catch" handler. For non-x86, the handler would have been moved out-of-line as a funclet. But for x86, the handler is still in-line with the loop blocks. This structure is peculiar because the catch handler has no predecessors and doesn't participate "normally" in the dominator tree. Prevent handler blocks like this from being considered loop exits.
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch, @kunalspathak Issue DetailsImprove recognized loop invariants When a loop has a single exit, the loop table stores a pointer to A peculiar loop structure on x86 only was preventing this: an "infinite" Prevent handler blocks like this from being considered loop exits.
|
|
There's a linux-arm Alpine System.Threading.Tasks.Dataflow.Tests failure, but there's some kind of infra failure and no log file: |
|
No asm diffs. TP improvement on linux-arm in MinOpts contexts in coreclr_tests.run.linux.arm.checked.mch, which doesn't make much sense since the only non-x86, non-DEBUG change was to move one Release check to DEBUG in hoisting, which shouldn't affect MinOpts. |
|
@AndyAyersMS PTAL |
AndyAyersMS
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.
I'm puzzled how we would ever consider a BBJ_ALWAYS or BBJ_CATCHRET block whose sole successor is outside the loop to ever be inside the loop.
|
Here's one example (partial block list): Note how BB03 is within the loop, and is the only branch out of the loop (x86 uses BBJ_ALWAYS to exit catches). (It's from this code: runtime/src/libraries/System.IO.Ports/tests/SerialPort/DiscardNull.cs Lines 381 to 407 in 57bfe47
|
|
Still puzzled. Since your fix is in But how? The set contents are computed by And more generally, how can any BBJ_ALWAYS block end up as an exit? If the successor is outside the loop then we can't reverse walk from within the loop to that block. |
|
The BB03, above, is initially not part of runtime/src/coreclr/jit/optimizer.cpp Lines 2124 to 2142 in 66da2e5
After it gets added to |
|
It's interesting how the condition runtime/src/coreclr/jit/optimizer.cpp Line 2124 in 66da2e5
doesn't check the |
|
I find the logic here a bit questionable too. At any rate that explains how we end up deciding that a non loop block is a loop block. Not sure what to recommend at this point -- maybe check and see how often we end up deciding a non-loop block has to remain in the loop, and if it's rare, we just take this fix and move on, and if its not rare, we decide if we want to pursue something more aggressive? |
|
Looks like 894 cases on win-x64 spmi replay of not moving out blocks due to EH, 883 on win-x86. One case I looked at seemed bogus: we refused to move a I saw a legitimate case where we wouldn't move a Another case that's somewhat bogus: we wouldn't move an ALWAYS that precedes a So, I think there are opportunities to move more blocks out of the loop. I'm not sure about the bug fixed by this PR, though: I can't remember the EH rules for x86 region placement. I think it's worthwhile fixing this one case to get to a place where we can assert on the dominator relationship between the loop entry and exit, and the IDom tree. I don't think fixing this and improving the non-loop block range need to be related. |
Ok by me. |
Improve recognized loop invariants
When a loop has a single exit, the loop table stores a pointer to
the loop exit block. Ideally, we would have the property that the
loop entry block dominates the single exit block, and you could
thus walk up the IDom list from the exit the the entry block.
A peculiar loop structure on x86 only was preventing this: an "infinite"
loop with a "try/catch" where the only "exit" was from the "catch"
handler. For non-x86, the handler would have been moved out-of-line
as a funclet. But for x86, the handler is still in-line with the
loop blocks. This structure is peculiar because the catch handler
has no predecessors and doesn't participate "normally" in the dominator
tree.
Prevent handler blocks like this from being considered loop exits.