Revert "[SimplifyCFG] Extend jump-threading to allow live local defs … (#190269)

…(#135079)"

This reverts commit a757f23404c594f4a48b4ddb6625f88b349d11d5. Commit
causes reduce.cu file in hipcub/warp go from 2 minutes of compilation to
taking several hours.
This commit is contained in:
hjagasiaAMD 2026-04-02 18:05:26 -05:00 committed by GitHub
parent 9d18702cd8
commit a76750e6de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 776 additions and 1023 deletions

View File

@ -144,17 +144,18 @@ void f4(void) {
// CHECK-NEXT: br label
// -> rethrow
// finally.call-exit: Predecessor is the no-match case in the catch mechanism
// which rethrows.
// CHECK: call void @objc_exception_try_exit(ptr nonnull [[EXNDATA]])
// finally.call-exit: Predecessors are the @try and @catch fallthroughs
// as well as the no-match case in the catch mechanism. The i1 is whether
// to rethrow and should be true only in the last case.
// CHECK: phi ptr
// CHECK-NEXT: phi i1
// CHECK-NEXT: call void @objc_exception_try_exit(ptr nonnull [[EXNDATA]])
// CHECK-NEXT: call void @f4_help(i32 noundef 2)
// CHECK-NEXT: br label
// -> rethrow
// CHECK-NEXT: br i1
// -> ret, rethrow
// finally.end.critedge: Predecessors are the @try and @catch fallthroughs.
// CHECK: call void @objc_exception_try_exit(ptr nonnull [[EXNDATA]])
// CHECK-NEXT: call void @f4_help(i32 noundef 2)
// CHECK-NEXT: ret void
// ret:
// CHECK: ret void
// Catch mechanism:
// CHECK: call ptr @objc_exception_extract(ptr nonnull [[EXNDATA]])

File diff suppressed because it is too large Load Diff

View File

@ -201,11 +201,6 @@ static cl::opt<unsigned> MaxSwitchCasesPerResult(
"max-switch-cases-per-result", cl::Hidden, cl::init(16),
cl::desc("Limit cases to analyze when converting a switch to select"));
static cl::opt<unsigned> MaxJumpThreadingLiveBlocks(
"max-jump-threading-live-blocks", cl::Hidden, cl::init(24),
cl::desc("Limit number of blocks a define in a threaded block is allowed "
"to be live in"));
extern cl::opt<bool> ProfcheckDisableMetadataFixes;
} // end namespace llvm
@ -3444,27 +3439,8 @@ bool SimplifyCFGOpt::speculativelyExecuteBB(CondBrInst *BI,
return true;
}
using BlocksSet = SmallPtrSet<BasicBlock *, 8>;
// Return false if number of blocks searched is too much.
static bool findReaching(BasicBlock *BB, BasicBlock *DefBB,
BlocksSet &ReachesNonLocalUses) {
if (BB == DefBB)
return true;
if (!ReachesNonLocalUses.insert(BB).second)
return true;
if (ReachesNonLocalUses.size() > MaxJumpThreadingLiveBlocks)
return false;
for (BasicBlock *Pred : predecessors(BB))
if (!findReaching(Pred, DefBB, ReachesNonLocalUses))
return false;
return true;
}
/// Return true if we can thread a branch across this block.
static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB,
BlocksSet &NonLocalUseBlocks) {
static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB) {
int Size = 0;
EphemeralValueTracker EphTracker;
@ -3484,16 +3460,12 @@ static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB,
return false; // Don't clone large BB's.
}
// Record blocks with non-local uses of values defined in the current basic
// block.
// We can only support instructions that do not define values that are
// live outside of the current basic block.
for (User *U : I.users()) {
Instruction *UI = cast<Instruction>(U);
BasicBlock *UsedInBB = UI->getParent();
if (UsedInBB == BB) {
if (isa<PHINode>(UI))
return false;
} else
NonLocalUseBlocks.insert(UsedInBB);
if (UI->getParent() != BB || isa<PHINode>(UI))
return false;
}
// Looks ok, continue checking.
@ -3552,37 +3524,18 @@ foldCondBranchOnValueKnownInPredecessorImpl(CondBrInst *BI, DomTreeUpdater *DTU,
return false;
// Now we know that this block has multiple preds and two succs.
// Check that the block is small enough and record which non-local blocks use
// values defined in the block.
BlocksSet NonLocalUseBlocks;
BlocksSet ReachesNonLocalUseBlocks;
if (!blockIsSimpleEnoughToThreadThrough(BB, NonLocalUseBlocks))
// Check that the block is small enough and values defined in the block are
// not used outside of it.
if (!blockIsSimpleEnoughToThreadThrough(BB))
return false;
// Jump-threading can only be done to destinations where no values defined
// in BB are live.
// Quickly check if both destinations have uses. If so, jump-threading cannot
// be done.
if (NonLocalUseBlocks.contains(BI->getSuccessor(0)) &&
NonLocalUseBlocks.contains(BI->getSuccessor(1)))
return false;
// Search backward from NonLocalUseBlocks to find which blocks
// reach non-local uses.
for (BasicBlock *UseBB : NonLocalUseBlocks)
// Give up if too many blocks are searched.
if (!findReaching(UseBB, BB, ReachesNonLocalUseBlocks))
return false;
for (const auto &Pair : KnownValues) {
// Okay, we now know that all edges from PredBB should be revectored to
// branch to RealDest.
ConstantInt *CB = Pair.first;
ArrayRef<BasicBlock *> PredBBs = Pair.second.getArrayRef();
BasicBlock *RealDest = BI->getSuccessor(!CB->getZExtValue());
// Okay, we now know that all edges from PredBB should be revectored to
// branch to RealDest.
if (RealDest == BB)
continue; // Skip self loops.
@ -3592,10 +3545,6 @@ foldCondBranchOnValueKnownInPredecessorImpl(CondBrInst *BI, DomTreeUpdater *DTU,
}))
continue;
// Only revector to RealDest if no values defined in BB are live.
if (ReachesNonLocalUseBlocks.contains(RealDest))
continue;
LLVM_DEBUG({
dbgs() << "Condition " << *Cond << " in " << BB->getName()
<< " has value " << *Pair.first << " in predecessors:\n";

View File

@ -59,33 +59,37 @@ bb27: ; preds = %bb9, %bb8
define void @avoid_promotion_2_and(ptr nocapture noundef %arg) {
; CHECK-LABEL: avoid_promotion_2_and:
; CHECK: ; %bb.0: ; %entry
; CHECK-NEXT: mov x8, xzr
; CHECK-NEXT: add x9, x0, #32
; CHECK-NEXT: LBB1_1: ; %loop
; CHECK-NEXT: add x8, x0, #32
; CHECK-NEXT: b LBB1_2
; CHECK-NEXT: LBB1_1: ; %latch
; CHECK-NEXT: ; in Loop: Header=BB1_2 Depth=1
; CHECK-NEXT: cmp w9, #2
; CHECK-NEXT: add x8, x8, #56
; CHECK-NEXT: b.ls LBB1_4
; CHECK-NEXT: LBB1_2: ; %loop
; CHECK-NEXT: ; =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr w10, [x9, #20]
; CHECK-NEXT: cmp w10, #3
; CHECK-NEXT: b.lo LBB1_3
; CHECK-NEXT: ; %bb.2: ; %then
; CHECK-NEXT: ; in Loop: Header=BB1_1 Depth=1
; CHECK-NEXT: ldp w13, w12, [x9, #12]
; CHECK-NEXT: ldr w10, [x9]
; CHECK-NEXT: ldr w9, [x8, #20]
; CHECK-NEXT: cmp w9, #3
; CHECK-NEXT: b.lo LBB1_1
; CHECK-NEXT: ; %bb.3: ; %then
; CHECK-NEXT: ; in Loop: Header=BB1_2 Depth=1
; CHECK-NEXT: ldp w13, w12, [x8, #12]
; CHECK-NEXT: ldr w10, [x8]
; CHECK-NEXT: ldr x11, [x0]
; CHECK-NEXT: add x8, x8, #1
; CHECK-NEXT: ldr w14, [x9, #8]
; CHECK-NEXT: ldr w14, [x8, #8]
; CHECK-NEXT: lsl w10, w10, w13
; CHECK-NEXT: ldrb w11, [x11, x12]
; CHECK-NEXT: eor w10, w10, w11
; CHECK-NEXT: ldur w11, [x9, #-24]
; CHECK-NEXT: ldur w11, [x8, #-24]
; CHECK-NEXT: and w10, w10, w14
; CHECK-NEXT: ldp x14, x13, [x9, #-16]
; CHECK-NEXT: str w10, [x9], #56
; CHECK-NEXT: ldp x14, x13, [x8, #-16]
; CHECK-NEXT: str w10, [x8]
; CHECK-NEXT: and w11, w11, w12
; CHECK-NEXT: ldrh w15, [x13, w10, uxtw #1]
; CHECK-NEXT: strh w15, [x14, w11, uxtw #1]
; CHECK-NEXT: strh w12, [x13, w10, uxtw #1]
; CHECK-NEXT: b LBB1_1
; CHECK-NEXT: LBB1_3: ; %exit.critedge
; CHECK-NEXT: LBB1_4: ; %exit
; CHECK-NEXT: ret
entry:
br label %loop

View File

@ -1,195 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=simplifycfg -S < %s | FileCheck %s
; Allow jump-threading when values defined in the block are live outside of the block
; to those destinations in which the values are dead.
define void @testA(ptr %ptrA, ptr %ptrB, i64 %a, i64 %b) {
; CHECK-LABEL: define void @testA(
; CHECK-SAME: ptr [[PTRA:%.*]], ptr [[PTRB:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT: [[MAINA:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT: br i1 [[COND]], label %[[IFA:.*]], label %[[MAINC:.*]]
; CHECK: [[IFA]]:
; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[PTRA]], align 4
; CHECK-NEXT: store i64 [[TMP0]], ptr [[PTRB]], align 4
; CHECK-NEXT: br label %[[MAINC]]
; CHECK: [[MAINC]]:
; CHECK-NEXT: ret void
;
mainA:
%cond = icmp slt i64 %a, %b
br i1 %cond, label %ifA, label %mainB
ifA:
%518 = load i64, ptr %ptrA
br label %mainB
; %value is live outside of block mainB, but jump-threading
; can still occur to destination mainC, since %value is dead there.
; Subsequent CFG simplifications will create one if block.
mainB:
%value = phi i64 [ %518, %ifA ], [ zeroinitializer, %mainA ]
br i1 %cond, label %ifB, label %mainC
ifB:
store i64 %value, ptr %ptrB
br label %mainC
mainC:
ret void
}
define void @testB(ptr %ptrA, ptr %ptrB, i64 %a, i64 %b, i64 %c) {
; CHECK-LABEL: define void @testB(
; CHECK-SAME: ptr [[PTRA:%.*]], ptr [[PTRB:%.*]], i64 [[A:%.*]], i64 [[B:%.*]], i64 [[C:%.*]]) {
; CHECK-NEXT: [[MAINA:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT: br i1 [[COND]], label %[[IFA:.*]], label %[[MAINC:.*]]
; CHECK: [[IFA]]:
; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[PTRA]], align 4
; CHECK-NEXT: [[COND2:%.*]] = icmp slt i64 [[A]], [[C]]
; CHECK-NEXT: [[PTR_ARM1:%.*]] = getelementptr i64, ptr [[PTRB]], i64 8
; CHECK-NEXT: [[PTR_ARM2:%.*]] = getelementptr i64, ptr [[PTRB]], i64 16
; CHECK-NEXT: [[PTRC:%.*]] = select i1 [[COND2]], ptr [[PTR_ARM1]], ptr [[PTR_ARM2]]
; CHECK-NEXT: store i64 [[TMP0]], ptr [[PTRC]], align 4
; CHECK-NEXT: br label %[[MAINC]]
; CHECK: [[MAINC]]:
; CHECK-NEXT: ret void
;
mainA:
%cond = icmp slt i64 %a, %b
br i1 %cond, label %ifA, label %mainB
ifA:
%518 = load i64, ptr %ptrA
br label %mainB
; Use of %value is not in either immediate destination of mainB.
mainB:
%value = phi i64 [ %518, %ifA ], [ zeroinitializer, %mainA ]
br i1 %cond, label %ifB, label %mainC
ifB:
%cond2 = icmp slt i64 %a, %c
br i1 %cond2, label %ifB_arm1, label %ifB_arm2
ifB_arm1:
%ptr_arm1 = getelementptr i64, ptr %ptrB, i64 8
br label %ifB_join
ifB_arm2:
%ptr_arm2 = getelementptr i64, ptr %ptrB, i64 16
br label %ifB_join
ifB_join:
%ptrC = phi ptr [ %ptr_arm1, %ifB_arm1 ], [ %ptr_arm2, %ifB_arm2 ]
store i64 %value, ptr %ptrC
br label %mainC
mainC:
ret void
}
; Jump-threading is not done since %value is live in both destinations.
define void @testA_negative(ptr %ptrA, ptr %ptrB, ptr %ptrD, i64 %a, i64 %b) {
; CHECK-LABEL: define void @testA_negative(
; CHECK-SAME: ptr [[PTRA:%.*]], ptr [[PTRB:%.*]], ptr [[PTRD:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT: [[MAINA:.*]]:
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT: br i1 [[COND]], label %[[IFA:.*]], label %[[MAINB:.*]]
; CHECK: [[IFA]]:
; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[PTRA]], align 4
; CHECK-NEXT: br label %[[MAINB]]
; CHECK: [[MAINB]]:
; CHECK-NEXT: [[VALUE:%.*]] = phi i64 [ [[TMP0]], %[[IFA]] ], [ 0, %[[MAINA]] ]
; CHECK-NEXT: br i1 [[COND]], label %[[IFB:.*]], label %[[MAINC:.*]]
; CHECK: [[IFB]]:
; CHECK-NEXT: store i64 [[VALUE]], ptr [[PTRB]], align 4
; CHECK-NEXT: br label %[[MAINC]]
; CHECK: [[MAINC]]:
; CHECK-NEXT: store i64 [[VALUE]], ptr [[PTRD]], align 4
; CHECK-NEXT: ret void
;
mainA:
%cond = icmp slt i64 %a, %b
br i1 %cond, label %ifA, label %mainB
ifA:
%518 = load i64, ptr %ptrA
br label %mainB
mainB:
%value = phi i64 [ %518, %ifA ], [ zeroinitializer, %mainA ]
br i1 %cond, label %ifB, label %mainC
ifB:
store i64 %value, ptr %ptrB
br label %mainC
mainC:
store i64 %value, ptr %ptrD
ret void
}
; Jump-threading is not done since %value is live in both destinations.
define void @testB_negative(ptr %ptrA, ptr %ptrB, ptr %ptrD, i64 %a, i64 %b, i64 %c) {
; CHECK-LABEL: define void @testB_negative(
; CHECK-SAME: ptr [[PTRA:%.*]], ptr [[PTRB:%.*]], ptr [[PTRD:%.*]], i64 [[A:%.*]], i64 [[B:%.*]], i64 [[C:%.*]]) {
; CHECK-NEXT: [[MAINA:.*]]:
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT: br i1 [[COND]], label %[[IFA:.*]], label %[[MAINB:.*]]
; CHECK: [[IFA]]:
; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[PTRA]], align 4
; CHECK-NEXT: br label %[[MAINB]]
; CHECK: [[MAINB]]:
; CHECK-NEXT: [[VALUE:%.*]] = phi i64 [ [[TMP0]], %[[IFA]] ], [ 0, %[[MAINA]] ]
; CHECK-NEXT: br i1 [[COND]], label %[[IFB:.*]], label %[[MAINC:.*]]
; CHECK: [[IFB]]:
; CHECK-NEXT: [[COND2:%.*]] = icmp slt i64 [[A]], [[C]]
; CHECK-NEXT: [[PTR_ARM1:%.*]] = getelementptr i64, ptr [[PTRB]], i64 8
; CHECK-NEXT: [[PTR_ARM2:%.*]] = getelementptr i64, ptr [[PTRB]], i64 16
; CHECK-NEXT: [[PTRC:%.*]] = select i1 [[COND2]], ptr [[PTR_ARM1]], ptr [[PTR_ARM2]]
; CHECK-NEXT: store i64 [[VALUE]], ptr [[PTRC]], align 4
; CHECK-NEXT: br label %[[MAINC]]
; CHECK: [[MAINC]]:
; CHECK-NEXT: store i64 [[VALUE]], ptr [[PTRD]], align 4
; CHECK-NEXT: ret void
;
mainA:
%cond = icmp slt i64 %a, %b
br i1 %cond, label %ifA, label %mainB
ifA:
%518 = load i64, ptr %ptrA
br label %mainB
mainB:
%value = phi i64 [ %518, %ifA ], [ zeroinitializer, %mainA ]
br i1 %cond, label %ifB, label %mainC
ifB:
%cond2 = icmp slt i64 %a, %c
br i1 %cond2, label %ifB_arm1, label %ifB_arm2
ifB_arm1:
%ptr_arm1 = getelementptr i64, ptr %ptrB, i64 8
br label %ifB_join
ifB_arm2:
%ptr_arm2 = getelementptr i64, ptr %ptrB, i64 16
br label %ifB_join
ifB_join:
%ptrC = phi ptr [ %ptr_arm1, %ifB_arm1 ], [ %ptr_arm2, %ifB_arm2 ]
store i64 %value, ptr %ptrC
br label %mainC
mainC:
store i64 %value, ptr %ptrD
ret void
}

View File

@ -1,95 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=simplifycfg -S -max-jump-threading-live-blocks=3 < %s | FileCheck %s --check-prefixes=CHECK_LIMIT_3
; RUN: opt -passes=simplifycfg -S -max-jump-threading-live-blocks=4 < %s | FileCheck %s --check-prefixes=CHECK_LIMIT_4
; Test option -max-jump-threading-live-blocks=<num>
define void @testB(ptr %ptrA, ptr %ptrB, i64 %a, i64 %b, i64 %c) {
; CHECK_LIMIT_3-LABEL: define void @testB(
; CHECK_LIMIT_3-SAME: ptr [[PTRA:%.*]], ptr [[PTRB:%.*]], i64 [[A:%.*]], i64 [[B:%.*]], i64 [[C:%.*]]) {
; CHECK_LIMIT_3-NEXT: [[MAINA:.*]]:
; CHECK_LIMIT_3-NEXT: [[COND:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK_LIMIT_3-NEXT: br i1 [[COND]], label %[[IFA:.*]], label %[[MAINB:.*]]
; CHECK_LIMIT_3: [[IFA]]:
; CHECK_LIMIT_3-NEXT: [[TMP0:%.*]] = load i64, ptr [[PTRA]], align 4
; CHECK_LIMIT_3-NEXT: br label %[[MAINB]]
; CHECK_LIMIT_3: [[MAINB]]:
; CHECK_LIMIT_3-NEXT: [[VALUE:%.*]] = phi i64 [ [[TMP0]], %[[IFA]] ], [ 0, %[[MAINA]] ]
; CHECK_LIMIT_3-NEXT: br i1 [[COND]], label %[[IFB:.*]], label %[[MAINC:.*]]
; CHECK_LIMIT_3: [[IFB]]:
; CHECK_LIMIT_3-NEXT: [[COND2:%.*]] = icmp slt i64 [[A]], [[C]]
; CHECK_LIMIT_3-NEXT: br i1 [[COND2]], label %[[IFB_ARM1:.*]], label %[[IFB_ARM2:.*]]
; CHECK_LIMIT_3: [[IFB_ARM1]]:
; CHECK_LIMIT_3-NEXT: [[PTR_ARM1:%.*]] = getelementptr i64, ptr [[PTRB]], i64 8
; CHECK_LIMIT_3-NEXT: store i128 0, ptr [[PTR_ARM1]], align 4
; CHECK_LIMIT_3-NEXT: br label %[[IFB_JOIN:.*]]
; CHECK_LIMIT_3: [[IFB_ARM2]]:
; CHECK_LIMIT_3-NEXT: [[PTR_ARM2:%.*]] = getelementptr i64, ptr [[PTRB]], i64 16
; CHECK_LIMIT_3-NEXT: store i128 0, ptr [[PTR_ARM2]], align 4
; CHECK_LIMIT_3-NEXT: br label %[[IFB_JOIN]]
; CHECK_LIMIT_3: [[IFB_JOIN]]:
; CHECK_LIMIT_3-NEXT: [[PTRC:%.*]] = phi ptr [ [[PTR_ARM1]], %[[IFB_ARM1]] ], [ [[PTR_ARM2]], %[[IFB_ARM2]] ]
; CHECK_LIMIT_3-NEXT: store i64 [[VALUE]], ptr [[PTRC]], align 4
; CHECK_LIMIT_3-NEXT: br label %[[MAINC]]
; CHECK_LIMIT_3: [[MAINC]]:
; CHECK_LIMIT_3-NEXT: ret void
;
; CHECK_LIMIT_4-LABEL: define void @testB(
; CHECK_LIMIT_4-SAME: ptr [[PTRA:%.*]], ptr [[PTRB:%.*]], i64 [[A:%.*]], i64 [[B:%.*]], i64 [[C:%.*]]) {
; CHECK_LIMIT_4-NEXT: [[MAINA:.*:]]
; CHECK_LIMIT_4-NEXT: [[COND:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK_LIMIT_4-NEXT: br i1 [[COND]], label %[[IFA:.*]], label %[[MAINC:.*]]
; CHECK_LIMIT_4: [[IFA]]:
; CHECK_LIMIT_4-NEXT: [[TMP0:%.*]] = load i64, ptr [[PTRA]], align 4
; CHECK_LIMIT_4-NEXT: [[COND2:%.*]] = icmp slt i64 [[A]], [[C]]
; CHECK_LIMIT_4-NEXT: br i1 [[COND2]], label %[[IFB_ARM1:.*]], label %[[IFB_ARM2:.*]]
; CHECK_LIMIT_4: [[IFB_ARM1]]:
; CHECK_LIMIT_4-NEXT: [[PTR_ARM1:%.*]] = getelementptr i64, ptr [[PTRB]], i64 8
; CHECK_LIMIT_4-NEXT: store i128 0, ptr [[PTR_ARM1]], align 4
; CHECK_LIMIT_4-NEXT: br label %[[IFB_JOIN:.*]]
; CHECK_LIMIT_4: [[IFB_ARM2]]:
; CHECK_LIMIT_4-NEXT: [[PTR_ARM2:%.*]] = getelementptr i64, ptr [[PTRB]], i64 16
; CHECK_LIMIT_4-NEXT: store i128 0, ptr [[PTR_ARM2]], align 4
; CHECK_LIMIT_4-NEXT: br label %[[IFB_JOIN]]
; CHECK_LIMIT_4: [[IFB_JOIN]]:
; CHECK_LIMIT_4-NEXT: [[PTRC:%.*]] = phi ptr [ [[PTR_ARM1]], %[[IFB_ARM1]] ], [ [[PTR_ARM2]], %[[IFB_ARM2]] ]
; CHECK_LIMIT_4-NEXT: store i64 [[TMP0]], ptr [[PTRC]], align 4
; CHECK_LIMIT_4-NEXT: br label %[[MAINC]]
; CHECK_LIMIT_4: [[MAINC]]:
; CHECK_LIMIT_4-NEXT: ret void
;
mainA:
%cond = icmp slt i64 %a, %b
br i1 %cond, label %ifA, label %mainB
ifA:
%518 = load i64, ptr %ptrA
br label %mainB
; Use of %value is not in either immediate destination of mainB.
mainB:
%value = phi i64 [ %518, %ifA ], [ zeroinitializer, %mainA ]
br i1 %cond, label %ifB, label %mainC
ifB:
%cond2 = icmp slt i64 %a, %c
br i1 %cond2, label %ifB_arm1, label %ifB_arm2
ifB_arm1:
%ptr_arm1 = getelementptr i64, ptr %ptrB, i64 8
store i128 0, ptr %ptr_arm1
br label %ifB_join
ifB_arm2:
%ptr_arm2 = getelementptr i64, ptr %ptrB, i64 16
store i128 0, ptr %ptr_arm2
br label %ifB_join
ifB_join:
%ptrC = phi ptr [ %ptr_arm1, %ifB_arm1 ], [ %ptr_arm2, %ifB_arm2 ]
store i64 %value, ptr %ptrC
br label %mainC
mainC:
ret void
}