This is an archive of the discontinued LLVM Phabricator instance.

[SimplifyCFG] Don't widen cond br to cond br if false branch has successors
ClosedPublic

Authored by dmakogon on Aug 22 2022, 1:53 AM.

Details

Summary

This fixes an infinite loop of transformations in SimplifyCFG (GItHub issue - https://github.com/llvm/llvm-project/issues/57221).
The problem is that there are two transforms in SimplifyCFG that do absolutely opposite things.
First, there is tryWidenCondBranchToCondBranch which does the following.
When it sees a branch on widenable condition followed by another conditional branch like here:

bb:
  %tmp = call i1 @llvm.experimental.widenable.condition()
  br i1 %tmp, label %bb2, label %bb1

bb1:                                              ; preds = %bb
  br i1 undef, label %bb7, label %bb5

bb2:                                              ; preds = %bb
  br i1 undef, label %bb7, label %bb4

it thinks that it's profitable for bb2 to branch to bb1 instead of bb7 on true condition.
The IR after the transform:

bb:
  %tmp = call i1 @llvm.experimental.widenable.condition()
  br i1 %tmp, label %bb2, label %bb1

bb1:                                              ; preds = %bb
  br i1 undef, label %bb7, label %bb5

bb2:                                              ; preds = %bb
  br i1 undef, label %bb1, label %bb4

Then, there is another transformation SimplifyCondBranchToCondBranch. It sees that bb2 branches to bb1 if the condition is true and that bb1 has the same condition. So instead of bb2->bb1->bb7 branches, it makes it just bb2->bb7 - the exact same IR before the first transform.

This patch limits the tryWidenCondBranchToCondBranch transform making it work only if the false block of widenable condition branch has no successors.
If that block has successors, then the possible impact of the transform is complicated. SimplifyCFG may apply other transforms after this one and produce unexpected results.
As far as I can see this transform only has impact when the no succesors condition stands.

Diff Detail

Event Timeline

dmakogon created this revision.Aug 22 2022, 1:53 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 22 2022, 1:53 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
dmakogon requested review of this revision.Aug 22 2022, 1:53 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 22 2022, 1:53 AM

So, you are crippling this transformation to avoid an infinite loop with another transform in SimplifyCFG. This is probably OK as we still handle the common case of a widenable condition going to a deoptimization block.

llvm/lib/Transforms/Utils/SimplifyCFG.cpp
4015

No need to check it twice. Just check if after line 4001 once.

Also, please add a comment on why you are restricting this transformation with a TODO to find a more fine-grained solution.

llvm/test/Transforms/SimplifyCFG/pr52290.ll
32

Before you make this change, please, update the tests and remove branching on undef. This is UB and the optimizer can do whatever for this test. This can be done in a separate patch without additional review.

dmakogon updated this revision to Diff 454730.Aug 23 2022, 1:10 AM

Hoisted the condition, added comments & updated test to not branch on undef but on a normal value

dmakogon updated this revision to Diff 454732.Aug 23 2022, 1:11 AM

Is it true that every block which has successors will necessarily fall into this infinite loop? If so, it's not crippling.

Is it true that every block which has successors will necessarily fall into this infinite loop?

No. What is special about this test is the fact that bb1 and bb2 have a branch on the same condition (undef).

apilipenko accepted this revision.Aug 25 2022, 2:21 PM

LGTM with a small comment to address.

llvm/lib/Transforms/Utils/SimplifyCFG.cpp
4002–4004

Unless you know of any other transformation cycles, just say that we prevent a cyclic transformation with SimplifyCondBranchToCondBranch.

This revision is now accepted and ready to land.Aug 25 2022, 2:21 PM