Skip to content

Commit 4c98070

Browse files
committed
[LoopBoundSplit] Handle the case in which exiting block is loop header
Update the incoming value of phi nodes in header of post-loop correctly. Differential Revision: https://reviews.llvm.org/D110060
1 parent dd5991c commit 4c98070

File tree

4 files changed

+188
-48
lines changed

4 files changed

+188
-48
lines changed

llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct ConditionInfo {
4040
ICmpInst::Predicate Pred;
4141
/// AddRec llvm value
4242
Value *AddRecValue;
43+
/// Non PHI AddRec llvm value
44+
Value *NonPHIAddRecValue;
4345
/// Bound llvm value
4446
Value *BoundValue;
4547
/// AddRec SCEV
@@ -55,7 +57,7 @@ struct ConditionInfo {
5557
} // namespace
5658

5759
static void analyzeICmp(ScalarEvolution &SE, ICmpInst *ICmp,
58-
ConditionInfo &Cond) {
60+
ConditionInfo &Cond, const Loop &L) {
5961
Cond.ICmp = ICmp;
6062
if (match(ICmp, m_ICmp(Cond.Pred, m_Value(Cond.AddRecValue),
6163
m_Value(Cond.BoundValue)))) {
@@ -72,6 +74,14 @@ static void analyzeICmp(ScalarEvolution &SE, ICmpInst *ICmp,
7274

7375
Cond.AddRecSCEV = dyn_cast<SCEVAddRecExpr>(AddRecSCEV);
7476
Cond.BoundSCEV = BoundSCEV;
77+
Cond.NonPHIAddRecValue = Cond.AddRecValue;
78+
79+
// If the Cond.AddRecValue is PHI node, update Cond.NonPHIAddRecValue with
80+
// value from backedge.
81+
if (Cond.AddRecSCEV && isa<PHINode>(Cond.AddRecValue)) {
82+
PHINode *PN = cast<PHINode>(Cond.AddRecValue);
83+
Cond.NonPHIAddRecValue = PN->getIncomingValueForBlock(L.getLoopLatch());
84+
}
7585
}
7686
}
7787

@@ -123,7 +133,7 @@ static bool calculateUpperBound(const Loop &L, ScalarEvolution &SE,
123133
static bool hasProcessableCondition(const Loop &L, ScalarEvolution &SE,
124134
ICmpInst *ICmp, ConditionInfo &Cond,
125135
bool IsExitCond) {
126-
analyzeICmp(SE, ICmp, Cond);
136+
analyzeICmp(SE, ICmp, Cond, L);
127137

128138
// The BoundSCEV should be evaluated at loop entry.
129139
if (!SE.isAvailableAtLoopEntry(Cond.BoundSCEV, &L))
@@ -353,13 +363,45 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
353363
".split", &LI, &DT, PostLoopBlocks);
354364
remapInstructionsInBlocks(PostLoopBlocks, VMap);
355365

356-
// Add conditional branch to check we can skip post-loop in its preheader.
357366
BasicBlock *PostLoopPreHeader = PostLoop->getLoopPreheader();
358-
IRBuilder<> Builder(PostLoopPreHeader);
367+
IRBuilder<> Builder(&PostLoopPreHeader->front());
368+
369+
// Update phi nodes in header of post-loop.
370+
bool isExitingLatch =
371+
(L.getExitingBlock() == L.getLoopLatch()) ? true : false;
372+
Value *ExitingCondLCSSAPhi = nullptr;
373+
for (PHINode &PN : L.getHeader()->phis()) {
374+
// Create LCSSA phi node in preheader of post-loop.
375+
PHINode *LCSSAPhi =
376+
Builder.CreatePHI(PN.getType(), 1, PN.getName() + ".lcssa");
377+
LCSSAPhi->setDebugLoc(PN.getDebugLoc());
378+
// If the exiting block is loop latch, the phi does not have the update at
379+
// last iteration. In this case, update lcssa phi with value from backedge.
380+
LCSSAPhi->addIncoming(
381+
isExitingLatch ? PN.getIncomingValueForBlock(L.getLoopLatch()) : &PN,
382+
L.getExitingBlock());
383+
384+
// Update the start value of phi node in post-loop with the LCSSA phi node.
385+
PHINode *PostLoopPN = cast<PHINode>(VMap[&PN]);
386+
PostLoopPN->setIncomingValueForBlock(PostLoopPreHeader, LCSSAPhi);
387+
388+
// Find PHI with exiting condition from pre-loop. The PHI should be
389+
// SCEVAddRecExpr and have same incoming value from backedge with
390+
// ExitingCond.
391+
if (!SE.isSCEVable(PN.getType()))
392+
continue;
393+
394+
const SCEVAddRecExpr *PhiSCEV = dyn_cast<SCEVAddRecExpr>(SE.getSCEV(&PN));
395+
if (PhiSCEV && ExitingCond.NonPHIAddRecValue ==
396+
PN.getIncomingValueForBlock(L.getLoopLatch()))
397+
ExitingCondLCSSAPhi = LCSSAPhi;
398+
}
399+
400+
// Add conditional branch to check we can skip post-loop in its preheader.
359401
Instruction *OrigBI = PostLoopPreHeader->getTerminator();
360402
ICmpInst::Predicate Pred = ICmpInst::ICMP_NE;
361403
Value *Cond =
362-
Builder.CreateICmp(Pred, ExitingCond.AddRecValue, ExitingCond.BoundValue);
404+
Builder.CreateICmp(Pred, ExitingCondLCSSAPhi, ExitingCond.BoundValue);
363405
Builder.CreateCondBr(Cond, PostLoop->getHeader(), PostLoop->getExitBlock());
364406
OrigBI->eraseFromParent();
365407

@@ -380,21 +422,6 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
380422
// Replace exiting bound value of pre-loop NewBound.
381423
ExitingCond.ICmp->setOperand(1, NewBoundValue);
382424

383-
// Replace IV's start value of post-loop by NewBound.
384-
for (PHINode &PN : L.getHeader()->phis()) {
385-
// Find PHI with exiting condition from pre-loop.
386-
if (SE.isSCEVable(PN.getType()) && isa<SCEVAddRecExpr>(SE.getSCEV(&PN))) {
387-
for (Value *Op : PN.incoming_values()) {
388-
if (Op == ExitingCond.AddRecValue) {
389-
// Find cloned PHI for post-loop.
390-
PHINode *PostLoopPN = cast<PHINode>(VMap[&PN]);
391-
PostLoopPN->setIncomingValueForBlock(PostLoopPreHeader,
392-
NewBoundValue);
393-
}
394-
}
395-
}
396-
}
397-
398425
// Replace SplitCandidateCond.BI's condition of pre-loop by True.
399426
LLVMContext &Context = PreHeader->getContext();
400427
SplitCandidateCond.BI->setCondition(ConstantInt::getTrue(Context));
@@ -411,15 +438,25 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
411438
ExitingCond.BI->setSuccessor(1, PostLoopPreHeader);
412439

413440
// Update phi node in exit block of post-loop.
441+
Builder.SetInsertPoint(&PostLoopPreHeader->front());
414442
for (PHINode &PN : PostLoop->getExitBlock()->phis()) {
415443
for (auto i : seq<int>(0, PN.getNumOperands())) {
416444
// Check incoming block is pre-loop's exiting block.
417445
if (PN.getIncomingBlock(i) == L.getExitingBlock()) {
446+
Value *IncomingValue = PN.getIncomingValue(i);
447+
448+
// Create LCSSA phi node for incoming value.
449+
PHINode *LCSSAPhi =
450+
Builder.CreatePHI(PN.getType(), 1, PN.getName() + ".lcssa");
451+
LCSSAPhi->setDebugLoc(PN.getDebugLoc());
452+
LCSSAPhi->addIncoming(IncomingValue, PN.getIncomingBlock(i));
453+
418454
// Replace pre-loop's exiting block by post-loop's preheader.
419455
PN.setIncomingBlock(i, PostLoopPreHeader);
456+
// Replace incoming value by LCSSAPhi.
457+
PN.setIncomingValue(i, LCSSAPhi);
420458
// Add a new incoming value with post-loop's exiting block.
421-
PN.addIncoming(VMap[PN.getIncomingValue(i)],
422-
PostLoop->getExitingBlock());
459+
PN.addIncoming(VMap[IncomingValue], PostLoop->getExitingBlock());
423460
}
424461
}
425462
}
@@ -432,10 +469,7 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
432469
SE.forgetLoop(&L);
433470

434471
// Canonicalize loops.
435-
// TODO: Try to update LCSSA information according to above change.
436-
formLCSSA(L, DT, &LI, &SE);
437472
simplifyLoop(&L, &DT, &LI, &SE, nullptr, nullptr, true);
438-
formLCSSA(*PostLoop, DT, &LI, &SE);
439473
simplifyLoop(PostLoop, &DT, &LI, &SE, nullptr, nullptr, true);
440474

441475
// Add new post-loop to loop pass manager.

llvm/test/Transforms/LoopBoundSplit/bug-loop-bound-split-phi-in-exit-block.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ define i16 @test_int() {
2424
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i16 [[I]], 3
2525
; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_BODY]], label [[ENTRY_SPLIT_SPLIT:%.*]]
2626
; CHECK: entry.split.split:
27-
; CHECK-NEXT: [[CALL_LCSSA1:%.*]] = phi i16 [ [[CALL]], [[COND_END]] ]
28-
; CHECK-NEXT: [[I_LCSSA:%.*]] = phi i16 [ [[I]], [[COND_END]] ]
27+
; CHECK-NEXT: [[CALL_LCSSA_LCSSA:%.*]] = phi i16 [ [[CALL]], [[COND_END]] ]
28+
; CHECK-NEXT: [[I_LCSSA:%.*]] = phi i16 [ [[ADD]], [[COND_END]] ]
2929
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i16 [[I_LCSSA]], 11
3030
; CHECK-NEXT: br i1 [[TMP0]], label [[FOR_BODY_SPLIT_PREHEADER:%.*]], label [[END:%.*]]
3131
; CHECK: for.body.split.preheader:
3232
; CHECK-NEXT: br label [[FOR_BODY_SPLIT:%.*]]
3333
; CHECK: for.body.split:
34-
; CHECK-NEXT: [[I_SPLIT:%.*]] = phi i16 [ [[ADD_SPLIT:%.*]], [[COND_END_SPLIT:%.*]] ], [ 0, [[FOR_BODY_SPLIT_PREHEADER]] ]
34+
; CHECK-NEXT: [[I_SPLIT:%.*]] = phi i16 [ [[ADD_SPLIT:%.*]], [[COND_END_SPLIT:%.*]] ], [ [[I_LCSSA]], [[FOR_BODY_SPLIT_PREHEADER]] ]
3535
; CHECK-NEXT: [[CMP1_SPLIT:%.*]] = icmp ult i16 [[I_SPLIT]], 3
3636
; CHECK-NEXT: br i1 false, label [[COND_TRUE_SPLIT:%.*]], label [[COND_FALSE_SPLIT:%.*]]
3737
; CHECK: cond.false.split:
@@ -47,7 +47,7 @@ define i16 @test_int() {
4747
; CHECK-NEXT: [[CALL_LCSSA_PH:%.*]] = phi i16 [ [[CALL_SPLIT]], [[COND_END_SPLIT]] ]
4848
; CHECK-NEXT: br label [[END]]
4949
; CHECK: end:
50-
; CHECK-NEXT: [[CALL_LCSSA:%.*]] = phi i16 [ [[CALL_LCSSA1]], [[ENTRY_SPLIT_SPLIT]] ], [ [[CALL_LCSSA_PH]], [[END_LOOPEXIT]] ]
50+
; CHECK-NEXT: [[CALL_LCSSA:%.*]] = phi i16 [ [[CALL_LCSSA_LCSSA]], [[ENTRY_SPLIT_SPLIT]] ], [ [[CALL_LCSSA_PH]], [[END_LOOPEXIT]] ]
5151
; CHECK-NEXT: ret i16 [[CALL_LCSSA]]
5252
;
5353
entry:
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -passes=loop-bound-split -S < %s | FileCheck %s
3+
4+
@B = external global [10 x i16], align 1
5+
6+
define void @test() {
7+
; CHECK-LABEL: @test(
8+
; CHECK-NEXT: entry:
9+
; CHECK-NEXT: br label [[ENTRY_SPLIT:%.*]]
10+
; CHECK: entry.split:
11+
; CHECK-NEXT: br label [[FOR_COND:%.*]]
12+
; CHECK: for.cond:
13+
; CHECK-NEXT: [[I_0:%.*]] = phi i16 [ 0, [[ENTRY_SPLIT]] ], [ [[INC_0:%.*]], [[FOR_INC:%.*]] ]
14+
; CHECK-NEXT: [[I_1:%.*]] = phi i16 [ 10, [[ENTRY_SPLIT]] ], [ [[INC_0]], [[FOR_INC]] ]
15+
; CHECK-NEXT: [[I_2:%.*]] = phi i16 [ 10, [[ENTRY_SPLIT]] ], [ [[INC_2:%.*]], [[FOR_INC]] ]
16+
; CHECK-NEXT: [[I_3:%.*]] = phi i16 [ 15, [[ENTRY_SPLIT]] ], [ 30, [[FOR_INC]] ]
17+
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i16 [[I_0]], 5
18+
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[FOR_BODY:%.*]]
19+
; CHECK: for.body:
20+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i16 [[I_0]], 5
21+
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i16], [10 x i16]* @B, i16 0, i16 [[I_0]]
22+
; CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* [[ARRAYIDX]], align 1
23+
; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
24+
; CHECK: if.then:
25+
; CHECK-NEXT: call void @foo(i16 [[TMP0]], i16 [[I_3]])
26+
; CHECK-NEXT: br label [[FOR_INC]]
27+
; CHECK: if.else:
28+
; CHECK-NEXT: call void @bar(i16 [[TMP0]], i16 [[I_3]])
29+
; CHECK-NEXT: br label [[FOR_INC]]
30+
; CHECK: for.inc:
31+
; CHECK-NEXT: [[INC_0]] = add nuw nsw i16 [[I_0]], 1
32+
; CHECK-NEXT: [[INC_2]] = add nuw nsw i16 [[I_2]], 2
33+
; CHECK-NEXT: br label [[FOR_COND]]
34+
; CHECK: entry.split.split:
35+
; CHECK-NEXT: [[I_0_LCSSA:%.*]] = phi i16 [ [[I_0]], [[FOR_COND]] ]
36+
; CHECK-NEXT: [[I_1_LCSSA:%.*]] = phi i16 [ [[I_1]], [[FOR_COND]] ]
37+
; CHECK-NEXT: [[I_2_LCSSA:%.*]] = phi i16 [ [[I_2]], [[FOR_COND]] ]
38+
; CHECK-NEXT: [[I_3_LCSSA:%.*]] = phi i16 [ [[I_3]], [[FOR_COND]] ]
39+
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i16 [[I_0_LCSSA]], 10
40+
; CHECK-NEXT: br i1 [[TMP1]], label [[FOR_COND_SPLIT_PREHEADER:%.*]], label [[FOR_END:%.*]]
41+
; CHECK: for.cond.split.preheader:
42+
; CHECK-NEXT: br label [[FOR_COND_SPLIT:%.*]]
43+
; CHECK: for.cond.split:
44+
; CHECK-NEXT: [[I_0_SPLIT:%.*]] = phi i16 [ [[INC_0_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[I_0_LCSSA]], [[FOR_COND_SPLIT_PREHEADER]] ]
45+
; CHECK-NEXT: [[I_1_SPLIT:%.*]] = phi i16 [ [[INC_0_SPLIT]], [[FOR_INC_SPLIT]] ], [ [[I_1_LCSSA]], [[FOR_COND_SPLIT_PREHEADER]] ]
46+
; CHECK-NEXT: [[I_2_SPLIT:%.*]] = phi i16 [ [[INC_2_SPLIT:%.*]], [[FOR_INC_SPLIT]] ], [ [[I_2_LCSSA]], [[FOR_COND_SPLIT_PREHEADER]] ]
47+
; CHECK-NEXT: [[I_3_SPLIT:%.*]] = phi i16 [ 30, [[FOR_INC_SPLIT]] ], [ [[I_3_LCSSA]], [[FOR_COND_SPLIT_PREHEADER]] ]
48+
; CHECK-NEXT: [[EXITCOND_NOT_SPLIT:%.*]] = icmp eq i16 [[I_0_SPLIT]], 10
49+
; CHECK-NEXT: br i1 [[EXITCOND_NOT_SPLIT]], label [[FOR_END_LOOPEXIT:%.*]], label [[FOR_BODY_SPLIT:%.*]]
50+
; CHECK: for.body.split:
51+
; CHECK-NEXT: [[CMP1_SPLIT:%.*]] = icmp ult i16 [[I_0_SPLIT]], 5
52+
; CHECK-NEXT: [[ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds [10 x i16], [10 x i16]* @B, i16 0, i16 [[I_0_SPLIT]]
53+
; CHECK-NEXT: [[TMP2:%.*]] = load i16, i16* [[ARRAYIDX_SPLIT]], align 1
54+
; CHECK-NEXT: br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
55+
; CHECK: if.else.split:
56+
; CHECK-NEXT: call void @bar(i16 [[TMP2]], i16 [[I_3_SPLIT]])
57+
; CHECK-NEXT: br label [[FOR_INC_SPLIT]]
58+
; CHECK: if.then.split:
59+
; CHECK-NEXT: call void @foo(i16 [[TMP2]], i16 [[I_3_SPLIT]])
60+
; CHECK-NEXT: br label [[FOR_INC_SPLIT]]
61+
; CHECK: for.inc.split:
62+
; CHECK-NEXT: [[INC_0_SPLIT]] = add nuw nsw i16 [[I_0_SPLIT]], 1
63+
; CHECK-NEXT: [[INC_2_SPLIT]] = add nuw nsw i16 [[I_2_SPLIT]], 2
64+
; CHECK-NEXT: br label [[FOR_COND_SPLIT]]
65+
; CHECK: for.end.loopexit:
66+
; CHECK-NEXT: br label [[FOR_END]]
67+
; CHECK: for.end:
68+
; CHECK-NEXT: ret void
69+
;
70+
entry:
71+
br label %for.cond
72+
73+
for.cond: ; preds = %for.inc, %entry
74+
%i.0 = phi i16 [ 0, %entry ], [ %inc.0, %for.inc ]
75+
%i.1 = phi i16 [ 10, %entry ], [ %inc.0, %for.inc ]
76+
%i.2 = phi i16 [ 10, %entry ], [ %inc.2, %for.inc ]
77+
%i.3 = phi i16 [ 15, %entry ], [ 30, %for.inc ]
78+
%exitcond.not = icmp eq i16 %i.0, 10
79+
br i1 %exitcond.not, label %for.end, label %for.body
80+
81+
for.body: ; preds = %for.cond
82+
%cmp1 = icmp ult i16 %i.0, 5
83+
%arrayidx = getelementptr inbounds [10 x i16], [10 x i16]* @B, i16 0, i16 %i.0
84+
%0 = load i16, i16* %arrayidx, align 1
85+
br i1 %cmp1, label %if.then, label %if.else
86+
87+
if.then: ; preds = %for.body
88+
call void @foo(i16 %0, i16 %i.3)
89+
br label %for.inc
90+
91+
if.else: ; preds = %for.body
92+
call void @bar(i16 %0, i16 %i.3)
93+
br label %for.inc
94+
95+
for.inc: ; preds = %if.else, %if.then
96+
%inc.0 = add nuw nsw i16 %i.0, 1
97+
%inc.2 = add nuw nsw i16 %i.2, 2
98+
br label %for.cond
99+
100+
for.end: ; preds = %for.cond
101+
ret void
102+
}
103+
104+
declare void @foo(i16, i16)
105+
declare void @bar(i16, i16)

0 commit comments

Comments
 (0)