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:
Chris Lattner 2003-02-22 23:57:48 +00:00
parent 74aa1f8c03
commit 2e4c1c8640
2 changed files with 121 additions and 94 deletions

View 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();
}

View File

@ -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();
} }