1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 03:33:20 +01:00

[SimplifyCFG] FoldBranchToCommonDest: lift use-restriction on bonus instructions

1. It doesn't make sense to enforce that the bonus instruction
   is only used once in it's basic block. What matters is
   whether those user instructions fit within our budget, sure,
   but that is another question.
2. It doesn't make sense to enforce that said bonus instructions
   are only used within their basic block. Perhaps the branch
   condition isn't using the value computed by said bonus instruction,
   and said bonus instruction is simply being calculated
   to be used in successors?

So iff we can clone bonus instructions, to lift these restrictions,
we just need to carefully update their external uses
to use the new cloned instructions.

Notably, this transform (even without this change) appears to be
poison-unsafe as per alive2, but is otherwise (including the patch) legal.

We don't introduce any new PHI nodes, but only "move" the instructions
around, i'm not really seeing much potential for extra cost modelling
for the transform, especially since now we allow at most one such
bonus instruction by default.

This causes the fold to fire +11.4% more (13216 -> 14725)
as of vanilla llvm test-suite + RawSpeed.

The motivational pattern is IEEE-754-2008 Binary16->Binary32
extension code:
ca57d77fb2/src/librawspeed/common/FloatingPoint.h (L115-L120)
^ that should be a switch, but it is not now: https://godbolt.org/z/bvja5v
That being said, even thought this seemed like this would fix it: https://godbolt.org/z/xGq3TM
apparently that fold is happening somewhere else afterall,
so something else also has a similar 'artificial' restriction.
This commit is contained in:
Roman Lebedev 2020-11-26 19:41:31 +03:00
parent 92849604b2
commit bd2c4beb4e
3 changed files with 75 additions and 58 deletions

View File

