diff options
author | Chris Lattner <sabre@nondot.org> | 2004-02-03 22:34:12 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2004-02-03 22:34:12 +0000 |
commit | e47f78ed124b35dbd03df9b1471bbc3c7b88898f (patch) | |
tree | c7c635f7460a5b70dba9b405c3af20fa4cf9238d /lib/Transforms/Utils/PromoteMemoryToRegister.cpp | |
parent | 7fecc2e5e28fa223b16280a5e434d7d0e03e9c52 (diff) |
Bunch up all locally used allocas by the block they are allocated in, and
process them all as a group. This speeds up SRoA/mem2reg from 28.46s to
0.62s on the testcase from PR209.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11100 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Utils/PromoteMemoryToRegister.cpp')
-rw-r--r-- | lib/Transforms/Utils/PromoteMemoryToRegister.cpp | 87 |
1 files changed, 74 insertions, 13 deletions
diff --git a/lib/Transforms/Utils/PromoteMemoryToRegister.cpp b/lib/Transforms/Utils/PromoteMemoryToRegister.cpp index c1a13a220e..fd320daae5 100644 --- a/lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ b/lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -110,7 +110,9 @@ namespace { private: void MarkDominatingPHILive(BasicBlock *BB, unsigned AllocaNum, std::set<PHINode*> &DeadPHINodes); - void PromoteLocallyUsedAlloca(AllocaInst *AI); + void PromoteLocallyUsedAlloca(BasicBlock *BB, AllocaInst *AI); + void PromoteLocallyUsedAllocas(BasicBlock *BB, + const std::vector<AllocaInst*> &AIs); void RenamePass(BasicBlock *BB, BasicBlock *Pred, std::vector<Value*> &IncVals); @@ -122,6 +124,13 @@ namespace { void PromoteMem2Reg::run() { Function &F = *DF.getRoot()->getParent(); + // LocallyUsedAllocas - Keep track of all of the alloca instructions which are + // only used in a single basic block. These instructions can be efficiently + // promoted by performing a single linear scan over that one block. Since + // individual basic blocks are sometimes large, we group together all allocas + // that are live in a single basic block by the basic block they are live in. + std::map<BasicBlock*, std::vector<AllocaInst*> > LocallyUsedAllocas; + for (unsigned AllocaNum = 0; AllocaNum != Allocas.size(); ++AllocaNum) { AllocaInst *AI = Allocas[AllocaNum]; @@ -207,9 +216,9 @@ void PromoteMem2Reg::run() { // If the alloca is only read and written in one basic block, just perform a // linear sweep over the block to eliminate it. if (OnlyUsedInOneBlock) { - PromoteLocallyUsedAlloca(AI); + LocallyUsedAllocas[OnlyBlock].push_back(AI); - // Remove the alloca from the Allocas list, since it has been processed + // Remove the alloca from the Allocas list, since it will be processed. Allocas[AllocaNum] = Allocas.back(); Allocas.pop_back(); --AllocaNum; @@ -272,6 +281,20 @@ void PromoteMem2Reg::run() { AllocaLookup[Allocas[AllocaNum]] = AllocaNum; } + // Process all allocas which are only used in a single basic block. + for (std::map<BasicBlock*, std::vector<AllocaInst*> >::iterator I = + LocallyUsedAllocas.begin(), E = LocallyUsedAllocas.end(); I != E; ++I){ + const std::vector<AllocaInst*> &Allocas = I->second; + assert(!Allocas.empty() && "empty alloca list??"); + + // It's common for there to only be one alloca in the list. Handle it + // efficiently. + if (Allocas.size() == 1) + PromoteLocallyUsedAlloca(I->first, Allocas[0]); + else + PromoteLocallyUsedAllocas(I->first, Allocas); + } + if (Allocas.empty()) return; // All of the allocas must have been trivial! @@ -393,15 +416,13 @@ void PromoteMem2Reg::MarkDominatingPHILive(BasicBlock *BB, unsigned AllocaNum, } } -// PromoteLocallyUsedAlloca - Many allocas are only used within a single basic -// block. If this is the case, avoid traversing the CFG and inserting a lot of -// potentially useless PHI nodes by just performing a single linear pass over -// the basic block using the Alloca. -// -void PromoteMem2Reg::PromoteLocallyUsedAlloca(AllocaInst *AI) { +/// PromoteLocallyUsedAlloca - Many allocas are only used within a single basic +/// block. If this is the case, avoid traversing the CFG and inserting a lot of +/// potentially useless PHI nodes by just performing a single linear pass over +/// the basic block using the Alloca. +/// +void PromoteMem2Reg::PromoteLocallyUsedAlloca(BasicBlock *BB, AllocaInst *AI) { assert(!AI->use_empty() && "There are no uses of the alloca!"); - BasicBlock *BB = cast<Instruction>(AI->use_back())->getParent(); - // Handle degenerate cases quickly. if (AI->hasOneUse()) { @@ -422,13 +443,13 @@ void PromoteMem2Reg::PromoteLocallyUsedAlloca(AllocaInst *AI) { Instruction *Inst = I++; if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { if (LI->getOperand(0) == AI) { - // Loads just return the "current value"... + // Loads just returns the "current value"... LI->replaceAllUsesWith(CurVal); BB->getInstList().erase(LI); } } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { if (SI->getOperand(1) == AI) { - // Loads just update the "current value"... + // Store updates the "current value"... CurVal = SI->getOperand(0); BB->getInstList().erase(SI); } @@ -442,6 +463,46 @@ void PromoteMem2Reg::PromoteLocallyUsedAlloca(AllocaInst *AI) { AI->getParent()->getInstList().erase(AI); } +/// PromoteLocallyUsedAllocas - This method is just like +/// PromoteLocallyUsedAlloca, except that it processes multiple alloca +/// instructions in parallel. This is important in cases where we have large +/// basic blocks, as we don't want to rescan the entire basic block for each +/// alloca which is locally used in it (which might be a lot). +void PromoteMem2Reg:: +PromoteLocallyUsedAllocas(BasicBlock *BB, const std::vector<AllocaInst*> &AIs) { + std::map<AllocaInst*, Value*> CurValues; + for (unsigned i = 0, e = AIs.size(); i != e; ++i) + CurValues[AIs[i]] = 0; // Insert with null value + + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { + Instruction *Inst = I++; + if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { + // Is this a load of an alloca we are tracking? + if (AllocaInst *AI = dyn_cast<AllocaInst>(LI->getOperand(0))) { + std::map<AllocaInst*, Value*>::iterator AIt = CurValues.find(AI); + if (AIt != CurValues.end()) { + // Loads just returns the "current value"... + if (AIt->second == 0) // Uninitialized value?? + AIt->second =Constant::getNullValue(AIt->first->getAllocatedType()); + LI->replaceAllUsesWith(AIt->second); + BB->getInstList().erase(LI); + } + } + } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { + if (AllocaInst *AI = dyn_cast<AllocaInst>(SI->getOperand(1))) { + std::map<AllocaInst*, Value*>::iterator AIt = CurValues.find(AI); + if (AIt != CurValues.end()) { + // Store updates the "current value"... + AIt->second = SI->getOperand(0); + BB->getInstList().erase(SI); + } + } + } + } +} + + + // 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 // |