Test case included demonstrates a situation where this matters
Slightly tangential: is a hypothetical getSingleSucessor() not useful yet?
Are you worried that L->getHeader() might be nullptr? Why check Next separately then?
Redundant && MustExecuteLoopHeader -- you do an &= anyway.
Probably nicer with a range-based loop or std::all_of.
Why have you shown two of these examples with the unknown parameter passed?
Even if it is, that's not relevant to this patch. But honestly, I don't know.
I can't find a pred_size.
L->getHeader() cannot be nullptr. Given that, I don't follow this comment -- I want to break if Next is nullptr OR Next is L->getHeader(). How do I do that with a single check?
DominatesHeaderIgnoringLoopEntry is not free, and I don't want to call it if MustExecuteLoopHeader is false.
Again, I cannot find a succ_empty. But I did notice that // No preds. should be // No successors..
std::all_of is a good idea. I don't want to make that change in this patch because I want getUniqueSuccessor to be an exact dual of getUniquePredecessor. But I can refactor both in a cleanup change.
These are negative tests that demonstrate that the transform does not fire incorrectly.
There really should not be any non-trivial "chains" of blocks with unique predecessors and successors once SimplifyCFG has run (as I understand it). What motivates this?
This needs a comment. Why are you bailing out if there is more than one predecessor?
In conclusion, I think this function is both overly limiting and too complicated (it handles a chain case that should not really occur -- although I certainly could be wrong about this).
It is also not quite correct (because you also need to check that none of these blocks have functions that might throw).
I think that a direct general approach would be better. Just walk the predecessor graph starting at BB, bailing out if you hit an edge that leaves the loop, and stopping when you hit the loop header. You also need to check for functions that might throw (this is what LICM does).
Thank you for taking out the time to review this!
It is quite possible that what I'm trying to fix can be solved by the right pass order in our frontend, I'll give that a try first before redoing this.