mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-18 18:32:32 +00:00
MemorySSA: Link all defs together into an intrusive defslist, to make updater easier
Summary: This is the first in a series of patches to add a simple, generalized updater to MemorySSA. For MemorySSA, every def is may-def, instead of the normal must-def. (the best way to think of memoryssa is "everything is really one variable, with different versions of that variable at different points in the program). This means when updating, we end up having to do a bunch of work to touch defs below and above us. In order to support this quickly, i have ilist'd all the defs for each block. ilist supports tags, so this is quite easy. the only slightly messy part is that you can't have two iplists for the same type that differ only whether they have the ownership part enabled or not, because the traits are for the value type. The verifiers have been updated to test that the def order is correct. Reviewers: george.burgess.iv Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29046 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293085 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
eb91947709
commit
db632c77aa
@ -73,13 +73,14 @@
|
|||||||
#define LLVM_TRANSFORMS_UTILS_MEMORYSSA_H
|
#define LLVM_TRANSFORMS_UTILS_MEMORYSSA_H
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/DenseSet.h"
|
||||||
#include "llvm/ADT/GraphTraits.h"
|
#include "llvm/ADT/GraphTraits.h"
|
||||||
#include "llvm/ADT/iterator_range.h"
|
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/ilist.h"
|
#include "llvm/ADT/ilist.h"
|
||||||
#include "llvm/ADT/ilist_node.h"
|
#include "llvm/ADT/ilist_node.h"
|
||||||
#include "llvm/ADT/iterator.h"
|
#include "llvm/ADT/iterator.h"
|
||||||
|
#include "llvm/ADT/iterator_range.h"
|
||||||
#include "llvm/Analysis/AliasAnalysis.h"
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/Analysis/MemoryLocation.h"
|
#include "llvm/Analysis/MemoryLocation.h"
|
||||||
#include "llvm/Analysis/PHITransAddr.h"
|
#include "llvm/Analysis/PHITransAddr.h"
|
||||||
@ -108,6 +109,11 @@ class Instruction;
|
|||||||
class MemoryAccess;
|
class MemoryAccess;
|
||||||
class LLVMContext;
|
class LLVMContext;
|
||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
|
namespace MSSAHelpers {
|
||||||
|
|
||||||
|
struct AllAccessTag {};
|
||||||
|
struct DefsOnlyTag {};
|
||||||
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
// Used to signify what the default invalid ID is for MemoryAccess's
|
// Used to signify what the default invalid ID is for MemoryAccess's
|
||||||
@ -122,8 +128,16 @@ using const_memoryaccess_def_iterator =
|
|||||||
|
|
||||||
// \brief The base for all memory accesses. All memory accesses in a block are
|
// \brief The base for all memory accesses. All memory accesses in a block are
|
||||||
// linked together using an intrusive list.
|
// 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:
|
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
|
// Methods for support type inquiry through isa, cast, and
|
||||||
// dyn_cast
|
// dyn_cast
|
||||||
static inline bool classof(const MemoryAccess *) { return true; }
|
static inline bool classof(const MemoryAccess *) { return true; }
|
||||||
@ -156,6 +170,33 @@ public:
|
|||||||
memoryaccess_def_iterator defs_end();
|
memoryaccess_def_iterator defs_end();
|
||||||
const_memoryaccess_def_iterator defs_end() const;
|
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:
|
protected:
|
||||||
friend class MemorySSA;
|
friend class MemorySSA;
|
||||||
friend class MemoryUseOrDef;
|
friend class MemoryUseOrDef;
|
||||||
@ -531,7 +572,14 @@ public:
|
|||||||
return LiveOnEntryDef.get();
|
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.
|
/// \brief Return the list of MemoryAccess's for a given basic block.
|
||||||
///
|
///
|
||||||
@ -540,6 +588,14 @@ public:
|
|||||||
return getWritableBlockAccesses(BB);
|
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.
|
/// \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
|
/// 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.
|
/// assert if you try to create one where it already exists.
|
||||||
@ -623,12 +679,18 @@ protected:
|
|||||||
void verifyDomination(Function &F) const;
|
void verifyDomination(Function &F) const;
|
||||||
void verifyOrdering(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 {
|
AccessList *getWritableBlockAccesses(const BasicBlock *BB) const {
|
||||||
auto It = PerBlockAccesses.find(BB);
|
auto It = PerBlockAccesses.find(BB);
|
||||||
return It == PerBlockAccesses.end() ? nullptr : It->second.get();
|
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:
|
private:
|
||||||
class CachingWalker;
|
class CachingWalker;
|
||||||
class OptimizeUses;
|
class OptimizeUses;
|
||||||
@ -639,6 +701,7 @@ private:
|
|||||||
|
|
||||||
void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const;
|
void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const;
|
||||||
using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>;
|
using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>;
|
||||||
|
using DefsMap = DenseMap<const BasicBlock *, std::unique_ptr<DefsList>>;
|
||||||
|
|
||||||
void
|
void
|
||||||
determineInsertionPoint(const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks);
|
determineInsertionPoint(const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks);
|
||||||
@ -656,15 +719,26 @@ private:
|
|||||||
void renamePass(DomTreeNode *, MemoryAccess *IncomingVal,
|
void renamePass(DomTreeNode *, MemoryAccess *IncomingVal,
|
||||||
SmallPtrSet<BasicBlock *, 16> &Visited);
|
SmallPtrSet<BasicBlock *, 16> &Visited);
|
||||||
AccessList *getOrCreateAccessList(const BasicBlock *);
|
AccessList *getOrCreateAccessList(const BasicBlock *);
|
||||||
|
DefsList *getOrCreateDefsList(const BasicBlock *);
|
||||||
void renumberBlock(const BasicBlock *) const;
|
void renumberBlock(const BasicBlock *) const;
|
||||||
|
void insertIntoListsForBlock(MemoryAccess *, const BasicBlock *,
|
||||||
|
InsertionPlace);
|
||||||
|
void insertIntoListsBefore(MemoryAccess *, const BasicBlock *,
|
||||||
|
AccessList::iterator);
|
||||||
AliasAnalysis *AA;
|
AliasAnalysis *AA;
|
||||||
DominatorTree *DT;
|
DominatorTree *DT;
|
||||||
Function &F;
|
Function &F;
|
||||||
|
|
||||||
// Memory SSA mappings
|
// Memory SSA mappings
|
||||||
DenseMap<const Value *, MemoryAccess *> ValueToMemoryAccess;
|
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;
|
AccessMap PerBlockAccesses;
|
||||||
|
DefsMap PerBlockDefs;
|
||||||
std::unique_ptr<MemoryAccess> LiveOnEntryDef;
|
std::unique_ptr<MemoryAccess> LiveOnEntryDef;
|
||||||
|
|
||||||
// Domination mappings
|
// Domination mappings
|
||||||
@ -957,9 +1031,7 @@ public:
|
|||||||
fillInCurrentPair();
|
fillInCurrentPair();
|
||||||
}
|
}
|
||||||
|
|
||||||
upward_defs_iterator() {
|
upward_defs_iterator() { CurrentPair.first = nullptr; }
|
||||||
CurrentPair.first = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const upward_defs_iterator &Other) const {
|
bool operator==(const upward_defs_iterator &Other) const {
|
||||||
return DefIterator == Other.DefIterator;
|
return DefIterator == Other.DefIterator;
|
||||||
|
@ -145,8 +145,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
union {
|
union {
|
||||||
ImmutableCallSite CS;
|
ImmutableCallSite CS;
|
||||||
MemoryLocation Loc;
|
MemoryLocation Loc;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1247,6 +1247,13 @@ MemorySSA::AccessList *MemorySSA::getOrCreateAccessList(const BasicBlock *BB) {
|
|||||||
Res.first->second = make_unique<AccessList>();
|
Res.first->second = make_unique<AccessList>();
|
||||||
return Res.first->second.get();
|
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
|
/// 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
|
/// their defining access at the thing that actually clobbers them. Because it
|
||||||
@ -1477,14 +1484,8 @@ void MemorySSA::placePHINodes(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Now place MemoryPhi nodes.
|
// Now place MemoryPhi nodes.
|
||||||
for (auto &BB : IDFBlocks) {
|
for (auto &BB : IDFBlocks)
|
||||||
// Insert phi node
|
createMemoryPhi(BB);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemorySSA::buildMemorySSA() {
|
void MemorySSA::buildMemorySSA() {
|
||||||
@ -1511,15 +1512,21 @@ void MemorySSA::buildMemorySSA() {
|
|||||||
BBNumbers[&B] = NextBBNum++;
|
BBNumbers[&B] = NextBBNum++;
|
||||||
bool InsertIntoDef = false;
|
bool InsertIntoDef = false;
|
||||||
AccessList *Accesses = nullptr;
|
AccessList *Accesses = nullptr;
|
||||||
|
DefsList *Defs = nullptr;
|
||||||
for (Instruction &I : B) {
|
for (Instruction &I : B) {
|
||||||
MemoryUseOrDef *MUD = createNewAccess(&I);
|
MemoryUseOrDef *MUD = createNewAccess(&I);
|
||||||
if (!MUD)
|
if (!MUD)
|
||||||
continue;
|
continue;
|
||||||
InsertIntoDef |= isa<MemoryDef>(MUD);
|
|
||||||
|
|
||||||
if (!Accesses)
|
if (!Accesses)
|
||||||
Accesses = getOrCreateAccessList(&B);
|
Accesses = getOrCreateAccessList(&B);
|
||||||
Accesses->push_back(MUD);
|
Accesses->push_back(MUD);
|
||||||
|
if (isa<MemoryDef>(MUD)) {
|
||||||
|
InsertIntoDef = true;
|
||||||
|
if (!Defs)
|
||||||
|
Defs = getOrCreateDefsList(&B);
|
||||||
|
Defs->push_back(*MUD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (InsertIntoDef)
|
if (InsertIntoDef)
|
||||||
DefiningBlocks.insert(&B);
|
DefiningBlocks.insert(&B);
|
||||||
@ -1558,13 +1565,73 @@ MemorySSA::CachingWalker *MemorySSA::getWalkerImpl() {
|
|||||||
return Walker.get();
|
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) {
|
MemoryPhi *MemorySSA::createMemoryPhi(BasicBlock *BB) {
|
||||||
assert(!getMemoryAccess(BB) && "MemoryPhi already exists for this BB");
|
assert(!getMemoryAccess(BB) && "MemoryPhi already exists for this BB");
|
||||||
AccessList *Accesses = getOrCreateAccessList(BB);
|
|
||||||
MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++);
|
MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++);
|
||||||
|
insertIntoListsForBlock(Phi, BB, Beginning);
|
||||||
ValueToMemoryAccess[BB] = Phi;
|
ValueToMemoryAccess[BB] = Phi;
|
||||||
// Phi's always are placed at the front of the block.
|
// Phi's always are placed at the front of the block.
|
||||||
Accesses->push_front(Phi);
|
|
||||||
BlockNumberingValid.erase(BB);
|
BlockNumberingValid.erase(BB);
|
||||||
return Phi;
|
return Phi;
|
||||||
}
|
}
|
||||||
@ -1585,16 +1652,7 @@ MemoryAccess *MemorySSA::createMemoryAccessInBB(Instruction *I,
|
|||||||
const BasicBlock *BB,
|
const BasicBlock *BB,
|
||||||
InsertionPlace Point) {
|
InsertionPlace Point) {
|
||||||
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
|
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
|
||||||
auto *Accesses = getOrCreateAccessList(BB);
|
insertIntoListsForBlock(NewAccess, BB, Point);
|
||||||
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);
|
|
||||||
}
|
|
||||||
BlockNumberingValid.erase(BB);
|
BlockNumberingValid.erase(BB);
|
||||||
return NewAccess;
|
return NewAccess;
|
||||||
}
|
}
|
||||||
@ -1605,9 +1663,9 @@ MemoryUseOrDef *MemorySSA::createMemoryAccessBefore(Instruction *I,
|
|||||||
assert(I->getParent() == InsertPt->getBlock() &&
|
assert(I->getParent() == InsertPt->getBlock() &&
|
||||||
"New and old access must be in the same block");
|
"New and old access must be in the same block");
|
||||||
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
|
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
|
||||||
auto *Accesses = getOrCreateAccessList(InsertPt->getBlock());
|
|
||||||
Accesses->insert(AccessList::iterator(InsertPt), NewAccess);
|
|
||||||
BlockNumberingValid.erase(InsertPt->getBlock());
|
BlockNumberingValid.erase(InsertPt->getBlock());
|
||||||
|
insertIntoListsBefore(NewAccess, InsertPt->getBlock(),
|
||||||
|
InsertPt->getIterator());
|
||||||
return NewAccess;
|
return NewAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1617,16 +1675,16 @@ MemoryUseOrDef *MemorySSA::createMemoryAccessAfter(Instruction *I,
|
|||||||
assert(I->getParent() == InsertPt->getBlock() &&
|
assert(I->getParent() == InsertPt->getBlock() &&
|
||||||
"New and old access must be in the same block");
|
"New and old access must be in the same block");
|
||||||
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
|
MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition);
|
||||||
auto *Accesses = getOrCreateAccessList(InsertPt->getBlock());
|
|
||||||
Accesses->insertAfter(AccessList::iterator(InsertPt), NewAccess);
|
|
||||||
BlockNumberingValid.erase(InsertPt->getBlock());
|
BlockNumberingValid.erase(InsertPt->getBlock());
|
||||||
|
insertIntoListsBefore(NewAccess, InsertPt->getBlock(),
|
||||||
|
++(InsertPt->getIterator()));
|
||||||
return NewAccess;
|
return NewAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemorySSA::spliceMemoryAccessAbove(MemoryDef *Where,
|
void MemorySSA::spliceMemoryAccessAbove(MemoryDef *Where,
|
||||||
MemoryUseOrDef *What) {
|
MemoryUseOrDef *What) {
|
||||||
assert(What != getLiveOnEntryDef() &&
|
assert(What != getLiveOnEntryDef() && Where != getLiveOnEntryDef() &&
|
||||||
Where != getLiveOnEntryDef() && "Can't splice (above) LOE.");
|
"Can't splice (above) LOE.");
|
||||||
assert(dominates(Where, What) && "Only upwards splices are permitted.");
|
assert(dominates(Where, What) && "Only upwards splices are permitted.");
|
||||||
|
|
||||||
if (Where == What)
|
if (Where == What)
|
||||||
@ -1761,6 +1819,16 @@ void MemorySSA::removeFromLookups(MemoryAccess *MA) {
|
|||||||
if (VMA->second == MA)
|
if (VMA->second == MA)
|
||||||
ValueToMemoryAccess.erase(VMA);
|
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());
|
auto AccessIt = PerBlockAccesses.find(MA->getBlock());
|
||||||
std::unique_ptr<AccessList> &Accesses = AccessIt->second;
|
std::unique_ptr<AccessList> &Accesses = AccessIt->second;
|
||||||
Accesses->erase(MA);
|
Accesses->erase(MA);
|
||||||
@ -1838,26 +1906,42 @@ void MemorySSA::verifyOrdering(Function &F) const {
|
|||||||
// lists think, as well as the order in the blocks vs the order in the access
|
// lists think, as well as the order in the blocks vs the order in the access
|
||||||
// lists.
|
// lists.
|
||||||
SmallVector<MemoryAccess *, 32> ActualAccesses;
|
SmallVector<MemoryAccess *, 32> ActualAccesses;
|
||||||
|
SmallVector<MemoryAccess *, 32> ActualDefs;
|
||||||
for (BasicBlock &B : F) {
|
for (BasicBlock &B : F) {
|
||||||
const AccessList *AL = getBlockAccesses(&B);
|
const AccessList *AL = getBlockAccesses(&B);
|
||||||
|
const auto *DL = getBlockDefs(&B);
|
||||||
MemoryAccess *Phi = getMemoryAccess(&B);
|
MemoryAccess *Phi = getMemoryAccess(&B);
|
||||||
if (Phi)
|
if (Phi) {
|
||||||
ActualAccesses.push_back(Phi);
|
ActualAccesses.push_back(Phi);
|
||||||
|
ActualDefs.push_back(Phi);
|
||||||
|
}
|
||||||
|
|
||||||
for (Instruction &I : B) {
|
for (Instruction &I : B) {
|
||||||
MemoryAccess *MA = getMemoryAccess(&I);
|
MemoryAccess *MA = getMemoryAccess(&I);
|
||||||
assert((!MA || AL) && "We have memory affecting instructions "
|
assert((!MA || (AL && (isa<MemoryUse>(MA) || DL))) &&
|
||||||
"in this block but they are not in the "
|
"We have memory affecting instructions "
|
||||||
"access list");
|
"in this block but they are not in the "
|
||||||
if (MA)
|
"access list or defs list");
|
||||||
|
if (MA) {
|
||||||
ActualAccesses.push_back(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
|
// Either we hit the assert, really have no accesses, or we have both
|
||||||
// accesses and an access list
|
// accesses and an access list.
|
||||||
if (!AL)
|
// Same with defs.
|
||||||
|
if (!AL && !DL)
|
||||||
continue;
|
continue;
|
||||||
assert(AL->size() == ActualAccesses.size() &&
|
assert(AL->size() == ActualAccesses.size() &&
|
||||||
"We don't have the same number of accesses in the block as on the "
|
"We don't have the same number of accesses in the block as on the "
|
||||||
"access list");
|
"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 ALI = AL->begin();
|
||||||
auto AAI = ActualAccesses.begin();
|
auto AAI = ActualAccesses.begin();
|
||||||
while (ALI != AL->end() && AAI != ActualAccesses.end()) {
|
while (ALI != AL->end() && AAI != ActualAccesses.end()) {
|
||||||
@ -1866,6 +1950,16 @@ void MemorySSA::verifyOrdering(Function &F) const {
|
|||||||
++AAI;
|
++AAI;
|
||||||
}
|
}
|
||||||
ActualAccesses.clear();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,6 +485,7 @@ TEST_F(MemorySSATest, WalkerReopt) {
|
|||||||
EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber);
|
EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Test out MemorySSA::spliceMemoryAccessAbove.
|
// Test out MemorySSA::spliceMemoryAccessAbove.
|
||||||
TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
|
TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
|
||||||
F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
|
F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
|
||||||
@ -532,3 +533,4 @@ TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
|
|||||||
EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1),
|
EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1),
|
||||||
MSSA.getMemoryAccess(StoreA2)));
|
MSSA.getMemoryAccess(StoreA2)));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user