@ -2779,15 +2779,9 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU,
// Ignore dbg intrinsics.
if (isa<DbgInfoIntrinsic>(I))
continue;
if (!I->hasOneUse() || !isSafeToSpeculativelyExecute(&*I))
// I must be safe to execute unconditionally.
if (!isSafeToSpeculativelyExecute(&*I))
return Changed;
// I has only one use and can be executed unconditionally.
Instruction *User = dyn_cast<Instruction>(I->user_back());
if (User == nullptr || User->getParent() != BB)
return Changed;
// I is used in the same BB. Since BI uses Cond and doesn't have more slots
// to use any other instruction, User must be an instruction between next(I)
// and Cond.
// Account for the cost of duplicating this instruction into each
// predecessor.
@ -2883,6 +2877,13 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU,
PBI->swapSuccessors();
}
// Before cloning instructions, notify the successor basic block that it
// is about to have a new predecessor. This will update PHI nodes,
// which will allow us to update live-out uses of bonus instructions.
if (BI->isConditional())
AddPredecessorToBlock(PBI->getSuccessor(0) == BB ? TrueDest : FalseDest,
PredBlock, BB, MSSAU);
// If we have bonus instructions, clone them into the predecessor block.
// Note that there may be multiple predecessor blocks, so we cannot move
// bonus instructions to a predecessor block.
@ -2914,6 +2915,18 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU,
PredBlock->getInstList().insert(PBI->getIterator(), NewBonusInst);
NewBonusInst->takeName(&*BonusInst);
BonusInst->setName(BonusInst->getName() + ".old");
BonusInst->replaceUsesWithIf(
NewBonusInst, [CurrBB = BonusInst->getParent(), PredBlock](Use &U) {
auto *User = cast<Instruction>(U.getUser());
// Ignore uses in the same block as the bonus instruction itself.
if (User->getParent() == CurrBB)
return false;
// We can safely update external non-PHI uses.
if (!isa<PHINode>(User))
return true;
// For PHI nodes, only update the uses for the current predecessor.
return cast<PHINode>(User)->getIncomingBlock(U) == PredBlock;
});
}
// Clone Cond into the predecessor basic block, and or/and the
@ -2955,7 +2968,6 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU,
(SuccFalseWeight + SuccTrueWeight) +
PredTrueWeight * SuccFalseWeight);
}
AddPredecessorToBlock(TrueDest, PredBlock, BB, MSSAU);
PBI->setSuccessor(0, TrueDest);
}
if (PBI->getSuccessor(1) == BB) {
@ -2970,7 +2982,6 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU,
// FalseWeight is FalseWeight for PBI * FalseWeight for BI.
NewWeights.push_back(PredFalseWeight * SuccFalseWeight);
}
AddPredecessorToBlock(FalseDest, PredBlock, BB, MSSAU);
PBI->setSuccessor(1, FalseDest);
}
if (NewWeights.size() == 2) {

View File

@ -1,3 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -S -passes='require<opt-remark-emit>,loop-unroll<peeling;no-runtime>,simplify-cfg,instcombine' -unroll-force-peel-count=3 -verify-dom-info | FileCheck %s
define void @basic(i32 %K, i32 %N) {
@ -6,24 +7,19 @@ define void @basic(i32 %K, i32 %N) {
; CHECK-NEXT: br label [[OUTER:%.*]]
; CHECK: outer:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_BACKEDGE:%.*]] ]
; CHECK-NEXT: [[CMP_INNER_PEEL:%.*]] = icmp sgt i32 [[K:%.*]], 1
; CHECK-NEXT: br i1 [[CMP_INNER_PEEL]], label [[INNER_PEEL2:%.*]], label [[OUTER_BACKEDGE]]
; CHECK: inner.peel2:
; CHECK-NEXT: [[CMP_INNER_PEEL4:%.*]] = icmp eq i32 [[K]], 2
; CHECK-NEXT: br i1 [[CMP_INNER_PEEL4]], label [[OUTER_BACKEDGE]], label [[INNER_PEEL6:%.*]]
; CHECK: inner.peel6:
; CHECK-NEXT: [[CMP_INNER_PEEL8:%.*]] = icmp sgt i32 [[K]], 3
; CHECK-NEXT: [[CMP_INNER_PEEL8:%.*]] = icmp sgt i32 [[K:%.*]], 3
; CHECK-NEXT: br i1 [[CMP_INNER_PEEL8]], label [[INNER:%.*]], label [[OUTER_BACKEDGE]]
; CHECK: inner:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_INC:%.*]], [[INNER]] ], [ 3, [[INNER_PEEL6]] ]
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[J_INC:%.*]], [[INNER]] ], [ undef, [[OUTER]] ]
; CHECK-NEXT: [[J_INC]] = add nuw nsw i32 [[J]], 1
; CHECK-NEXT: [[CMP_INNER:%.*]] = icmp slt i32 [[J_INC]], [[K]]
; CHECK-NEXT: br i1 [[CMP_INNER]], label [[INNER]], label [[OUTER_BACKEDGE]], !llvm.loop !0
; CHECK-NEXT: br i1 [[CMP_INNER]], label [[INNER]], label [[OUTER_BACKEDGE]], [[LOOP0:!llvm.loop !.*]]
; CHECK: outer.backedge:
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: [[CMP_OUTER:%.*]] = icmp slt i32 [[I_INC]], [[N:%.*]]
; CHECK-NOT: !llvm.loop
; CHECK-NEXT: br i1 [[CMP_OUTER]], label [[OUTER]], label [[END:%.*]]
; CHECK: end:
; CHECK-NEXT: ret void
;
entry:
br label %outer

View File

