mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 09:13:34 +00:00
Split mem2reg promotion into two parts: a function which does the work, and
a pass which wraps the function. This allows other passes to use the functionality llvm-svn: 5610
This commit is contained in:
parent
74aa1f8c03
commit
2e4c1c8640
59
lib/Transforms/Scalar/Mem2Reg.cpp
Normal file
59
lib/Transforms/Scalar/Mem2Reg.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//===- Mem2Reg.cpp - The -mem2reg pass, a wrapper around the Utils lib ----===//
|
||||||
|
//
|
||||||
|
// This pass is a simple pass wrapper around the PromoteMemToReg function call
|
||||||
|
// exposed by the Utils library.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/Transforms/Scalar.h"
|
||||||
|
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
||||||
|
#include "llvm/Analysis/Dominators.h"
|
||||||
|
#include "llvm/iMemory.h"
|
||||||
|
#include "llvm/Function.h"
|
||||||
|
#include "Support/Statistic.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Statistic<> NumPromoted("mem2reg", "Number of alloca's promoted");
|
||||||
|
|
||||||
|
struct PromotePass : public FunctionPass {
|
||||||
|
// runOnFunction - To run this pass, first we calculate the alloca
|
||||||
|
// instructions that are safe for promotion, then we promote each one.
|
||||||
|
//
|
||||||
|
virtual bool runOnFunction(Function &F);
|
||||||
|
|
||||||
|
// getAnalysisUsage - We need dominance frontiers
|
||||||
|
//
|
||||||
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
|
AU.addRequired<DominanceFrontier>();
|
||||||
|
AU.setPreservesCFG();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterOpt<PromotePass> X("mem2reg", "Promote Memory to Register");
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
bool PromotePass::runOnFunction(Function &F) {
|
||||||
|
std::vector<AllocaInst*> Allocas;
|
||||||
|
|
||||||
|
BasicBlock &BB = F.getEntryNode(); // Get the entry node for the function
|
||||||
|
|
||||||
|
// Find allocas that are safe to promote, by looking at all instructions in
|
||||||
|
// the entry node
|
||||||
|
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
|
||||||
|
if (AllocaInst *AI = dyn_cast<AllocaInst>(&*I)) // Is it an alloca?
|
||||||
|
if (isAllocaPromotable(AI))
|
||||||
|
Allocas.push_back(AI);
|
||||||
|
|
||||||
|
if (!Allocas.empty()) {
|
||||||
|
PromoteMemToReg(Allocas, getAnalysis<DominanceFrontier>());
|
||||||
|
NumPromoted += Allocas.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// createPromoteMemoryToRegister - Provide an entry point to create this pass.
|
||||||
|
//
|
||||||
|
Pass *createPromoteMemoryToRegister() {
|
||||||
|
return new PromotePass();
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
//===- PromoteMemoryToRegister.cpp - Convert memory refs to regs ----------===//
|
//===- PromoteMemoryToRegister.cpp - Convert memory refs to regs ----------===//
|
||||||
//
|
//
|
||||||
// This pass is used to promote memory references to be register references. A
|
// This file is used to promote memory references to be register references. A
|
||||||
// simple example of the transformation performed by this pass is:
|
// simple example of the transformation performed by this function is:
|
||||||
//
|
//
|
||||||
// FROM CODE TO CODE
|
// FROM CODE TO CODE
|
||||||
// %X = alloca int, uint 1 ret int 42
|
// %X = alloca int, uint 1 ret int 42
|
||||||
@ -9,17 +9,14 @@
|
|||||||
// %Y = load int* %X
|
// %Y = load int* %X
|
||||||
// ret int %Y
|
// ret int %Y
|
||||||
//
|
//
|
||||||
// To do this transformation, a simple analysis is done to ensure it is safe.
|
// The code is transformed by looping over all of the alloca instruction,
|
||||||
// Currently this just loops over all alloca instructions, looking for
|
// calculating dominator frontiers, then inserting phi-nodes following the usual
|
||||||
// instructions that are only used in simple load and stores.
|
// SSA construction algorithm. This code does not modify the CFG of the
|
||||||
//
|
// function.
|
||||||
// After this, the code is transformed by looping over all of the alloca
|
|
||||||
// instruction, calculating dominator frontiers, then inserting phi-nodes
|
|
||||||
// following the usual SSA construction algorithm.
|
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/Transforms/Scalar.h"
|
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
||||||
#include "llvm/Analysis/Dominators.h"
|
#include "llvm/Analysis/Dominators.h"
|
||||||
#include "llvm/iMemory.h"
|
#include "llvm/iMemory.h"
|
||||||
#include "llvm/iPHINode.h"
|
#include "llvm/iPHINode.h"
|
||||||
@ -27,54 +24,11 @@
|
|||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
#include "llvm/Constant.h"
|
#include "llvm/Constant.h"
|
||||||
#include "llvm/Type.h"
|
#include "llvm/Type.h"
|
||||||
#include "Support/Statistic.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
Statistic<> NumPromoted("mem2reg", "Number of alloca's promoted");
|
|
||||||
|
|
||||||
struct PromotePass : public FunctionPass {
|
|
||||||
std::vector<AllocaInst*> Allocas; // the alloca instruction..
|
|
||||||
std::map<Instruction*, unsigned> AllocaLookup; // reverse mapping of above
|
|
||||||
|
|
||||||
std::vector<std::vector<BasicBlock*> > PhiNodes;// Idx corresponds 2 Allocas
|
|
||||||
|
|
||||||
// List of instructions to remove at end of pass
|
|
||||||
std::vector<Instruction *> KillList;
|
|
||||||
|
|
||||||
std::map<BasicBlock*,
|
|
||||||
std::vector<PHINode*> > NewPhiNodes; // the PhiNodes we're adding
|
|
||||||
|
|
||||||
public:
|
|
||||||
// runOnFunction - To run this pass, first we calculate the alloca
|
|
||||||
// instructions that are safe for promotion, then we promote each one.
|
|
||||||
//
|
|
||||||
virtual bool runOnFunction(Function &F);
|
|
||||||
|
|
||||||
// getAnalysisUsage - We need dominance frontiers
|
|
||||||
//
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
||||||
AU.addRequired<DominanceFrontier>();
|
|
||||||
AU.setPreservesCFG();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RenamePass(BasicBlock *BB, BasicBlock *Pred,
|
|
||||||
std::vector<Value*> &IncVals,
|
|
||||||
std::set<BasicBlock*> &Visited);
|
|
||||||
bool QueuePhiNode(BasicBlock *BB, unsigned AllocaIdx);
|
|
||||||
void FindSafeAllocas(Function &F);
|
|
||||||
};
|
|
||||||
|
|
||||||
RegisterOpt<PromotePass> X("mem2reg", "Promote Memory to Register");
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
|
|
||||||
// isSafeAlloca - This predicate controls what types of alloca instructions are
|
|
||||||
// allowed to be promoted...
|
|
||||||
//
|
|
||||||
static inline bool isSafeAlloca(const AllocaInst *AI) {
|
|
||||||
if (AI->isArrayAllocation()) return false;
|
|
||||||
|
|
||||||
|
/// isAllocaPromotable - Return true if this alloca is legal for promotion.
|
||||||
|
/// This is true if there are only loads and stores to the alloca...
|
||||||
|
///
|
||||||
|
bool isAllocaPromotable(const AllocaInst *AI) {
|
||||||
// Only allow direct loads and stores...
|
// Only allow direct loads and stores...
|
||||||
for (Value::use_const_iterator UI = AI->use_begin(), UE = AI->use_end();
|
for (Value::use_const_iterator UI = AI->use_begin(), UE = AI->use_end();
|
||||||
UI != UE; ++UI) // Loop over all of the uses of the alloca
|
UI != UE; ++UI) // Loop over all of the uses of the alloca
|
||||||
@ -89,28 +43,51 @@ static inline bool isSafeAlloca(const AllocaInst *AI) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindSafeAllocas - Find allocas that are safe to promote
|
|
||||||
//
|
|
||||||
void PromotePass::FindSafeAllocas(Function &F) {
|
|
||||||
BasicBlock &BB = F.getEntryNode(); // Get the entry node for the function
|
|
||||||
|
|
||||||
// Look at all instructions in the entry node
|
namespace {
|
||||||
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
|
struct PromoteMem2Reg {
|
||||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(&*I)) // Is it an alloca?
|
const std::vector<AllocaInst*> &Allocas; // the alloca instructions..
|
||||||
if (isSafeAlloca(AI)) { // If safe alloca, add alloca to safe list
|
DominanceFrontier &DF;
|
||||||
AllocaLookup[AI] = Allocas.size(); // Keep reverse mapping
|
|
||||||
Allocas.push_back(AI);
|
std::map<Instruction*, unsigned> AllocaLookup; // reverse mapping of above
|
||||||
}
|
|
||||||
}
|
std::vector<std::vector<BasicBlock*> > PhiNodes;// Idx corresponds 2 Allocas
|
||||||
|
|
||||||
|
// List of instructions to remove at end of pass
|
||||||
|
std::vector<Instruction *> KillList;
|
||||||
|
|
||||||
|
std::map<BasicBlock*,
|
||||||
|
std::vector<PHINode*> > NewPhiNodes; // the PhiNodes we're adding
|
||||||
|
|
||||||
|
public:
|
||||||
|
PromoteMem2Reg(const std::vector<AllocaInst*> &A, DominanceFrontier &df)
|
||||||
|
:Allocas(A), DF(df) {}
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RenamePass(BasicBlock *BB, BasicBlock *Pred,
|
||||||
|
std::vector<Value*> &IncVals,
|
||||||
|
std::set<BasicBlock*> &Visited);
|
||||||
|
bool QueuePhiNode(BasicBlock *BB, unsigned AllocaIdx);
|
||||||
|
};
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
void PromoteMem2Reg::run() {
|
||||||
bool PromotePass::runOnFunction(Function &F) {
|
|
||||||
// Calculate the set of safe allocas
|
|
||||||
FindSafeAllocas(F);
|
|
||||||
|
|
||||||
// If there is nothing to do, bail out...
|
// If there is nothing to do, bail out...
|
||||||
if (Allocas.empty()) return false;
|
if (Allocas.empty()) return;
|
||||||
|
|
||||||
|
Function &F = *DF.getRoot()->getParent();
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = Allocas.size(); i != e; ++i) {
|
||||||
|
assert(isAllocaPromotable(Allocas[i]) &&
|
||||||
|
"Cannot promote non-promotable alloca!");
|
||||||
|
assert(Allocas[i]->getParent()->getParent() == &F &&
|
||||||
|
"All allocas should be in the same function, which is same as DF!");
|
||||||
|
AllocaLookup[Allocas[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Add each alloca to the KillList. Note: KillList is destroyed MOST recently
|
// Add each alloca to the KillList. Note: KillList is destroyed MOST recently
|
||||||
// added to least recently.
|
// added to least recently.
|
||||||
@ -128,9 +105,6 @@ bool PromotePass::runOnFunction(Function &F) {
|
|||||||
WriteSets[i].push_back(SI->getParent());
|
WriteSets[i].push_back(SI->getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get dominance frontier information...
|
|
||||||
DominanceFrontier &DF = getAnalysis<DominanceFrontier>();
|
|
||||||
|
|
||||||
// Compute the locations where PhiNodes need to be inserted. Look at the
|
// Compute the locations where PhiNodes need to be inserted. Look at the
|
||||||
// dominance frontier of EACH basic-block we have a write in
|
// dominance frontier of EACH basic-block we have a write in
|
||||||
//
|
//
|
||||||
@ -177,22 +151,13 @@ bool PromotePass::runOnFunction(Function &F) {
|
|||||||
|
|
||||||
I->getParent()->getInstList().erase(I);
|
I->getParent()->getInstList().erase(I);
|
||||||
}
|
}
|
||||||
|
|
||||||
NumPromoted += Allocas.size();
|
|
||||||
|
|
||||||
// Purge data structurse so they are available the next iteration...
|
|
||||||
Allocas.clear();
|
|
||||||
AllocaLookup.clear();
|
|
||||||
PhiNodes.clear();
|
|
||||||
NewPhiNodes.clear();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// QueuePhiNode - queues a phi-node to be added to a basic-block for a specific
|
// QueuePhiNode - queues a phi-node to be added to a basic-block for a specific
|
||||||
// Alloca returns true if there wasn't already a phi-node for that variable
|
// Alloca returns true if there wasn't already a phi-node for that variable
|
||||||
//
|
//
|
||||||
bool PromotePass::QueuePhiNode(BasicBlock *BB, unsigned AllocaNo) {
|
bool PromoteMem2Reg::QueuePhiNode(BasicBlock *BB, unsigned AllocaNo) {
|
||||||
// Look up the basic-block in question
|
// Look up the basic-block in question
|
||||||
std::vector<PHINode*> &BBPNs = NewPhiNodes[BB];
|
std::vector<PHINode*> &BBPNs = NewPhiNodes[BB];
|
||||||
if (BBPNs.empty()) BBPNs.resize(Allocas.size());
|
if (BBPNs.empty()) BBPNs.resize(Allocas.size());
|
||||||
@ -210,7 +175,7 @@ bool PromotePass::QueuePhiNode(BasicBlock *BB, unsigned AllocaNo) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PromotePass::RenamePass(BasicBlock *BB, BasicBlock *Pred,
|
void PromoteMem2Reg::RenamePass(BasicBlock *BB, BasicBlock *Pred,
|
||||||
std::vector<Value*> &IncomingVals,
|
std::vector<Value*> &IncomingVals,
|
||||||
std::set<BasicBlock*> &Visited) {
|
std::set<BasicBlock*> &Visited) {
|
||||||
// If this is a BB needing a phi node, lookup/create the phinode for each
|
// If this is a BB needing a phi node, lookup/create the phinode for each
|
||||||
@ -269,9 +234,12 @@ void PromotePass::RenamePass(BasicBlock *BB, BasicBlock *Pred,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// PromoteMemToReg - Promote the specified list of alloca instructions into
|
||||||
// createPromoteMemoryToRegister - Provide an entry point to create this pass.
|
/// scalar registers, inserting PHI nodes as appropriate. This function makes
|
||||||
//
|
/// use of DominanceFrontier information. This function does not modify the CFG
|
||||||
Pass *createPromoteMemoryToRegister() {
|
/// of the function at all. All allocas must be from the same function.
|
||||||
return new PromotePass();
|
///
|
||||||
|
void PromoteMemToReg(const std::vector<AllocaInst*> &Allocas,
|
||||||
|
DominanceFrontier &DF) {
|
||||||
|
PromoteMem2Reg(Allocas, DF).run();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user