Skip to content

Commit e09958d

Browse files
committed
[LoopPeel] Peel loops with exits followed by an unreachable or deopt block
Added support for peeling loops with exits that are followed either by an unreachable-terminated block or block that has a terminatnig deoptimize call. All blocks in the sequence must have an unique successor, maybe except for the last one. Reviewed By: mkazantsev Differential Revision: https://reviews.llvm.org/D110922
1 parent e2024d7 commit e09958d

File tree

4 files changed

+71
-15
lines changed

4 files changed

+71
-15
lines changed

llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ void ReplaceInstWithInst(BasicBlock::InstListType &BIL,
129129
/// To. Copies DebugLoc from BI to I, if I doesn't already have a DebugLoc.
130130
void ReplaceInstWithInst(Instruction *From, Instruction *To);
131131

132+
/// Check if we can prove that all paths starting from this block converge
133+
/// to a block that either has a @llvm.experimental.deoptimize call
134+
/// prior to its terminating return instruction or is terminated by unreachable.
135+
/// All blocks in the traversed sequence must have an unique successor, maybe
136+
/// except for the last one.
137+
bool IsBlockFollowedByDeoptOrUnreachable(const BasicBlock *BB);
138+
132139
/// Option class for critical edge splitting.
133140
///
134141
/// This provides a builder interface for overriding the default options used

llvm/lib/Transforms/Utils/BasicBlockUtils.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/IR/Value.h"
4040
#include "llvm/IR/ValueHandle.h"
4141
#include "llvm/Support/Casting.h"
42+
#include "llvm/Support/CommandLine.h"
4243
#include "llvm/Support/Debug.h"
4344
#include "llvm/Support/raw_ostream.h"
4445
#include "llvm/Transforms/Utils/Local.h"
@@ -52,6 +53,12 @@ using namespace llvm;
5253

5354
#define DEBUG_TYPE "basicblock-utils"
5455

56+
static cl::opt<unsigned> MaxDeoptOrUnreachableSuccessorCheckDepth(
57+
"max-deopt-or-unreachable-succ-check-depth", cl::init(8), cl::Hidden,
58+
cl::desc("Set the maximum path length when checking whether a basic block "
59+
"is followed by a block that either has a terminating "
60+
"deoptimizing call or is terminated with an unreachable"));
61+
5562
void llvm::DetatchDeadBlocks(
5663
ArrayRef<BasicBlock *> BBs,
5764
SmallVectorImpl<DominatorTree::UpdateType> *Updates,
@@ -485,6 +492,20 @@ void llvm::ReplaceInstWithInst(BasicBlock::InstListType &BIL,
485492
BI = New;
486493
}
487494

495+
bool llvm::IsBlockFollowedByDeoptOrUnreachable(const BasicBlock *BB) {
496+
// Remember visited blocks to avoid infinite loop
497+
SmallPtrSet<const BasicBlock *, 8> VisitedBlocks;
498+
unsigned Depth = 0;
499+
while (BB && Depth++ < MaxDeoptOrUnreachableSuccessorCheckDepth &&
500+
VisitedBlocks.insert(BB).second) {
501+
if (BB->getTerminatingDeoptimizeCall() ||
502+
isa<UnreachableInst>(BB->getTerminator()))
503+
return true;
504+
BB = BB->getUniqueSuccessor();
505+
}
506+
return false;
507+
}
508+
488509
void llvm::ReplaceInstWithInst(Instruction *From, Instruction *To) {
489510
BasicBlock::iterator BI(From);
490511
ReplaceInstWithInst(From->getParent()->getInstList(), BI, To);

llvm/lib/Transforms/Utils/LoopPeel.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,15 @@ bool llvm::canPeel(Loop *L) {
103103
SmallVector<BasicBlock *, 4> Exits;
104104
L->getUniqueNonLatchExitBlocks(Exits);
105105
// The latch must either be the only exiting block or all non-latch exit
106-
// blocks have either a deopt or unreachable terminator. Both deopt and
107-
// unreachable terminators are a strong indication they are not taken. Note
108-
// that this is a profitability check, not a legality check. Also note that
109-
// LoopPeeling currently can only update the branch weights of latch blocks
110-
// and branch weights to blocks with deopt or unreachable do not need
106+
// blocks have either a deopt or unreachable terminator or compose a chain of
107+
// blocks where the last one is either deopt or unreachable terminated. Both
108+
// deopt and unreachable terminators are a strong indication they are not
109+
// taken. Note that this is a profitability check, not a legality check. Also
110+
// note that LoopPeeling currently can only update the branch weights of latch
111+
// blocks and branch weights to blocks with deopt or unreachable do not need
111112
// updating.
112113
return all_of(Exits, [](const BasicBlock *BB) {
113-
return BB->getTerminatingDeoptimizeCall() ||
114-
isa<UnreachableInst>(BB->getTerminator());
114+
return IsBlockFollowedByDeoptOrUnreachable(BB);
115115
});
116116
}
117117

llvm/test/Transforms/LoopUnroll/peel-multiple-unreachable-exits.ll

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,28 +193,56 @@ unreachable.exit:
193193
define void @peel_exits_to_blocks_branch_to_unreachable_block(i32* %ptr, i32 %N, i32 %x, i1 %c.1) {
194194
; CHECK-LABEL: @peel_exits_to_blocks_branch_to_unreachable_block(
195195
; CHECK-NEXT: entry:
196+
; CHECK-NEXT: br label [[LOOP_HEADER_PEEL_BEGIN:%.*]]
197+
; CHECK: loop.header.peel.begin:
198+
; CHECK-NEXT: br label [[LOOP_HEADER_PEEL:%.*]]
199+
; CHECK: loop.header.peel:
200+
; CHECK-NEXT: [[C_PEEL:%.*]] = icmp ult i32 1, 2
201+
; CHECK-NEXT: br i1 [[C_PEEL]], label [[THEN_PEEL:%.*]], label [[ELSE_PEEL:%.*]]
202+
; CHECK: else.peel:
203+
; CHECK-NEXT: [[C_2_PEEL:%.*]] = icmp eq i32 1, [[X:%.*]]
204+
; CHECK-NEXT: br i1 [[C_2_PEEL]], label [[EXIT_2:%.*]], label [[LOOP_LATCH_PEEL:%.*]]
205+
; CHECK: then.peel:
206+
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[EXIT_1:%.*]], label [[LOOP_LATCH_PEEL]]
207+
; CHECK: loop.latch.peel:
208+
; CHECK-NEXT: [[M_PEEL:%.*]] = phi i32 [ 0, [[THEN_PEEL]] ], [ [[X]], [[ELSE_PEEL]] ]
209+
; CHECK-NEXT: [[GEP_PEEL:%.*]] = getelementptr i32, i32* [[PTR:%.*]], i32 1
210+
; CHECK-NEXT: store i32 [[M_PEEL]], i32* [[GEP_PEEL]], align 4
211+
; CHECK-NEXT: [[IV_NEXT_PEEL:%.*]] = add nuw nsw i32 1, 1
212+
; CHECK-NEXT: [[C_3_PEEL:%.*]] = icmp ult i32 1, 1000
213+
; CHECK-NEXT: br i1 [[C_3_PEEL]], label [[LOOP_HEADER_PEEL_NEXT:%.*]], label [[EXIT:%.*]]
214+
; CHECK: loop.header.peel.next:
215+
; CHECK-NEXT: br label [[LOOP_HEADER_PEEL_NEXT1:%.*]]
216+
; CHECK: loop.header.peel.next1:
217+
; CHECK-NEXT: br label [[ENTRY_PEEL_NEWPH:%.*]]
218+
; CHECK: entry.peel.newph:
196219
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
197220
; CHECK: loop.header:
198-
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
199-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], 2
200-
; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]
221+
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT_PEEL]], [[ENTRY_PEEL_NEWPH]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
222+
; CHECK-NEXT: br i1 false, label [[THEN:%.*]], label [[ELSE:%.*]]
201223
; CHECK: then:
202-
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[EXIT_1:%.*]], label [[LOOP_LATCH]]
224+
; CHECK-NEXT: br i1 [[C_1]], label [[EXIT_1_LOOPEXIT:%.*]], label [[LOOP_LATCH]]
203225
; CHECK: else:
204-
; CHECK-NEXT: [[C_2:%.*]] = icmp eq i32 [[IV]], [[X:%.*]]
205-
; CHECK-NEXT: br i1 [[C_2]], label [[EXIT_2:%.*]], label [[LOOP_LATCH]]
226+
; CHECK-NEXT: [[C_2:%.*]] = icmp eq i32 [[IV]], [[X]]
227+
; CHECK-NEXT: br i1 [[C_2]], label [[EXIT_2_LOOPEXIT:%.*]], label [[LOOP_LATCH]]
206228
; CHECK: loop.latch:
207229
; CHECK-NEXT: [[M:%.*]] = phi i32 [ 0, [[THEN]] ], [ [[X]], [[ELSE]] ]
208-
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, i32* [[PTR:%.*]], i32 [[IV]]
230+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, i32* [[PTR]], i32 [[IV]]
209231
; CHECK-NEXT: store i32 [[M]], i32* [[GEP]], align 4
210232
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
211233
; CHECK-NEXT: [[C_3:%.*]] = icmp ult i32 [[IV]], 1000
212-
; CHECK-NEXT: br i1 [[C_3]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
234+
; CHECK-NEXT: br i1 [[C_3]], label [[LOOP_HEADER]], label [[EXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP2:![0-9]+]]
235+
; CHECK: exit.loopexit:
236+
; CHECK-NEXT: br label [[EXIT]]
213237
; CHECK: exit:
214238
; CHECK-NEXT: ret void
239+
; CHECK: exit.1.loopexit:
240+
; CHECK-NEXT: br label [[EXIT_1]]
215241
; CHECK: exit.1:
216242
; CHECK-NEXT: call void @foo()
217243
; CHECK-NEXT: br label [[UNREACHABLE_TERM:%.*]]
244+
; CHECK: exit.2.loopexit:
245+
; CHECK-NEXT: br label [[EXIT_2]]
218246
; CHECK: exit.2:
219247
; CHECK-NEXT: call void @bar()
220248
; CHECK-NEXT: br label [[UNREACHABLE_TERM]]

0 commit comments

Comments
 (0)