@ -160,12 +160,11 @@ define void @one_pred_with_extra_op_multiuse(i8 %v0, i8 %v1) {
; CHECK-LABEL: @one_pred_with_extra_op_multiuse(
; CHECK-NEXT: pred:
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: br i1 [[C0]], label [[DISPATCH:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[V1_ADJ_ADJ:%.*]] = add i8 [[V1_ADJ]], [[V1_ADJ]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ_ADJ]], 0
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: ret void
@ -196,15 +195,18 @@ define void @two_preds_with_extra_op_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
; CHECK-NEXT: br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
; CHECK: pred0:
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2:%.*]]
; CHECK-NEXT: [[DOTOLD1:%.*]] = add i8 [[DOTOLD]], [[DOTOLD]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[DOTOLD1]], 0
; CHECK-NEXT: [[OR_COND4:%.*]] = or i1 [[C1]], [[C3_OLD]]
; CHECK-NEXT: br i1 [[OR_COND4]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: br i1 [[C2]], label [[DISPATCH]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[V3_ADJ_ADJ:%.*]] = add i8 [[V3_ADJ]], [[V3_ADJ]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ_ADJ]], 0
; CHECK-NEXT: br i1 [[C3]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: ret void
@ -241,11 +243,10 @@ define void @one_pred_with_extra_op_liveout(i8 %v0, i8 %v1) {
; CHECK-LABEL: @one_pred_with_extra_op_liveout(
; CHECK-NEXT: pred:
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: br i1 [[C0]], label [[DISPATCH:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]])
@ -273,11 +274,10 @@ define void @one_pred_with_extra_op_liveout_multiuse(i8 %v0, i8 %v1) {
; CHECK-LABEL: @one_pred_with_extra_op_liveout_multiuse(
; CHECK-NEXT: pred:
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: br i1 [[C0]], label [[DISPATCH:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]])
@ -314,13 +314,16 @@ define void @two_preds_with_extra_op_liveout(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: br i1 [[C2]], label [[DISPATCH]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
; CHECK-NEXT: br i1 [[C3]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[DOTOLD]], 0
; CHECK-NEXT: br i1 [[C3_OLD]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[V3_ADJ]], [[DISPATCH]] ], [ 0, [[PRED0]] ]
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]])
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: ret void
@ -361,14 +364,17 @@ define void @two_preds_with_extra_op_liveout_multiuse(i8 %v0, i8 %v1, i8 %v2, i8
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: br i1 [[C2]], label [[DISPATCH]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
; CHECK-NEXT: br i1 [[C3]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[DOTOLD]], 0
; CHECK-NEXT: br i1 [[C3_OLD]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[V3_ADJ]], [[DISPATCH]] ], [ 0, [[PRED0]] ]
; CHECK-NEXT: [[MERGE_LEFT_2:%.*]] = phi i8 [ [[V3_ADJ]], [[DISPATCH]] ], [ 42, [[PRED0]] ]
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
; CHECK-NEXT: [[MERGE_LEFT_2:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 42, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]])
; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT_2]])
; CHECK-NEXT: call void @sideeffect0()
@ -409,11 +415,10 @@ define void @one_pred_with_extra_op_eexternally_used_only(i8 %v0, i8 %v1) {
; CHECK-LABEL: @one_pred_with_extra_op_eexternally_used_only(
; CHECK-NEXT: pred:
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: br i1 [[C0]], label [[DISPATCH:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1]], 0
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]])
@ -441,11 +446,10 @@ define void @one_pred_with_extra_op_externally_used_only_multiuse(i8 %v0, i8 %v1
; CHECK-LABEL: @one_pred_with_extra_op_externally_used_only_multiuse(
; CHECK-NEXT: pred:
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: br i1 [[C0]], label [[DISPATCH:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1]], 0
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: call void @use8(i8 [[V1_ADJ]])
@ -482,13 +486,16 @@ define void @two_preds_with_extra_op_externally_used_only(i8 %v0, i8 %v1, i8 %v2
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: br i1 [[C2]], label [[DISPATCH]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
; CHECK-NEXT: br i1 [[C3]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[V3]], 0
; CHECK-NEXT: br i1 [[C3_OLD]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[V3_ADJ]], [[DISPATCH]] ], [ 0, [[PRED0]] ]
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]])
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: ret void
@ -529,14 +536,17 @@ define void @two_preds_with_extra_op_externally_used_only_multiuse(i8 %v0, i8 %v
; CHECK-NEXT: br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: br i1 [[C2]], label [[DISPATCH]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
; CHECK-NEXT: br i1 [[C3]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[V3]], 0
; CHECK-NEXT: br i1 [[C3_OLD]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[V3_ADJ]], [[DISPATCH]] ], [ 0, [[PRED0]] ]
; CHECK-NEXT: [[MERGE_LEFT_2:%.*]] = phi i8 [ [[V3_ADJ]], [[DISPATCH]] ], [ 42, [[PRED0]] ]
; CHECK-NEXT: [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
; CHECK-NEXT: [[MERGE_LEFT_2:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 42, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT]])
; CHECK-NEXT: call void @use8(i8 [[MERGE_LEFT_2]])
; CHECK-NEXT: call void @sideeffect0()