|
@@ -46,7 +46,9 @@
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
#include "llvm/IR/PassManager.h"
|
|
|
#include "llvm/Pass.h"
|
|
|
+#include "llvm/Support/Allocator.h"
|
|
|
#include <algorithm>
|
|
|
+#include <utility>
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
@@ -74,25 +76,16 @@ template <class BlockT, class LoopT> class LoopBase {
|
|
|
|
|
|
SmallPtrSet<const BlockT *, 8> DenseBlockSet;
|
|
|
|
|
|
+#if !defined(NDEBUG) || !LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
|
/// Indicator that this loop is no longer a valid loop.
|
|
|
bool IsInvalid = false;
|
|
|
+#endif
|
|
|
|
|
|
LoopBase(const LoopBase<BlockT, LoopT> &) = delete;
|
|
|
const LoopBase<BlockT, LoopT> &
|
|
|
operator=(const LoopBase<BlockT, LoopT> &) = delete;
|
|
|
|
|
|
- void clear() {
|
|
|
- IsInvalid = true;
|
|
|
- SubLoops.clear();
|
|
|
- Blocks.clear();
|
|
|
- DenseBlockSet.clear();
|
|
|
- ParentLoop = nullptr;
|
|
|
- }
|
|
|
-
|
|
|
public:
|
|
|
- /// This creates an empty loop.
|
|
|
- LoopBase() : ParentLoop(nullptr) {}
|
|
|
-
|
|
|
/// Return the nesting level of this loop. An outer-most loop has depth 1,
|
|
|
/// for consistency with loop depth values used for basic blocks, where depth
|
|
|
/// 0 is used for blocks not inside any loops.
|
|
@@ -172,8 +165,15 @@ public:
|
|
|
return Blocks.size();
|
|
|
}
|
|
|
|
|
|
- /// Return true if this loop is no longer valid.
|
|
|
+#ifndef NDEBUG
|
|
|
+ /// Return true if this loop is no longer valid. The only valid use of this
|
|
|
+ /// helper is "assert(L.isInvalid())" or equivalent, since IsInvalid is set to
|
|
|
+ /// false by the destructor. In other words, if this accessor returns false,
|
|
|
+ /// the caller has already triggered UB by calling this accessor; and so it
|
|
|
+ /// can only be called in a context where a return value of false indicates a
|
|
|
+ /// programmer error.
|
|
|
bool isInvalid() const { return IsInvalid; }
|
|
|
+#endif
|
|
|
|
|
|
/// True if terminator in the block can branch to another block that is
|
|
|
/// outside of the current loop.
|
|
@@ -370,6 +370,10 @@ public:
|
|
|
|
|
|
protected:
|
|
|
friend class LoopInfoBase<BlockT, LoopT>;
|
|
|
+
|
|
|
+ /// This creates an empty loop.
|
|
|
+ LoopBase() : ParentLoop(nullptr) {}
|
|
|
+
|
|
|
explicit LoopBase(BlockT *BB) : ParentLoop(nullptr) {
|
|
|
Blocks.push_back(BB);
|
|
|
DenseBlockSet.insert(BB);
|
|
@@ -386,7 +390,13 @@ protected:
|
|
|
// non-public.
|
|
|
~LoopBase() {
|
|
|
for (auto *SubLoop : SubLoops)
|
|
|
- delete SubLoop;
|
|
|
+ SubLoop->~LoopT();
|
|
|
+
|
|
|
+ IsInvalid = true;
|
|
|
+ SubLoops.clear();
|
|
|
+ Blocks.clear();
|
|
|
+ DenseBlockSet.clear();
|
|
|
+ ParentLoop = nullptr;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -422,8 +432,6 @@ public:
|
|
|
explicit operator bool() const { return Start && End; }
|
|
|
};
|
|
|
|
|
|
- Loop() {}
|
|
|
-
|
|
|
/// Return true if the specified value is loop invariant.
|
|
|
bool isLoopInvariant(const Value *V) const;
|
|
|
|
|
@@ -534,8 +542,6 @@ public:
|
|
|
LocRange getLocRange() const;
|
|
|
|
|
|
StringRef getName() const {
|
|
|
- if (isInvalid())
|
|
|
- return "<invalidated loop>";
|
|
|
if (BasicBlock *Header = getHeader())
|
|
|
if (Header->hasName())
|
|
|
return Header->getName();
|
|
@@ -543,6 +549,8 @@ public:
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
+ Loop() = default;
|
|
|
+
|
|
|
friend class LoopInfoBase<BasicBlock, Loop>;
|
|
|
friend class LoopBase<BasicBlock, Loop>;
|
|
|
explicit Loop(BasicBlock *BB) : LoopBase<BasicBlock, Loop>(BB) {}
|
|
@@ -558,7 +566,7 @@ template <class BlockT, class LoopT> class LoopInfoBase {
|
|
|
// BBMap - Mapping of basic blocks to the inner most loop they occur in
|
|
|
DenseMap<const BlockT *, LoopT *> BBMap;
|
|
|
std::vector<LoopT *> TopLevelLoops;
|
|
|
- std::vector<LoopT *> RemovedLoops;
|
|
|
+ BumpPtrAllocator LoopAllocator;
|
|
|
|
|
|
friend class LoopBase<BlockT, LoopT>;
|
|
|
friend class LoopInfo;
|
|
@@ -572,7 +580,8 @@ public:
|
|
|
|
|
|
LoopInfoBase(LoopInfoBase &&Arg)
|
|
|
: BBMap(std::move(Arg.BBMap)),
|
|
|
- TopLevelLoops(std::move(Arg.TopLevelLoops)) {
|
|
|
+ TopLevelLoops(std::move(Arg.TopLevelLoops)),
|
|
|
+ LoopAllocator(std::move(Arg.LoopAllocator)) {
|
|
|
// We have to clear the arguments top level loops as we've taken ownership.
|
|
|
Arg.TopLevelLoops.clear();
|
|
|
}
|
|
@@ -580,8 +589,10 @@ public:
|
|
|
BBMap = std::move(RHS.BBMap);
|
|
|
|
|
|
for (auto *L : TopLevelLoops)
|
|
|
- delete L;
|
|
|
+ L->~LoopT();
|
|
|
+
|
|
|
TopLevelLoops = std::move(RHS.TopLevelLoops);
|
|
|
+ LoopAllocator = std::move(RHS.LoopAllocator);
|
|
|
RHS.TopLevelLoops.clear();
|
|
|
return *this;
|
|
|
}
|
|
@@ -590,11 +601,14 @@ public:
|
|
|
BBMap.clear();
|
|
|
|
|
|
for (auto *L : TopLevelLoops)
|
|
|
- delete L;
|
|
|
+ L->~LoopT();
|
|
|
TopLevelLoops.clear();
|
|
|
- for (auto *L : RemovedLoops)
|
|
|
- delete L;
|
|
|
- RemovedLoops.clear();
|
|
|
+ LoopAllocator.Reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename... ArgsTy> LoopT *AllocateLoop(ArgsTy &&... Args) {
|
|
|
+ LoopT *Storage = LoopAllocator.Allocate<LoopT>();
|
|
|
+ return new (Storage) LoopT(std::forward<ArgsTy>(Args)...);
|
|
|
}
|
|
|
|
|
|
/// iterator/begin/end - The interface to the top-level loops in the current
|
|
@@ -717,7 +731,15 @@ public:
|
|
|
void verify(const DominatorTreeBase<BlockT, false> &DomTree) const;
|
|
|
|
|
|
protected:
|
|
|
- static void clearLoop(LoopT &L) { L.clear(); }
|
|
|
+ // Calls the destructor for \p L but keeps the memory for \p L around so that
|
|
|
+ // the pointer value does not get re-used.
|
|
|
+ void destroy(LoopT *L) {
|
|
|
+ L->~LoopT();
|
|
|
+
|
|
|
+ // Since LoopAllocator is a BumpPtrAllocator, this Deallocate only poisons
|
|
|
+ // \c L, but the pointer remains valid for non-dereferencing uses.
|
|
|
+ LoopAllocator.Deallocate(L, sizeof(LoopT));
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// Implementation in LoopInfoImpl.h
|