This is an archive of the discontinued LLVM Phabricator instance.

[SimplifyCFG] Don't remove preheaders when we need canonical loops.
Needs ReviewPublic

Authored by dmgreen on Feb 14 2018, 8:16 AM.

Details

Summary

Commit rL324208 loosened a restriction on removing basic blocks
in the intent to remove empty back edge blocks, but also started
removing preheaders in the process. This prevents the preheaders
from being removed when we want to keep loop simple form.

Diff Detail

Event Timeline

dmgreen created this revision.Feb 14 2018, 8:16 AM
fhahn added a subscriber: fhahn.Feb 14 2018, 8:19 AM

You might need to update the BackEdges set in more places, if we can introduce backedges in certain cases.

What passes benefit from having SimplifyCFG keep around empty preheaders?

Does it eliminate your regression?
I double the Eli's question: "What passes benefit from having SimplifyCFG keep around empty preheaders?"

lib/Transforms/Utils/SimplifyCFG.cpp
5740–5741

It becomes complicated. Could you please re-write it in a more readable way?

I guess lambda with explicit ifs and possible comments may do things cleaner in terms of reading this.

I don't see any use of empty preheaders. Can you explain for which cases empty preheaders are important?

dmgreen updated this revision to Diff 134454.Feb 15 2018, 11:21 AM

Updated to simplify if condition.

Hello all

Yes, from rL324572 I'm seeing multiple small regressions and two large-ish ones (no improvements unfortunately - I usually try to look for reasons why changes like that are a net gain, even if they cause some regressions, but in this case my numbers are not being very kind in that regard). I believe removing preheaders was not intended, and this "fixes" all of the regressions except for one of the big ones. That looks like it's to do with loop rotate choosing a differently loop header, and the knock on affects of that. I'm still trying to pull apart why exactly that is making things worse there.

For this patch - which was suggested by Serguie as a potential fix (I should have mentioned that somewhere - sorry). I agree that if we need loop simple form then that pass will re-create the loop preheader for us. So the change in rL324572 to remove preheaders should be benign, except for block layout, anything that might benefit from less critical edges and the fact that we are repeatedly removing and recreating loop preheaders through the pass pipeline. The NeedCanonicalLoop option seems to be requiring that we don't break loop simple form, which this patch aims to fix. So not a direct fix (I'm not sure that would even be possible for all these regressions) but hopefully a sensible change none-the-less (?)

lib/Transforms/Utils/SimplifyCFG.cpp
5740–5741

I agree this one was giving me trouble. Thanks for the lambda suggestion, that's a good idea.

What is about Eli's comment?

When you remove backedge you introduce new backedge. So you need to add new backedge to the list of the backedges.

Maybe we should introduce some annotation to loops that are in simple form. Passes like SimplifyCFG may honor this annotation and don't remove empty preheaders. Removing and recreating empty preheaders seems wrong.

When you remove backedge you introduce new backedge. So you need to add new backedge to the list of the backedges.

I looked into this a little, and had convinced myself that it would be OK (if we add a new backedge, we probably don't want to remove it again in the same pass). Looking at it again though, that might not be correct. I've not done much work in simplify cfg before. Do you think this would involve updating the backedge list in many places?

Perhaps we can turn this around, calculate the Preheaders as Preds(Headers) - Backedges and use that instead.

Maybe we should introduce some annotation to loops that are in simple form.

I don't think that annotations are the way that this is usually handled in llvm, if we can help it. (Plus clang creates preheaders, but wouldn't mark the loops as loop simple form.) I guess the standard way to do this would be to have simplifyCFG know more about loops (using LoopInfo and check if the loop is in simple form). But I suspect that isn't what we would want here if we can take a lighter approach.

When you remove backedge you introduce new backedge. So you need to add new backedge to the list of the backedges.

I looked into this a little, and had convinced myself that it would be OK (if we add a new backedge, we probably don't want to remove it again in the same pass). Looking at it again though, that might not be correct. I've not done much work in simplify cfg before. Do you think this would involve updating the backedge list in many places?

Perhaps we can turn this around, calculate the Preheaders as Preds(Headers) - Backedges and use that instead.

I do not follow how computing Preheaders as Preds(Headers) - Backedges will help you.
In general, potentially you can have CFG like empty backedge coming to pre-header only and predecessor of backedge is also empty block having only one predecessor. In this case current implementation will eliminate only one backedge and preserve the second one.

In my understanding each time you are removing backedge you need add all its predecessors to backedge if this backedge is not a loop header. The last case seems to me impossible (otherwise you eliminate the loop and can be asserted).
To minimize changes you can introduce the utility which will do this check (and even you can put LoopHeader erase to the same utility function) and everywhere you invoke backedge erase you can invoke this utility..