Skip to content

Commit

Permalink
MemorySSA: Add support for renaming uses in the updater.
Browse files Browse the repository at this point in the history
Summary:
This lets one add aliasing stores to the updater.
(i'm next going to move the creation/etc functions to the updater)

Reviewers: george.burgess.iv

Subscribers: llvm-commits, Prazek

Differential Revision: https://reviews.llvm.org/D30154

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295677 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
dberlin committed Feb 20, 2017
1 parent c4d575e commit 4f1c254
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 31 deletions.
12 changes: 9 additions & 3 deletions include/llvm/Transforms/Utils/MemorySSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,11 @@ class MemorySSA {
// on the updater to fixup what it breaks, so it is not public.
void moveTo(MemoryUseOrDef *What, BasicBlock *BB, AccessList::iterator Where);
void moveTo(MemoryUseOrDef *What, BasicBlock *BB, InsertionPlace Point);
// Rename the dominator tree branch rooted at BB.
void renamePass(BasicBlock *BB, MemoryAccess *IncomingVal,
SmallPtrSetImpl<BasicBlock *> &Visited) {
renamePass(DT->getNode(BB), IncomingVal, Visited, true, true);
}

private:
class CachingWalker;
Expand All @@ -708,12 +713,13 @@ class MemorySSA {
MemoryAccess *findDominatingDef(BasicBlock *, enum InsertionPlace);
void removeFromLookups(MemoryAccess *);
void removeFromLists(MemoryAccess *, bool ShouldDelete = true);

void placePHINodes(const SmallPtrSetImpl<BasicBlock *> &,
const DenseMap<const BasicBlock *, unsigned int> &);
MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *);
MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *, bool);
void renameSuccessorPhis(BasicBlock *, MemoryAccess *, bool);
void renamePass(DomTreeNode *, MemoryAccess *IncomingVal,
SmallPtrSet<BasicBlock *, 16> &Visited);
SmallPtrSetImpl<BasicBlock *> &Visited,
bool SkipVisited = false, bool RenameAllUses = false);
AccessList *getOrCreateAccessList(const BasicBlock *);
DefsList *getOrCreateDefsList(const BasicBlock *);
void renumberBlock(const BasicBlock *) const;
Expand Down
20 changes: 19 additions & 1 deletion include/llvm/Transforms/Utils/MemorySSAUpdater.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,30 @@ class MemorySSAUpdater {

public:
MemorySSAUpdater(MemorySSA *MSSA) : MSSA(MSSA) {}
void insertDef(MemoryDef *Def);
// Insert a definition into the MemorySSA IR. RenameUses will rename any use
// below the new def block (and any inserted phis). RenameUses should be set
// to true if the definition may cause new aliases for loads below it. This
// is not the case for hoisting or sinking or other forms of code *movement*.
// It *is* the case for straight code insertion.
// For example:
// store a
// if (foo) { }
// load a
//
// Moving the store into the if block, and calling insertDef, does not
// require RenameUses.
// However, changing it to:
// store a
// if (foo) { store b }
// load a
// Where a mayalias b, *does* require RenameUses be set to true.
void insertDef(MemoryDef *Def, bool RenameUses = false);
void insertUse(MemoryUse *Use);
void moveBefore(MemoryUseOrDef *What, MemoryUseOrDef *Where);
void moveAfter(MemoryUseOrDef *What, MemoryUseOrDef *Where);
void moveToPlace(MemoryUseOrDef *What, BasicBlock *BB,
MemorySSA::InsertionPlace Where);

private:
// Move What before Where in the MemorySSA IR.
template <class WhereType>
Expand Down
73 changes: 49 additions & 24 deletions lib/Transforms/Utils/MemorySSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1116,18 +1116,37 @@ class MemorySSA::CachingWalker final : public MemorySSAWalker {
}
};

void MemorySSA::renameSuccessorPhis(BasicBlock *BB, MemoryAccess *IncomingVal,
bool RenameAllUses) {
// Pass through values to our successors
for (const BasicBlock *S : successors(BB)) {
auto It = PerBlockAccesses.find(S);
// Rename the phi nodes in our successor block
if (It == PerBlockAccesses.end() || !isa<MemoryPhi>(It->second->front()))
continue;
AccessList *Accesses = It->second.get();
auto *Phi = cast<MemoryPhi>(&Accesses->front());
if (RenameAllUses) {
int PhiIndex = Phi->getBasicBlockIndex(BB);
assert(PhiIndex != -1 && "Incomplete phi during partial rename");
Phi->setIncomingValue(PhiIndex, IncomingVal);
} else
Phi->addIncoming(IncomingVal, BB);
}
}

