Skip to content

Commit e253cdd

Browse files
committed
[MustExecute] Add backward exploration for must-be-executed-context
Summary: As mentioned in D71974, it is useful for must-be-executed-context to explore CFG backwardly. This patch is ported from parts of D64975. We use a dominator tree to find the previous context if a dominator tree is available. Reviewers: jdoerfert, hfinkel, baziotis, sstefan1 Reviewed By: jdoerfert Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74817
1 parent 8e76fec commit e253cdd

File tree

8 files changed

+378
-56
lines changed

8 files changed

+378
-56
lines changed

llvm/include/llvm/Analysis/MustExecute.h

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ class ICFLoopSafetyInfo: public LoopSafetyInfo {
178178

179179
struct MustBeExecutedContextExplorer;
180180

181+
/// Enum that allows us to spell out the direction.
182+
enum class ExplorationDirection {
183+
BACKWARD = 0,
184+
FORWARD = 1,
185+
};
186+
181187
/// Must be executed iterators visit stretches of instructions that are
182188
/// guaranteed to be executed together, potentially with other instruction
183189
/// executed in-between.
@@ -282,16 +288,18 @@ struct MustBeExecutedIterator {
282288

283289
MustBeExecutedIterator(const MustBeExecutedIterator &Other)
284290
: Visited(Other.Visited), Explorer(Other.Explorer),
285-
CurInst(Other.CurInst) {}
291+
CurInst(Other.CurInst), Head(Other.Head), Tail(Other.Tail) {}
286292

287293
MustBeExecutedIterator(MustBeExecutedIterator &&Other)
288294
: Visited(std::move(Other.Visited)), Explorer(Other.Explorer),
289-
CurInst(Other.CurInst) {}
295+
CurInst(Other.CurInst), Head(Other.Head), Tail(Other.Tail) {}
290296

291297
MustBeExecutedIterator &operator=(MustBeExecutedIterator &&Other) {
292298
if (this != &Other) {
293299
std::swap(Visited, Other.Visited);
294300
std::swap(CurInst, Other.CurInst);
301+
std::swap(Head, Other.Head);
302+
std::swap(Tail, Other.Tail);
295303
}
296304
return *this;
297305
}
@@ -315,7 +323,7 @@ struct MustBeExecutedIterator {
315323
/// Equality and inequality operators. Note that we ignore the history here.
316324
///{
317325
bool operator==(const MustBeExecutedIterator &Other) const {
318-
return CurInst == Other.CurInst;
326+
return CurInst == Other.CurInst && Head == Other.Head && Tail == Other.Tail;
319327
}
320328

321329
bool operator!=(const MustBeExecutedIterator &Other) const {
@@ -328,17 +336,24 @@ struct MustBeExecutedIterator {
328336
const Instruction *getCurrentInst() const { return CurInst; }
329337

330338
/// Return true if \p I was encountered by this iterator already.
331-
bool count(const Instruction *I) const { return Visited.count(I); }
339+
bool count(const Instruction *I) const {
340+
return Visited.count({I, ExplorationDirection::FORWARD}) ||
341+
Visited.count({I, ExplorationDirection::BACKWARD});
342+
}
332343

333344
private:
334-
using VisitedSetTy = DenseSet<const Instruction *>;
345+
using VisitedSetTy =
346+
DenseSet<PointerIntPair<const Instruction *, 1, ExplorationDirection>>;
335347

336348
/// Private constructors.
337349
MustBeExecutedIterator(ExplorerTy &Explorer, const Instruction *I);
338350

339351
/// Reset the iterator to its initial state pointing at \p I.
340352
void reset(const Instruction *I);
341353

354+
/// Reset the iterator to point at \p I, keep cached state.
355+
void resetInstruction(const Instruction *I);
356+
342357
/// Try to advance one of the underlying positions (Head or Tail).
343358
///
344359
/// \return The next instruction in the must be executed context, or nullptr
@@ -357,6 +372,11 @@ struct MustBeExecutedIterator {
357372
/// initially the program point itself.
358373
const Instruction *CurInst;
359374

375+
/// Two positions that mark the program points where this iterator will look
376+
/// for the next instruction. Note that the current instruction is either the
377+
/// one pointed to by Head, Tail, or both.
378+
const Instruction *Head, *Tail;
379+
360380
friend struct MustBeExecutedContextExplorer;
361381
};
362382

@@ -379,14 +399,24 @@ struct MustBeExecutedContextExplorer {
379399
/// \param ExploreInterBlock Flag to indicate if instructions in blocks
380400
/// other than the parent of PP should be
381401
/// explored.
402+
/// \param ExploreCFGForward Flag to indicate if instructions located after
403+
/// PP in the CFG, e.g., post-dominating PP,
404+
/// should be explored.
405+
/// \param ExploreCFGBackward Flag to indicate if instructions located
406+
/// before PP in the CFG, e.g., dominating PP,
407+
/// should be explored.
382408
MustBeExecutedContextExplorer(
383-
bool ExploreInterBlock,
409+
bool ExploreInterBlock, bool ExploreCFGForward, bool ExploreCFGBackward,
384410
GetterTy<const LoopInfo> LIGetter =
385411
[](const Function &) { return nullptr; },
412+
GetterTy<const DominatorTree> DTGetter =
413+
[](const Function &) { return nullptr; },
386414
GetterTy<const PostDominatorTree> PDTGetter =
387415
[](const Function &) { return nullptr; })
388-
: ExploreInterBlock(ExploreInterBlock), LIGetter(LIGetter),
389-
PDTGetter(PDTGetter), EndIterator(*this, nullptr) {}
416+
: ExploreInterBlock(ExploreInterBlock),
417+
ExploreCFGForward(ExploreCFGForward),
418+
ExploreCFGBackward(ExploreCFGBackward), LIGetter(LIGetter),
419+
DTGetter(DTGetter), PDTGetter(PDTGetter), EndIterator(*this, nullptr) {}
390420

391421
/// Clean up the dynamically allocated iterators.
392422
~MustBeExecutedContextExplorer() {
@@ -464,21 +494,36 @@ struct MustBeExecutedContextExplorer {
464494
const Instruction *
465495
getMustBeExecutedNextInstruction(MustBeExecutedIterator &It,
466496
const Instruction *PP);
497+
/// Return the previous instr. that is guaranteed to be executed before \p PP.
498+
///
499+
/// \param It The iterator that is used to traverse the must be
500+
/// executed context.
501+
/// \param PP The program point for which the previous instr.
502+
/// that is guaranteed to execute is determined.
503+
const Instruction *
504+
getMustBeExecutedPrevInstruction(MustBeExecutedIterator &It,
505+
const Instruction *PP);
467506

468507
/// Find the next join point from \p InitBB in forward direction.
469508
const BasicBlock *findForwardJoinPoint(const BasicBlock *InitBB);
470509

510+
/// Find the next join point from \p InitBB in backward direction.
511+
const BasicBlock *findBackwardJoinPoint(const BasicBlock *InitBB);
512+
471513
/// Parameter that limit the performed exploration. See the constructor for
472514
/// their meaning.
473515
///{
474516
const bool ExploreInterBlock;
517+
const bool ExploreCFGForward;
518+
const bool ExploreCFGBackward;
475519
///}
476520

477521
private:
478522
/// Getters for common CFG analyses: LoopInfo, DominatorTree, and
479523
/// PostDominatorTree.
480524
///{
481525
GetterTy<const LoopInfo> LIGetter;
526+
GetterTy<const DominatorTree> DTGetter;
482527
GetterTy<const PostDominatorTree> PDTGetter;
483528
///}
484529

llvm/include/llvm/Transforms/IPO/Attributor.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,10 @@ struct AnalysisGetter {
569569
struct InformationCache {
570570
InformationCache(const Module &M, AnalysisGetter &AG,
571571
SetVector<Function *> *CGSCC)
572-
: DL(M.getDataLayout()), Explorer(/* ExploreInterBlock */ true), AG(AG),
573-
CGSCC(CGSCC) {}
572+
: DL(M.getDataLayout()),
573+
Explorer(/* ExploreInterBlock */ true, /* ExploreCFGForward */ true,
574+
/* ExploreCFGBackward */ true),
575+
AG(AG), CGSCC(CGSCC) {}
574576

575577
/// A map type from opcodes to instructions with this opcode.
576578
using OpcodeInstMapTy = DenseMap<unsigned, SmallVector<Instruction *, 32>>;

llvm/lib/Analysis/MustExecute.cpp

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,21 @@ bool MustBeExecutedContextPrinter::runOnModule(Module &M) {
368368
LIs.push_back(LI);
369369
return LI;
370370
};
371+
GetterTy<DominatorTree> DTGetter = [&](const Function &F) {
372+
DominatorTree *DT = new DominatorTree(const_cast<Function &>(F));
373+
DTs.push_back(DT);
374+
return DT;
375+
};
371376
GetterTy<PostDominatorTree> PDTGetter = [&](const Function &F) {
372377
PostDominatorTree *PDT = new PostDominatorTree(const_cast<Function &>(F));
373378
PDTs.push_back(PDT);
374379
return PDT;
375380
};
376-
MustBeExecutedContextExplorer Explorer(true, LIGetter, PDTGetter);
381+
MustBeExecutedContextExplorer Explorer(
382+
/* ExploreInterBlock */ true,
383+
/* ExploreCFGForward */ true,
384+
/* ExploreCFGBackward */ true, LIGetter, DTGetter, PDTGetter);
385+
377386
for (Function &F : M) {
378387
for (Instruction &I : instructions(F)) {
379388
dbgs() << "-- Explore context of: " << I << "\n";
@@ -632,6 +641,72 @@ MustBeExecutedContextExplorer::findForwardJoinPoint(const BasicBlock *InitBB) {
632641
LLVM_DEBUG(dbgs() << "\tJoin block: " << JoinBB->getName() << "\n");
633642
return JoinBB;
634643
}
644+
const BasicBlock *
645+
MustBeExecutedContextExplorer::findBackwardJoinPoint(const BasicBlock *InitBB) {
646+
const LoopInfo *LI = LIGetter(*InitBB->getParent());
647+
const DominatorTree *DT = DTGetter(*InitBB->getParent());
648+
LLVM_DEBUG(dbgs() << "\tFind backward join point for " << InitBB->getName()
649+
<< (LI ? " [LI]" : "") << (DT ? " [DT]" : ""));
650+
651+
// Try to determine a join block through the help of the dominance tree. If no
652+
// tree was provided, we perform simple pattern matching for one block
653+
// conditionals only.
654+
if (DT)
655+
if (const auto *InitNode = DT->getNode(InitBB))
656+
if (const auto *IDomNode = InitNode->getIDom())
657+
return IDomNode->getBlock();
658+
659+
const Loop *L = LI ? LI->getLoopFor(InitBB) : nullptr;
660+
const BasicBlock *HeaderBB = L ? L->getHeader() : nullptr;
661+
662+
// Determine the predecessor blocks but ignore backedges.
663+
SmallVector<const BasicBlock *, 8> Worklist;
664+
for (const BasicBlock *PredBB : predecessors(InitBB)) {
665+
bool IsBackedge =
666+
(PredBB == InitBB) || (HeaderBB == InitBB && L->contains(PredBB));
667+
// Loop backedges are ignored in backwards propagation: control has to come
668+
// from somewhere.
669+
if (!IsBackedge)
670+
Worklist.push_back(PredBB);
671+
}
672+
673+
// If there are no other predecessor blocks, there is no join point.
674+
if (Worklist.empty())
675+
return nullptr;
676+
677+
// If there is one predecessor block, it is the join point.
678+
if (Worklist.size() == 1)
679+
return Worklist[0];
680+
681+
const BasicBlock *JoinBB = nullptr;
682+
if (Worklist.size() == 2) {
683+
const BasicBlock *Pred0 = Worklist[0];
684+
const BasicBlock *Pred1 = Worklist[1];
685+
const BasicBlock *Pred0UniquePred = Pred0->getUniquePredecessor();
686+
const BasicBlock *Pred1UniquePred = Pred1->getUniquePredecessor();
687+
if (Pred0 == Pred1UniquePred) {
688+
// InitBB <- Pred0 = JoinBB
689+
// InitBB <- Pred1 <- Pred0 = JoinBB
690+
JoinBB = Pred0;
691+
} else if (Pred1 == Pred0UniquePred) {
692+
// InitBB <- Pred0 <- Pred1 = JoinBB
693+
// InitBB <- Pred1 = JoinBB
694+
JoinBB = Pred1;
695+
} else if (Pred0UniquePred == Pred1UniquePred) {
696+
// InitBB <- Pred0 <- JoinBB
697+
// InitBB <- Pred1 <- JoinBB
698+
JoinBB = Pred0UniquePred;
699+
}
700+
}
701+
702+
if (!JoinBB && L)
703+
JoinBB = L->getHeader();
704+
705+
// In backwards direction there is no need to show termination of previous
706+
// instructions. If they do not terminate, the code afterward is dead, making
707+
// any information/transformation correct anyway.
708+
return JoinBB;
709+
}
635710

636711
const Instruction *
637712
MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
@@ -690,23 +765,79 @@ MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
690765
return nullptr;
691766
}
692767

768+
const Instruction *
769+
MustBeExecutedContextExplorer::getMustBeExecutedPrevInstruction(
770+
MustBeExecutedIterator &It, const Instruction *PP) {
771+
if (!PP)
772+
return PP;
773+
774+
bool IsFirst = !(PP->getPrevNode());
775+
LLVM_DEBUG(dbgs() << "Find next instruction for " << *PP
776+
<< (IsFirst ? " [IsFirst]" : "") << "\n");
777+
778+
// If we explore only inside a given basic block we stop at the first
779+
// instruction.
780+
if (!ExploreInterBlock && IsFirst) {
781+
LLVM_DEBUG(dbgs() << "\tReached block front in intra-block mode, done\n");
782+
return nullptr;
783+
}
784+
785+
// The block and function that contains the current position.
786+
const BasicBlock *PPBlock = PP->getParent();
787+
788+
// If we are inside a block we know what instruction was executed before, the
789+
// previous one.
790+
if (!IsFirst) {
791+
const Instruction *PrevPP = PP->getPrevNode();
792+
LLVM_DEBUG(
793+
dbgs() << "\tIntermediate instruction, continue with previous\n");
794+
// We did not enter a callee so we simply return the previous instruction.
795+
return PrevPP;
796+
}
797+
798+
// Finally, we have to handle the case where the program point is the first in
799+
// a block but not in the function. We use the findBackwardJoinPoint helper
800+
// function with information about the function and helper analyses, if
801+
// available.
802+
if (const BasicBlock *JoinBB = findBackwardJoinPoint(PPBlock))
803+
return &JoinBB->back();
804+
805+
LLVM_DEBUG(dbgs() << "\tNo join point found\n");
806+
return nullptr;
807+
}
808+
693809
MustBeExecutedIterator::MustBeExecutedIterator(
694810
MustBeExecutedContextExplorer &Explorer, const Instruction *I)
695811
: Explorer(Explorer), CurInst(I) {
696812
reset(I);
697813
}
698814

699815
void MustBeExecutedIterator::reset(const Instruction *I) {
700-
CurInst = I;
701816
Visited.clear();
702-
Visited.insert(I);
817+
resetInstruction(I);
818+
}
819+
820+
void MustBeExecutedIterator::resetInstruction(const Instruction *I) {
821+
CurInst = I;
822+
Head = Tail = nullptr;
823+
Visited.insert({I, ExplorationDirection::FORWARD});
824+
Visited.insert({I, ExplorationDirection::BACKWARD});
825+
if (Explorer.ExploreCFGForward)
826+
Head = I;
827+
if (Explorer.ExploreCFGBackward)
828+
Tail = I;
703829
}
704830

705831
const Instruction *MustBeExecutedIterator::advance() {
706832
assert(CurInst && "Cannot advance an end iterator!");
707-
const Instruction *Next =
708-
Explorer.getMustBeExecutedNextInstruction(*this, CurInst);
709-
if (Next && !Visited.insert(Next).second)
710-
Next = nullptr;
711-
return Next;
833+
Head = Explorer.getMustBeExecutedNextInstruction(*this, Head);
834+
if (Head && Visited.insert({Head, ExplorationDirection ::FORWARD}).second)
835+
return Head;
836+
Head = nullptr;
837+
838+
Tail = Explorer.getMustBeExecutedPrevInstruction(*this, Tail);
839+
if (Tail && Visited.insert({Tail, ExplorationDirection ::BACKWARD}).second)
840+
return Tail;
841+
Tail = nullptr;
842+
return nullptr;
712843
}

0 commit comments

Comments
 (0)