diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 5dc9d2c3b71a..389ec419b5c1 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -2982,6 +2982,21 @@ static bool mergeConditionalStoreToAddress(BasicBlock *PTB, BasicBlock *PFB, if (&*I != PStore && I->mayReadOrWriteMemory()) return false; + // If PostBB has more than two predecessors, we need to split it so we can + // sink the store. + if (std::next(pred_begin(PostBB), 2) != pred_end(PostBB)) { + // We know that QFB's only successor is PostBB. And QFB has a single + // predecessor. If QTB exists, then its only successor is also PostBB. + // If QTB does not exist, then QFB's only predecessor has a conditional + // branch to QFB and PostBB. + BasicBlock *TruePred = QTB ? QTB : QFB->getSinglePredecessor(); + BasicBlock *NewBB = SplitBlockPredecessors(PostBB, { QFB, TruePred}, + "condstore.split"); + if (!NewBB) + return false; + PostBB = NewBB; + } + // OK, we're going to sink the stores to PostBB. The store has to be // conditional though, so first create the predicate. Value *PCond = cast(PFB->getSinglePredecessor()->getTerminator()) @@ -3117,7 +3132,7 @@ static bool mergeConditionalStores(BranchInst *PBI, BranchInst *QBI, if ((PTB && !HasOnePredAndOneSucc(PTB, PBI->getParent(), QBI->getParent())) || (QTB && !HasOnePredAndOneSucc(QTB, QBI->getParent(), PostBB))) return false; - if (!PostBB->hasNUses(2) || !QBI->getParent()->hasNUses(2)) + if (!QBI->getParent()->hasNUses(2)) return false; // OK, this is a sequence of two diamonds or triangles. diff --git a/llvm/test/Transforms/SimplifyCFG/merge-cond-stores.ll b/llvm/test/Transforms/SimplifyCFG/merge-cond-stores.ll index a4bda96e22a1..f730ef2aed3c 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-cond-stores.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-cond-stores.ll @@ -369,3 +369,42 @@ end: %z4 = phi i32 [ %z3, %no2 ], [ 3, %yes2 ] ret i32 %z4 } + +; This test has an outer if over the two triangles. This requires creating a new BB to hold the store. +define void @test_outer_if(i32* %p, i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @test_outer_if( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X3:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: br i1 [[X3]], label [[END:%.*]], label [[CONTINUE:%.*]] +; CHECK: continue: +; CHECK-NEXT: [[X1:%.*]] = icmp ne i32 [[A:%.*]], 0 +; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[B:%.*]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X2]], true +; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[X1]], [[TMP0]] +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[END]] +; CHECK: [[NOT_X2:%.*]] = xor i1 [[X2]], true +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = zext i1 [[NOT_X2]] to i32 +; CHECK-NEXT: store i32 [[SPEC_SELECT]], i32* [[P:%.*]], align 4 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %x3 = icmp eq i32 %c, 0 + br i1 %x3, label %end, label %continue +continue: + %x1 = icmp eq i32 %a, 0 + br i1 %x1, label %fallthrough, label %yes1 +yes1: + store i32 0, i32* %p + br label %fallthrough + fallthrough: + %x2 = icmp eq i32 %b, 0 + br i1 %x2, label %end, label %yes2 +yes2: + store i32 1, i32* %p + br label %end +end: + ret void +} +