/// \brief Rename a single basic block into MemorySSA form.
/// Uses the standard SSA renaming algorithm.
/// \returns The new incoming value.
MemoryAccess *MemorySSA::renameBlock(BasicBlock *BB,
MemoryAccess *IncomingVal) {
MemoryAccess *MemorySSA::renameBlock(BasicBlock *BB, MemoryAccess *IncomingVal,
bool RenameAllUses) {
auto It = PerBlockAccesses.find(BB);
// Skip most processing if the list is empty.
if (It != PerBlockAccesses.end()) {
AccessList *Accesses = It->second.get();
for (MemoryAccess &L : *Accesses) {
if (MemoryUseOrDef *MUD = dyn_cast<MemoryUseOrDef>(&L)) {
if (MUD->getDefiningAccess() == nullptr)
if (MUD->getDefiningAccess() == nullptr || RenameAllUses)
MUD->setDefiningAccess(IncomingVal);
if (isa<MemoryDef>(&L))
IncomingVal = &L;
Expand All @@ -1136,18 +1155,6 @@ MemoryAccess *MemorySSA::renameBlock(BasicBlock *BB,
}
}
}

// Pass through values to our successors
for (const BasicBlock *S : successors(BB)) {
auto It = PerBlockAccesses.find(S);
// Rename the phi nodes in our successor block
if (It == PerBlockAccesses.end() || !isa<MemoryPhi>(It->second->front()))
continue;
AccessList *Accesses = It->second.get();
auto *Phi = cast<MemoryPhi>(&Accesses->front());
Phi->addIncoming(IncomingVal, BB);
}

return IncomingVal;
}

Expand All @@ -1156,11 +1163,19 @@ MemoryAccess *MemorySSA::renameBlock(BasicBlock *BB,
/// We walk the dominator tree in preorder, renaming accesses, and then filling
/// in phi nodes in our successors.
void MemorySSA::renamePass(DomTreeNode *Root, MemoryAccess *IncomingVal,
SmallPtrSet<BasicBlock *, 16> &Visited) {
SmallPtrSetImpl<BasicBlock *> &Visited,
bool SkipVisited, bool RenameAllUses) {
SmallVector<RenamePassData, 32> WorkStack;
IncomingVal = renameBlock(Root->getBlock(), IncomingVal);
// Skip everything if we already renamed this block and we are skipping.
// Note: You can't sink this into the if, because we need it to occur
// regardless of whether we skip blocks or not.
bool AlreadyVisited = !Visited.insert(Root->getBlock()).second;
if (SkipVisited && AlreadyVisited)
return;

IncomingVal = renameBlock(Root->getBlock(), IncomingVal, RenameAllUses);
renameSuccessorPhis(Root->getBlock(), IncomingVal, RenameAllUses);
WorkStack.push_back({Root, Root->begin(), IncomingVal});
Visited.insert(Root->getBlock());

while (!WorkStack.empty()) {
DomTreeNode *Node = WorkStack.back().DTN;
Expand All @@ -1173,8 +1188,20 @@ void MemorySSA::renamePass(DomTreeNode *Root, MemoryAccess *IncomingVal,
DomTreeNode *Child = *ChildIt;
++WorkStack.back().ChildIt;
BasicBlock *BB = Child->getBlock();
Visited.insert(BB);
IncomingVal = renameBlock(BB, IncomingVal);
// Note: You can't sink this into the if, because we need it to occur
// regardless of whether we skip blocks or not.
AlreadyVisited = !Visited.insert(BB).second;
if (SkipVisited && AlreadyVisited) {
// We already visited this during our renaming, which can happen when
// being asked to rename multiple blocks. Figure out the incoming val,
// which is the last def.
// Incoming value can only change if there is a block def, and in that
// case, it's the last block def in the list.
if (auto *BlockDefs = getWritableBlockDefs(BB))
IncomingVal = &*BlockDefs->rbegin();
} else
IncomingVal = renameBlock(BB, IncomingVal, RenameAllUses);
renameSuccessorPhis(BB, IncomingVal, RenameAllUses);
WorkStack.push_back({Child, Child->begin(), IncomingVal});
}
}
Expand Down Expand Up @@ -1891,9 +1918,7 @@ void MemorySSA::print(raw_ostream &OS) const {
}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void MemorySSA::dump() const {
print(dbgs());
}
LLVM_DUMP_METHOD void MemorySSA::dump() const { print(dbgs()); }
#endif

void MemorySSA::verifyMemorySSA() const {
Expand Down Expand Up @@ -2163,7 +2188,7 @@ void MemoryUse::print(raw_ostream &OS) const {
}

void MemoryAccess::dump() const {
// Cannot completely remove virtual function even in release mode.
// Cannot completely remove virtual function even in release mode.
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
print(dbgs());
dbgs() << "\n";
Expand Down
20 changes: 19 additions & 1 deletion lib/Transforms/Utils/MemorySSAUpdater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ void setMemoryPhiValueForBlock(MemoryPhi *MP, const BasicBlock *BB,
// Then, we update the defs below us (and any new phi nodes) in the graph to
// point to the correct new defs, to ensure we only have one variable, and no
// disconnected stores.
void MemorySSAUpdater::insertDef(MemoryDef *MD) {
void MemorySSAUpdater::insertDef(MemoryDef *MD, bool RenameUses) {
InsertedPHIs.clear();

// See if we had a local def, and if not, go hunting.
Expand Down Expand Up @@ -287,6 +287,24 @@ void MemorySSAUpdater::insertDef(MemoryDef *MD) {
// Put any new phis on the fixup list, and process them
FixupList.append(InsertedPHIs.end() - StartingPHISize, InsertedPHIs.end());
}
// Now that all fixups are done, rename all uses if we are asked.
if (RenameUses) {
SmallPtrSet<BasicBlock *, 16> Visited;
BasicBlock *StartBlock = MD->getBlock();
// We are guaranteed there is a def in the block, because we just got it
// handed to us in this function.
MemoryAccess *FirstDef = &*MSSA->getWritableBlockDefs(StartBlock)->begin();
// Convert to incoming value if it's a memorydef. A phi *is* already an
// incoming value.
if (auto *MD = dyn_cast<MemoryDef>(FirstDef))
FirstDef = MD->getDefiningAccess();

MSSA->renamePass(MD->getBlock(), FirstDef, Visited);
// We just inserted a phi into this block, so the incoming value will become
// the phi anyway, so it does not matter what we pass.
for (auto *MP : InsertedPHIs)
MSSA->renamePass(MP->getBlock(), nullptr, Visited);
}
}

void MemorySSAUpdater::fixupDefs(const SmallVectorImpl<MemoryAccess *> &Vars) {
Expand Down
8 changes: 6 additions & 2 deletions unittests/Transforms/Utils/MemorySSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ TEST_F(MemorySSATest, CreateLoadsAndStoreUpdater) {
StoreInst *LeftStore = B.CreateStore(B.getInt8(16), PointerArg);
MemoryAccess *LeftStoreAccess = MSSA.createMemoryAccessInBB(
LeftStore, nullptr, Left, MemorySSA::Beginning);
Updater.insertDef(cast<MemoryDef>(LeftStoreAccess));
Updater.insertDef(cast<MemoryDef>(LeftStoreAccess), false);
// We don't touch existing loads, so we need to create a new one to get a phi
// Add the second load
B.SetInsertPoint(Merge, Merge->begin());
Expand All @@ -183,7 +183,11 @@ TEST_F(MemorySSATest, CreateLoadsAndStoreUpdater) {
StoreInst *SecondEntryStore = B.CreateStore(B.getInt8(16), PointerArg);
MemoryAccess *SecondEntryStoreAccess = MSSA.createMemoryAccessInBB(
SecondEntryStore, nullptr, Entry, MemorySSA::End);
Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess));
// Insert it twice just to test renaming
Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess), false);
EXPECT_NE(FirstLoadAccess->getDefiningAccess(), MergePhi);
Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess), true);
EXPECT_EQ(FirstLoadAccess->getDefiningAccess(), MergePhi);
// and make sure the phi below it got updated, despite being blocks away
MergePhi = dyn_cast<MemoryPhi>(SecondLoadAccess->getDefiningAccess());
EXPECT_NE(MergePhi, nullptr);
Expand Down

0 comments on commit 4f1c254

Please sign in to comment.