diff --git a/include/llvm/Analysis/MustExecute.h b/include/llvm/Analysis/MustExecute.h index f136ff750de..62d9b056e88 100644 --- a/include/llvm/Analysis/MustExecute.h +++ b/include/llvm/Analysis/MustExecute.h @@ -19,6 +19,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Analysis/EHPersonalities.h" +#include "llvm/Analysis/InstructionPrecedenceTracking.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Dominators.h" @@ -122,6 +123,37 @@ public: virtual ~SimpleLoopSafetyInfo() {}; }; +/// This implementation of LoopSafetyInfo use ImplicitControlFlowTracking to +/// give precise answers on "may throw" queries. This implementation uses cache +/// that should be invalidated by calling the method dropCachedInfo whenever we +/// modify a basic block's contents by adding or removing instructions. +class ICFLoopSafetyInfo: public LoopSafetyInfo { + bool MayThrow = false; // The current loop contains an instruction which + // may throw. + // Contains information about implicit control flow in this loop's blocks. + mutable ImplicitControlFlowTracking ICF; + +public: + virtual bool blockMayThrow(const BasicBlock *BB) const; + + virtual bool anyBlockMayThrow() const; + + virtual void computeLoopSafetyInfo(const Loop *CurLoop); + + virtual bool isGuaranteedToExecute(const Instruction &Inst, + const DominatorTree *DT, + const Loop *CurLoop) const; + + /// Drops cached information regarding the implicit control flow in block + /// \p BB. It should be called for every block in which we add or remove any + /// instructions to a block before we make queries to it. + void dropCachedInfo(const BasicBlock *BB); + + ICFLoopSafetyInfo(DominatorTree *DT) : LoopSafetyInfo(), ICF(DT) {}; + + virtual ~ICFLoopSafetyInfo() {}; +}; + } #endif diff --git a/lib/Analysis/MustExecute.cpp b/lib/Analysis/MustExecute.cpp index 4e42f336dc7..64ee2a7e5b0 100644 --- a/lib/Analysis/MustExecute.cpp +++ b/lib/Analysis/MustExecute.cpp @@ -61,6 +61,31 @@ void SimpleLoopSafetyInfo::computeLoopSafetyInfo(const Loop *CurLoop) { computeBlockColors(CurLoop); } +bool ICFLoopSafetyInfo::blockMayThrow(const BasicBlock *BB) const { + return ICF.hasICF(BB); +} + +bool ICFLoopSafetyInfo::anyBlockMayThrow() const { + return MayThrow; +} + +void ICFLoopSafetyInfo::computeLoopSafetyInfo(const Loop *CurLoop) { + assert(CurLoop != nullptr && "CurLoop can't be null"); + ICF.clear(); + MayThrow = false; + // Figure out the fact that at least one block may throw. + for (auto &BB : CurLoop->blocks()) + if (ICF.hasICF(&*BB)) { + MayThrow = true; + break; + } + computeBlockColors(CurLoop); +} + +void ICFLoopSafetyInfo::dropCachedInfo(const BasicBlock *BB) { + ICF.invalidateBlock(BB); +} + void LoopSafetyInfo::computeBlockColors(const Loop *CurLoop) { // Compute funclet colors if we might sink/hoist in a function with a funclet // personality routine. @@ -215,6 +240,12 @@ bool SimpleLoopSafetyInfo::isGuaranteedToExecute(const Instruction &Inst, return allLoopPathsLeadToBlock(CurLoop, Inst.getParent(), DT); } +bool ICFLoopSafetyInfo::isGuaranteedToExecute(const Instruction &Inst, + const DominatorTree *DT, + const Loop *CurLoop) const { + return !ICF.isDominatedByICFIFromSameBlock(&Inst) && + allLoopPathsLeadToBlock(CurLoop, Inst.getParent(), DT); +} namespace { struct MustExecutePrinter : public FunctionPass {