-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
If compReturnBB is unreachable we should remove it #48740
Comments
I have been looking at code that's related to this recently so posting my findings here, might be worth fixing at the same time. There is a bug in how runtime/src/coreclr/jit/morph.cpp Line 17024 in 1f866d2
Merging of returns calculates private static int Loop(int a)
{
for (int i = 0; i < 10; i++)
{
if (a is 1)
return a;
if (a is 2)
return a;
if (a is 3)
return a;
if (a is 4)
return a;
}
return 5;
} Considering loop 0 to clone for optimizations.
Loop cloning: rejecting loop because it has 0 returns; if added to previously-existing -2 returns, would exceed the limit of 4. (Edit: to be clear, I believe the fix for this to be the simple deletion of the decrement in morph. The reason I haven't done it yet is the fact that adding debug checking for We are safe here from the correctness perspective because nothing important uses I also know that One idea I had on how we could have our cake and eat it too was to just delete |
Thanks for bringing this up, @SingleAccretion. Seems like we could either (a) decide to count properly at all times, and start checking this post-phase, or (b) decide to (re) count only when we actually need to act based on the number. (a) may be tricky as there's a delay between when we figure out our merging strategy and do the actual merging, and as we've seen from the above, an interaction with tail calls (which can't be accounted for early, when we merge we haven't yet committed to which tail call candidates will become tails calls). So we may be temporarily over the limit, and post merge we may have fewer actual returns then we thought (or more, given the bug in morph's accounting). (b) may be tricky as we can't be over the limit once we get to the point where we can't fix things, so at some point we have to settle on the number and stick with it and ensure we're at or under any runtime constraint. I think your idea of (almost) always moving BBJ_RETURN out of loops is a good one -- moving does not alter the number of returns but as you note it can unblock cloning. There are potential EH constraints on moving but they should only hamper movement out of loops when there's a return inside a try inside a loop, and that's likely not something we are able/likely to clone anyways. And you can always split off the tail part of the BBJ_RETURN (past the point where any exceptions can happen) and move that. Back when we did the return merging work I actually thought we should be more aggressive about merging and perhaps have the default stance that we always try and merge returns. Would be interesting to study the impact of something like this. |
cc @BruceForstall for the issue with poor tracking of returns impacting cloning. |
Another thing we might consider is creating a true "final BB" that the return blocks all branch to. This block would post-dominate all the normal flow in the method, and its pred list would allow easy enumeration of all the returns. It wouldn't hold any code. Going a bit further, we could have a second "truly final BB" that is targeted by the final BB above and by any exceptional exits and flow dead ends (no return calls, possibly heads of no-exit loops). This block would post-dominate everything in the method and could (with suitable fake IR like keep alive) be used to force things to remain alive throughout the method without doing anything "artificial". And would also be useful if we ever decide to build post-dominance. |
We create
compReturnBB
anticipating redirection of existing returns, but we do that before we take tail calls into account, so we may not actually redirect any returns there. Because the block is marked withBBF_DONT_REMOVE
it hangs around and ends up creating a dead epilog. Here's an example; noteIG06
is unreachable.Probably not super common, but we should consider some other method of keeping the block around until morph (like an artificial ref count that we retract), or perhaps not creating it until it is needed.
category:cq
theme:block-opts
The text was updated successfully, but these errors were encountered: