Skip to content

Commit 9b88979

Browse files
committed
implement feedback
1 parent 3c5e96b commit 9b88979

File tree

9 files changed

+146
-58
lines changed

9 files changed

+146
-58
lines changed

llvm/include/llvm/ADT/GenericCycleImpl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,17 @@ auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(CycleT *A,
561561
return A;
562562
}
563563

564+
/// \brief Find the innermost cycle containing both given blocks.
565+
///
566+
/// \returns the innermost cycle containing both \p A and \p B
567+
/// or nullptr if there is no such cycle.
568+
template <typename ContextT>
569+
auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(BlockT *A,
570+
BlockT *B) const
571+
-> CycleT * {
572+
return getSmallestCommonCycle(getCycle(A), getCycle(B));
573+
}
574+
564575
/// \brief get the depth for the cycle which containing a given block.
565576
///
566577
/// \returns the depth for the innermost cycle containing \p Block or 0 if it is

llvm/include/llvm/ADT/GenericCycleInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ template <typename ContextT> class GenericCycleInfo {
298298

299299
CycleT *getCycle(const BlockT *Block) const;
300300
CycleT *getSmallestCommonCycle(CycleT *A, CycleT *B) const;
301+
CycleT *getSmallestCommonCycle(BlockT *A, BlockT *B) const;
301302
unsigned getCycleDepth(const BlockT *Block) const;
302303
CycleT *getTopLevelParentCycle(BlockT *Block);
303304

llvm/include/llvm/Support/GenericLoopInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,17 @@ template <class BlockT, class LoopT> class LoopInfoBase {
615615
return L ? L->getLoopDepth() : 0;
616616
}
617617

618+
/// \brief Find the innermost loop containing both given loops.
619+
///
620+
/// \returns the innermost loop containing both \p A and \p B
621+
/// or nullptr if there is no such loop.
622+
LoopT *getSmallestCommonLoop(LoopT *A, LoopT *B) const;
623+
/// \brief Find the innermost loop containing both given blocks.
624+
///
625+
/// \returns the innermost loop containing both \p A and \p B
626+
/// or nullptr if there is no such loop.
627+
LoopT *getSmallestCommonLoop(BlockT *A, BlockT *B) const;
628+
618629
// True if the block is a loop header node
619630
bool isLoopHeader(const BlockT *BB) const {
620631
const LoopT *L = getLoopFor(BB);

llvm/include/llvm/Support/GenericLoopInfoImpl.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,36 @@ LoopInfoBase<BlockT, LoopT>::getLoopsInReverseSiblingPreorder() const {
645645
return PreOrderLoops;
646646
}
647647

648+
template <class BlockT, class LoopT>
649+
LoopT *LoopInfoBase<BlockT, LoopT>::getSmallestCommonLoop(LoopT *A,
650+
LoopT *B) const {
651+
if (!A || !B)
652+
return nullptr;
653+
654+
// If lops A and B have different depth replace them with parent loop
655+
// until they have the same depth.
656+
while (A->getLoopDepth() > B->getLoopDepth())
657+
A = A->getParentLoop();
658+
while (B->getLoopDepth() > A->getLoopDepth())
659+
B = B->getParentLoop();
660+
661+
// Loops A and B are at same depth but may be disjoint, replace them with
662+
// parent loops until we find loop that contains both or we run out of
663+
// parent loops.
664+
while (A != B) {
665+
A = A->getParentLoop();
666+
B = B->getParentLoop();
667+
}
668+
669+
return A;
670+
}
671+
672+
template <class BlockT, class LoopT>
673+
LoopT *LoopInfoBase<BlockT, LoopT>::getSmallestCommonLoop(BlockT *A,
674+
BlockT *B) const {
675+
return getSmallestCommonLoop(getLoopFor(A), getLoopFor(B));
676+
}
677+
648678
// Debugging
649679
template <class BlockT, class LoopT>
650680
void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {

llvm/include/llvm/Transforms/Utils/ControlFlowUtils.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,21 @@ struct ControlFlowHub {
135135
/// \param Succ The original successor basic block to be reached.
136136
/// \param SuccIdx The index of the successor in the callbr
137137
/// instruction.
138-
/// \param AttachToCallBr If true, the new block is associated with the
139-
/// callbr's parent for loop/cycle info.
140-
/// If false, the new block is associated with the
141-
/// callbr's successor for loop/cycle info.
142138
/// \param CI Optional CycleInfo for updating cycle membership.
143139
/// \param DTU Optional DomTreeUpdater for updating the dominator
144140
/// tree.
145141
/// \param LI Optional LoopInfo for updating loop membership.
142+
/// \param UpdatedLI Optional output flag indicating if LoopInfo has been
143+
/// updated.
146144
///
147145
/// \returns The newly created intermediate target block.
148146
///
149147
/// \note This function updates PHI nodes, dominator tree, loop info, and
150148
/// cycle info as needed.
151149
static BasicBlock *
152150
createCallBrTarget(CallBrInst *CallBr, BasicBlock *Succ, unsigned SuccIdx,
153-
bool AttachToCallBr = true, CycleInfo *CI = nullptr,
154-
DomTreeUpdater *DTU = nullptr, LoopInfo *LI = nullptr);
151+
CycleInfo *CI = nullptr, DomTreeUpdater *DTU = nullptr,
152+
LoopInfo *LI = nullptr, bool *UpdatedLI = nullptr);
155153
};
156154

157155
} // end namespace llvm

llvm/lib/Transforms/Utils/ControlFlowUtils.cpp

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -346,56 +346,35 @@ std::pair<BasicBlock *, bool> ControlFlowHub::finalize(
346346
return {FirstGuardBlock, true};
347347
}
348348

349-
// Check if the given cycle is disjoint with the cycle of the given basic block.
350-
// If the basic block does not belong to any cycle, this is regarded as
351-
// disjoint, too.
352-
static bool disjointWithBlock(CycleInfo *CI, Cycle *C, BasicBlock *BB) {
353-
Cycle *CC = CI->getCycle(BB);
354-
if (!CC)
355-
return true;
356-
Cycle *CommonC = CI->getSmallestCommonCycle(C, CC);
357-
return CommonC != C && CommonC != CC;
358-
}
359-
360-
// Check if the given loop is disjoint with the loop of the given basic block.
361-
// If the basic block does not belong to any loop, this is regarded as
362-
// disjoint, too.
363-
static bool disjointWithBlock(LoopInfo *LI, Loop *L, BasicBlock *BB) {
364-
Loop *LL = LI->getLoopFor(BB);
365-
return LL && !L->contains(LL) && !LL->contains(L);
366-
}
367-
368349
template <typename TI, typename T>
369-
static void updateCycleLoopInfo(TI *LCI, bool AttachToCallBr,
370-
BasicBlock *CallBrBlock,
350+
static bool updateCycleLoopInfo(TI *LCI, BasicBlock *CallBrBlock,
371351
BasicBlock *CallBrTarget, BasicBlock *Succ) {
372352
static_assert(std::is_same_v<TI, CycleInfo> || std::is_same_v<TI, LoopInfo>,
373353
"type must be CycleInfo or LoopInfo");
374354
if (!LCI)
375-
return;
355+
return false;
376356

377357
T *LC;
378358
if constexpr (std::is_same_v<TI, CycleInfo>)
379-
LC = LCI->getCycle(AttachToCallBr ? CallBrBlock : Succ);
359+
LC = LCI->getSmallestCommonCycle(CallBrBlock, Succ);
380360
else
381-
LC = LCI->getLoopFor(AttachToCallBr ? CallBrBlock : Succ);
361+
LC = LCI->getSmallestCommonLoop(CallBrBlock, Succ);
382362
if (!LC)
383-
return;
384-
385-
// Check if the cycles/loops are disjoint. In that case, we do not add the
386-
// intermediate target to any cycle/loop.
387-
if (AttachToCallBr && disjointWithBlock(LCI, LC, Succ))
388-
return;
363+
return false;
389364

390365
if constexpr (std::is_same_v<TI, CycleInfo>)
391366
LCI->addBlockToCycle(CallBrTarget, LC);
392367
else
393368
LC->addBasicBlockToLoop(CallBrTarget, *LCI);
369+
370+
return true;
394371
}
395372

396-
BasicBlock *ControlFlowHub::createCallBrTarget(
397-
CallBrInst *CallBr, BasicBlock *Succ, unsigned SuccIdx, bool AttachToCallBr,
398-
CycleInfo *CI, DomTreeUpdater *DTU, LoopInfo *LI) {
373+
BasicBlock *ControlFlowHub::createCallBrTarget(CallBrInst *CallBr,
374+
BasicBlock *Succ,
375+
unsigned SuccIdx, CycleInfo *CI,
376+
DomTreeUpdater *DTU,
377+
LoopInfo *LI, bool *UpdatedLI) {
399378
BasicBlock *CallBrBlock = CallBr->getParent();
400379
BasicBlock *CallBrTarget =
401380
BasicBlock::Create(CallBrBlock->getContext(),
@@ -406,10 +385,11 @@ BasicBlock *ControlFlowHub::createCallBrTarget(
406385
CallBr->setSuccessor(SuccIdx, CallBrTarget);
407386
// Jump from the new target block to the original successor.
408387
BranchInst::Create(Succ, CallBrTarget);
409-
updateCycleLoopInfo<LoopInfo, Loop>(LI, AttachToCallBr, CallBrBlock,
410-
CallBrTarget, Succ);
411-
updateCycleLoopInfo<CycleInfo, Cycle>(CI, AttachToCallBr, CallBrBlock,
412-
CallBrTarget, Succ);
388+
bool Updated =
389+
updateCycleLoopInfo<LoopInfo, Loop>(LI, CallBrBlock, CallBrTarget, Succ);
390+
if (UpdatedLI)
391+
*UpdatedLI = Updated;
392+
updateCycleLoopInfo<CycleInfo, Cycle>(CI, CallBrBlock, CallBrTarget, Succ);
413393
if (DTU) {
414394
DTU->applyUpdates({{DominatorTree::Insert, CallBrBlock, CallBrTarget}});
415395
if (DTU->getDomTree().dominates(CallBrBlock, Succ))

llvm/lib/Transforms/Utils/FixIrreducible.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,8 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
308308
BasicBlock *Succ = CallBr->getSuccessor(I);
309309
if (Succ != Header)
310310
continue;
311-
BasicBlock *NewSucc = ControlFlowHub::createCallBrTarget(
312-
CallBr, Succ, I, /* AttachToCallBr = */ false, &CI, &DTU, LI);
311+
BasicBlock *NewSucc =
312+
ControlFlowHub::createCallBrTarget(CallBr, Succ, I, &CI, &DTU, LI);
313313
CHub.addBranch(NewSucc, Succ);
314314
LLVM_DEBUG(dbgs() << "Added internal branch: "
315315
<< printBasicBlock(NewSucc) << " -> "
@@ -347,8 +347,8 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
347347
BasicBlock *Succ = CallBr->getSuccessor(I);
348348
if (!C.contains(Succ))
349349
continue;
350-
BasicBlock *NewSucc = ControlFlowHub::createCallBrTarget(
351-
CallBr, Succ, I, /* AttachToCallBr = */ true, &CI, &DTU, LI);
350+
BasicBlock *NewSucc =
351+
ControlFlowHub::createCallBrTarget(CallBr, Succ, I, &CI, &DTU, LI);
352352
CHub.addBranch(NewSucc, Succ);
353353
LLVM_DEBUG(dbgs() << "Added external branch: "
354354
<< printBasicBlock(NewSucc) << " -> "

llvm/lib/Transforms/Utils/UnifyLoopExits.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
155155
L->getExitingBlocks(ExitingBlocks);
156156

157157
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
158-
SmallVector<BasicBlock *, 8> CallBrTargetBlocks;
158+
SmallVector<BasicBlock *, 8> CallBrTargetBlocksToFix;
159159
// Redirect exiting edges through a control flow hub.
160160
ControlFlowHub CHub;
161161

@@ -179,8 +179,13 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
179179
BasicBlock *Succ = CallBr->getSuccessor(J);
180180
if (L->contains(Succ))
181181
continue;
182+
bool UpdatedLI = false;
182183
BasicBlock *NewSucc = ControlFlowHub::createCallBrTarget(
183-
CallBr, Succ, J, /* AttachToCallBr = */ false, nullptr, &DTU, &LI);
184+
CallBr, Succ, J, nullptr, &DTU, &LI, &UpdatedLI);
185+
// Even if CallBr and Succ do not have a common parent loop, we need to
186+
// add the new target block to the parent loop of the current loop.
187+
if (!UpdatedLI)
188+
CallBrTargetBlocksToFix.push_back(NewSucc);
184189
// ExitingBlocks is later used to restore SSA, so we need to make sure
185190
// that the blocks used for phi nodes in the guard blocks match the
186191
// predecessors of the guard blocks, which, in the case of callbr, are
@@ -191,9 +196,6 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
191196
LLVM_DEBUG(dbgs() << "Added exiting branch: "
192197
<< printBasicBlock(NewSucc) << " -> "
193198
<< printBasicBlock(Succ) << "\n");
194-
// Also add the new target block to the list of exiting blocks that
195-
// should later be added to the parent loops.
196-
CallBrTargetBlocks.push_back(NewSucc);
197199
}
198200
} else {
199201
llvm_unreachable("unsupported block terminator");
@@ -218,16 +220,19 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
218220
L->verifyLoop();
219221

220222
// The guard blocks were created outside the loop, so they need to become
221-
// members of the parent loop. Same goes for the callbr target blocks if they
222-
// have not already been added to the respective parent loop by adding them to
223-
// the original callbr target's loop.
223+
// members of the parent loop.
224+
// Same goes for the callbr target blocks. Although we try to add them to the
225+
// smallest common parent loop of the callbr block and the corresponding
226+
// original target block, there might not have been such a loop, in which case
227+
// the newly created callbr target blocks are not part of any loop. For nested
228+
// loops, this might result in them leading to a loop with multiple entry
229+
// points.
224230
if (auto *ParentLoop = L->getParentLoop()) {
225231
for (auto *G : GuardBlocks) {
226232
ParentLoop->addBasicBlockToLoop(G, LI);
227233
}
228-
for (auto *C : CallBrTargetBlocks) {
229-
if (!ParentLoop->contains(C))
230-
ParentLoop->addBasicBlockToLoop(C, LI);
234+
for (auto *C : CallBrTargetBlocksToFix) {
235+
ParentLoop->addBasicBlockToLoop(C, LI);
231236
}
232237
ParentLoop->verifyLoop();
233238
}

llvm/test/Transforms/UnifyLoopExits/nested.ll

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,55 @@ exit:
168168
%exit.phi = phi i32 [%A4.phi, %A5], [%Z, %C]
169169
ret void
170170
}
171+
172+
; Here, the newly created target loop that connects b to r1 needs to be part of
173+
; the parent loop (the outer loop b participates in). Otherwise, it will be
174+
; regarded as an additional loop entry point to this outer loop.
175+
define void @nested_callbr_multiple_exits() {
176+
; CHECK-LABEL: @nested_callbr_multiple_exits(
177+
; CHECK-NEXT: br label [[A:%.*]]
178+
; CHECK: a:
179+
; CHECK-NEXT: callbr void asm "", ""()
180+
; CHECK-NEXT: to label [[B:%.*]] []
181+
; CHECK: b:
182+
; CHECK-NEXT: callbr void asm "", "!i"()
183+
; CHECK-NEXT: to label [[C:%.*]] [label %b.target.b.target.r1]
184+
; CHECK: c:
185+
; CHECK-NEXT: callbr void asm "", "!i"()
186+
; CHECK-NEXT: to label [[C_TARGET_E:%.*]] [label %b]
187+
; CHECK: e:
188+
; CHECK-NEXT: callbr void asm "", "!i"()
189+
; CHECK-NEXT: to label [[A]] [label %e.target.r2]
190+
; CHECK: r1:
191+
; CHECK-NEXT: ret void
192+
; CHECK: r2:
193+
; CHECK-NEXT: ret void
194+
; CHECK: b.target.r1:
195+
; CHECK-NEXT: br label [[LOOP_EXIT_GUARD:%.*]]
196+
; CHECK: e.target.r2:
197+
; CHECK-NEXT: br label [[LOOP_EXIT_GUARD]]
198+
; CHECK: loop.exit.guard:
199+
; CHECK-NEXT: [[GUARD_R1:%.*]] = phi i1 [ true, [[B_TARGET_R1:%.*]] ], [ false, [[E_TARGET_R2:%.*]] ]
200+
; CHECK-NEXT: br i1 [[GUARD_R1]], label [[R1:%.*]], label [[R2:%.*]]
201+
; CHECK: b.target.b.target.r1:
202+
; CHECK-NEXT: br label [[LOOP_EXIT_GUARD1:%.*]]
203+
; CHECK: c.target.e:
204+
; CHECK-NEXT: br label [[LOOP_EXIT_GUARD1]]
205+
; CHECK: loop.exit.guard1:
206+
; CHECK-NEXT: [[GUARD_B_TARGET_R1:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_R1:%.*]] ], [ false, [[C_TARGET_E]] ]
207+
; CHECK-NEXT: br i1 [[GUARD_B_TARGET_R1]], label [[B_TARGET_R1]], label [[E:%.*]]
208+
;
209+
br label %a
210+
a:
211+
callbr void asm "", ""() to label %b []
212+
b:
213+
callbr void asm "", "!i"() to label %c [label %r1]
214+
c:
215+
callbr void asm "", "!i"() to label %e [label %b]
216+
e:
217+
callbr void asm "", "!i"() to label %a [label %r2]
218+
r1:
219+
ret void
220+
r2:
221+
ret void
222+
}

0 commit comments

Comments
 (0)