#define LLVM_TRANSFORMS_UTILS_MEMORYSSA_H
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/PHITransAddr.h"
class MemoryAccess;
class LLVMContext;
class raw_ostream;
+namespace MSSAHelpers {
+
+struct AllAccessTag {};
+struct DefsOnlyTag {};
+}
enum {
// Used to signify what the default invalid ID is for MemoryAccess's
// \brief The base for all memory accesses. All memory accesses in a block are
// linked together using an intrusive list.
-class MemoryAccess : public User, public ilist_node<MemoryAccess> {
+class MemoryAccess
+ : public User,
+ public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>,
+ public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>> {
public:
+ using AllAccessType =
+ ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>;
+ using DefsOnlyType =
+ ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>>;
+
// Methods for support type inquiry through isa, cast, and
// dyn_cast
static inline bool classof(const MemoryAccess *) { return true; }
memoryaccess_def_iterator defs_end();
const_memoryaccess_def_iterator defs_end() const;
+ /// \brief Get the iterators for the all access list and the defs only list
+ /// We default to the all access list.
+ AllAccessType::self_iterator getIterator() {
+ return this->AllAccessType::getIterator();
+ }
+ AllAccessType::const_self_iterator getIterator() const {
+ return this->AllAccessType::getIterator();
+ }
+ AllAccessType::reverse_self_iterator getReverseIterator() {
+ return this->AllAccessType::getReverseIterator();
+ }
+ AllAccessType::const_reverse_self_iterator getReverseIterator() const {
+ return this->AllAccessType::getReverseIterator();
+ }
+ DefsOnlyType::self_iterator getDefsIterator() {
+ return this->DefsOnlyType::getIterator();
+ }
+ DefsOnlyType::const_self_iterator getDefsIterator() const {
+ return this->DefsOnlyType::getIterator();
+ }
+ DefsOnlyType::reverse_self_iterator getReverseDefsIterator() {
+ return this->DefsOnlyType::getReverseIterator();
+ }
+ DefsOnlyType::const_reverse_self_iterator getReverseDefsIterator() const {
+ return this->DefsOnlyType::getReverseIterator();
+ }
+
protected:
friend class MemorySSA;
friend class MemoryUseOrDef;
return LiveOnEntryDef.get();
}
- using AccessList = iplist<MemoryAccess>;
+ // Sadly, iplists, by default, owns and deletes pointers added to the
+ // list. It's not currently possible to have two iplists for the same type,
+ // where one owns the pointers, and one does not. This is because the traits
+ // are per-type, not per-tag. If this ever changes, we should make the
+ // DefList an iplist.
+ using AccessList = iplist<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>;
+ using DefsList =
+ simple_ilist<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>>;
/// \brief Return the list of MemoryAccess's for a given basic block.
///
return getWritableBlockAccesses(BB);
}
+ /// \brief Return the list of MemoryDef's and MemoryPhi's for a given basic
+ /// block.
+ ///
+ /// This list is not modifiable by the user.
+ const DefsList *getBlockDefs(const BasicBlock *BB) const {
+ return getWritableBlockDefs(BB);
+ }
+
/// \brief Create an empty MemoryPhi in MemorySSA for a given basic block.
/// Only one MemoryPhi for a block exists at a time, so this function will
/// assert if you try to create one where it already exists.
void verifyDomination(Function &F) const;
void verifyOrdering(Function &F) const;
- // This is used by the use optimizer class
+ // This is used by the use optimizer and updater.
AccessList *getWritableBlockAccesses(const BasicBlock *BB) const {
auto It = PerBlockAccesses.find(BB);
return It == PerBlockAccesses.end() ? nullptr : It->second.get();
}
+ // This is used by the use optimizer and updater.
+ DefsList *getWritableBlockDefs(const BasicBlock *BB) const {
+ auto It = PerBlockDefs.find(BB);
+ return It == PerBlockDefs.end() ? nullptr : It->second.get();
+ }
+
private:
class CachingWalker;
class OptimizeUses;
void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const;
using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>;
+ using DefsMap = DenseMap<const BasicBlock *, std::unique_ptr<DefsList>>;
void
determineInsertionPoint(const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks);
void renamePass(DomTreeNode *, MemoryAccess *IncomingVal,
SmallPtrSet<BasicBlock *, 16> &Visited);
AccessList *getOrCreateAccessList(const BasicBlock *);
+ DefsList *getOrCreateDefsList(const BasicBlock *);
void renumberBlock(const BasicBlock *) const;
-
+ void insertIntoListsForBlock(MemoryAccess *, const BasicBlock *,
+ InsertionPlace);
+ void insertIntoListsBefore(MemoryAccess *, const BasicBlock *,
+ AccessList::iterator);
AliasAnalysis *AA;
DominatorTree *DT;
Function &F;
// Memory SSA mappings
DenseMap<const Value *, MemoryAccess *> ValueToMemoryAccess;
+ // These two mappings contain the main block to access/def mappings for
+ // MemorySSA. The list contained in PerBlockAccesses really owns all the
+ // MemoryAccesses.
+ // Both maps maintain the invariant that if a block is found in them, the
+ // corresponding list is not empty, and if a block is not found in them, the
+ // corresponding list is empty.
AccessMap PerBlockAccesses;
+ DefsMap PerBlockDefs;
std::unique_ptr<MemoryAccess> LiveOnEntryDef;
// Domination mappings
fillInCurrentPair();
}
- upward_defs_iterator() {
- CurrentPair.first = nullptr;
- }
+ upward_defs_iterator() { CurrentPair.first = nullptr; }
bool operator==(const upward_defs_iterator &Other) const {
return DefIterator == Other.DefIterator;
private:
union {
- ImmutableCallSite CS;
- MemoryLocation Loc;
+ ImmutableCallSite CS;
+ MemoryLocation Loc;
};
};
}
Res.first->second = make_unique<AccessList>();
return Res.first->second.get();
}
+MemorySSA::DefsList *MemorySSA::getOrCreateDefsList(const BasicBlock *BB) {
+ auto Res = PerBlockDefs.insert(std::make_pair(BB, nullptr));
+
+ if (Res.second)
+ Res.first->second = make_unique<DefsList>();
+ return Res.first->second.get();
+}
/// This class is a batch walker of all MemoryUse's in the program, and points
/// their defining access at the thing that actually clobbers them. Because it
});
// Now place MemoryPhi nodes.
- for (auto &BB : IDFBlocks) {
- // Insert phi node
- AccessList *Accesses = getOrCreateAccessList(BB);
- MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++);
- ValueToMemoryAccess[BB] = Phi;
- // Phi's always are placed at the front of the block.
- Accesses->push_front(Phi);
- }
+ for (auto &BB : IDFBlocks)
+ createMemoryPhi(BB);
}
void MemorySSA::buildMemorySSA() {
BBNumbers[&B] = NextBBNum++;
bool InsertIntoDef = false;
AccessList *Accesses = nullptr;
+ DefsList *Defs = nullptr;
for (Instruction &I : B) {
MemoryUseOrDef *MUD = createNewAccess(&I);
if (!MUD)
continue;
- InsertIntoDef |= isa<MemoryDef>(MUD);
if (!Accesses)
Accesses = getOrCreateAccessList(&B);
Accesses->push_back(MUD);
+ if (isa<MemoryDef>(MUD)) {
+ InsertIntoDef = true;
+ if (!Defs)
+ Defs = getOrCreateDefsList(&B);
+ Defs->push_back(*MUD);
+ }
}
if (InsertIntoDef)
DefiningBlocks.insert(&B);
return Walker.get();
}
+// This is a helper function used by the creation routines. It places NewAccess
+// into the access and defs lists for a given basic block, at the given
+// insertion point.
+void MemorySSA::insertIntoListsForBlock(MemoryAccess *NewAccess,
+ const BasicBlock *BB,
+ InsertionPlace Point) {
+ auto *Accesses = getOrCreateAccessList(BB);
+ if (Point == Beginning) {
+ // If it's a phi node, it goes first, otherwise, it goes after any phi
+ // nodes.
+ if (isa<MemoryPhi>(NewAccess)) {
+ Accesses->push_front(NewAccess);
+ auto *Defs = getOrCreateDefsList(BB);
+ Defs->push_front(*NewAccess);
+ } else {
+ auto AI = find_if_not(
+ *Accesses, [](const MemoryAccess &MA) { return isa<MemoryPhi>(MA); });
+ Accesses->insert(AI, NewAccess);
+ if (!isa<MemoryUse>(NewAccess)) {
+ auto *Defs = getOrCreateDefsList(BB);
+ auto DI = find_if_not(
+ *Defs, [](const MemoryAccess &MA) { return isa<MemoryPhi>(MA); });
+ Defs->insert(DI, *NewAccess);
+ }
+ }
+ } else {
+ Accesses->push_back(NewAccess);
+ if (!isa<MemoryUse>(NewAccess)) {
+ auto *Defs = getOrCreateDefsList(BB);
+ Defs->push_back(*NewAccess);
+ }
+ }
+}
+
+void MemorySSA::insertIntoListsBefore(MemoryAccess *What, const BasicBlock *BB,
+ AccessList::iterator InsertPt) {
+ auto *Accesses = getWritableBlockAccesses(BB);
+ bool WasEnd = InsertPt == Accesses->end();
+ Accesses->insert(AccessList::iterator(InsertPt), What);
+ if (!isa<MemoryUse>(What)) {
+ auto *Defs = getOrCreateDefsList(BB);
+ // If we got asked to insert at the end, we have an easy job, just shove it
+ // at the end. If we got asked to insert before an existing def, we also get
+ // an terator. If we got asked to insert before a use, we have to hunt for
+ // the next def.
+ if (WasEnd) {
+ Defs->push_back(*What);
+ } else if (isa<MemoryDef>(InsertPt)) {
+ Defs->insert(InsertPt->getDefsIterator(), *What);
+ } else {
+ while (InsertPt != Accesses->end() && !isa<MemoryDef>(InsertPt))
+ ++InsertPt;
+ // Either we found a def, or we are inserting at the end
+ if (InsertPt == Accesses->end())
+ Defs->push_back(*What);
+ else
+ Defs->insert(InsertPt->getDefsIterator(), *What);
+ }
+ }
+}
+
MemoryPhi *MemorySSA::createMemoryPhi(BasicBlock *BB) {
assert(!getMemoryAccess(BB) && "MemoryPhi already exists for this BB");
- AccessList *Accesses = getOrCreateAccessList(BB);
MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++);
+ insertIntoListsForBlock(Phi, BB, Beginning);
ValueToMemoryAccess[BB] = Phi;
// Phi's always are placed at the front of the block.
- Accesses->push_front(Phi);
BlockNumberingValid.erase(BB);
return Phi;
}
const BasicBlock *BB,
InsertionPlace Point) {
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
- auto *Accesses = getOrCreateAccessList(BB);
- if (Point == Beginning) {
- // It goes after any phi nodes
- auto AI = find_if(
- *Accesses, [](const MemoryAccess &MA) { return !isa<MemoryPhi>(MA); });
-
- Accesses->insert(AI, NewAccess);
- } else {
- Accesses->push_back(NewAccess);
- }
+ insertIntoListsForBlock(NewAccess, BB, Point);
BlockNumberingValid.erase(BB);
return NewAccess;
}
assert(I->getParent() == InsertPt->getBlock() &&
"New and old access must be in the same block");
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
- auto *Accesses = getOrCreateAccessList(InsertPt->getBlock());
- Accesses->insert(AccessList::iterator(InsertPt), NewAccess);
BlockNumberingValid.erase(InsertPt->getBlock());
+ insertIntoListsBefore(NewAccess, InsertPt->getBlock(),
+ InsertPt->getIterator());
return NewAccess;
}
assert(I->getParent() == InsertPt->getBlock() &&
"New and old access must be in the same block");
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
- auto *Accesses = getOrCreateAccessList(InsertPt->getBlock());
- Accesses->insertAfter(AccessList::iterator(InsertPt), NewAccess);
BlockNumberingValid.erase(InsertPt->getBlock());
+ insertIntoListsBefore(NewAccess, InsertPt->getBlock(),
+ ++(InsertPt->getIterator()));
return NewAccess;
}
void MemorySSA::spliceMemoryAccessAbove(MemoryDef *Where,
MemoryUseOrDef *What) {
- assert(What != getLiveOnEntryDef() &&
- Where != getLiveOnEntryDef() && "Can't splice (above) LOE.");
+ assert(What != getLiveOnEntryDef() && Where != getLiveOnEntryDef() &&
+ "Can't splice (above) LOE.");
assert(dominates(Where, What) && "Only upwards splices are permitted.");
if (Where == What)
if (VMA->second == MA)
ValueToMemoryAccess.erase(VMA);
+ // The access list owns the reference, so we erase it from the non-owning list
+ // first.
+ if (!isa<MemoryUse>(MA)) {
+ auto DefsIt = PerBlockDefs.find(MA->getBlock());
+ std::unique_ptr<DefsList> &Defs = DefsIt->second;
+ Defs->remove(*MA);
+ if (Defs->empty())
+ PerBlockDefs.erase(DefsIt);
+ }
+
auto AccessIt = PerBlockAccesses.find(MA->getBlock());
std::unique_ptr<AccessList> &Accesses = AccessIt->second;
Accesses->erase(MA);
// lists think, as well as the order in the blocks vs the order in the access
// lists.
SmallVector<MemoryAccess *, 32> ActualAccesses;
+ SmallVector<MemoryAccess *, 32> ActualDefs;
for (BasicBlock &B : F) {
const AccessList *AL = getBlockAccesses(&B);
+ const auto *DL = getBlockDefs(&B);
MemoryAccess *Phi = getMemoryAccess(&B);
- if (Phi)
+ if (Phi) {
ActualAccesses.push_back(Phi);
+ ActualDefs.push_back(Phi);
+ }
+
for (Instruction &I : B) {
MemoryAccess *MA = getMemoryAccess(&I);
- assert((!MA || AL) && "We have memory affecting instructions "
- "in this block but they are not in the "
- "access list");
- if (MA)
+ assert((!MA || (AL && (isa<MemoryUse>(MA) || DL))) &&
+ "We have memory affecting instructions "
+ "in this block but they are not in the "
+ "access list or defs list");
+ if (MA) {
ActualAccesses.push_back(MA);
+ if (isa<MemoryDef>(MA))
+ ActualDefs.push_back(MA);
+ }
}
// Either we hit the assert, really have no accesses, or we have both
- // accesses and an access list
- if (!AL)
+ // accesses and an access list.
+ // Same with defs.
+ if (!AL && !DL)
continue;
assert(AL->size() == ActualAccesses.size() &&
"We don't have the same number of accesses in the block as on the "
"access list");
+ assert(DL ||
+ ActualDefs.size() == 0 &&
+ "Either we should have a defs list, or we should have no defs");
+ assert((!DL || DL->size() == ActualDefs.size()) &&
+ "We don't have the same number of defs in the block as on the "
+ "def list");
auto ALI = AL->begin();
auto AAI = ActualAccesses.begin();
while (ALI != AL->end() && AAI != ActualAccesses.end()) {
++AAI;
}
ActualAccesses.clear();
+ if (DL) {
+ auto DLI = DL->begin();
+ auto ADI = ActualDefs.begin();
+ while (DLI != DL->end() && ADI != ActualDefs.end()) {
+ assert(&*DLI == *ADI && "Not the same defs in the same order");
+ ++DLI;
+ ++ADI;
+ }
+ }
+ ActualDefs.clear();
}
}