[llvm-commits] CVS: poolalloc/lib/PoolAllocate/PoolAllocate.cpp
Chris Lattner
lattner at cs.uiuc.edu
Mon Nov 10 12:10:01 PST 2003
Changes in directory poolalloc/lib/PoolAllocate:
PoolAllocate.cpp updated: 1.37 -> 1.38
---
Log message:
Implement intelligent placement of poolinit/destroy's. This does not yet
elide any poolfree's though.
---
Diffs of the changes: (+182 -31)
Index: poolalloc/lib/PoolAllocate/PoolAllocate.cpp
diff -u poolalloc/lib/PoolAllocate/PoolAllocate.cpp:1.37 poolalloc/lib/PoolAllocate/PoolAllocate.cpp:1.38
--- poolalloc/lib/PoolAllocate/PoolAllocate.cpp:1.37 Sun Nov 9 19:25:28 2003
+++ poolalloc/lib/PoolAllocate/PoolAllocate.cpp Mon Nov 10 12:09:42 2003
@@ -7,15 +7,19 @@
#define DEBUG_TYPE "PoolAllocation"
#include "poolalloc/PoolAllocate.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
+#include "llvm/Analysis/DataStructure.h"
+#include "llvm/Analysis/DSGraph.h"
+#include "llvm/Support/CFG.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "Support/CommandLine.h"
#include "Support/Debug.h"
+#include "Support/DepthFirstIterator.h"
#include "Support/VectorExtras.h"
#include "Support/Statistic.h"
using namespace PA;
@@ -25,7 +29,8 @@
namespace {
Statistic<> NumArgsAdded("poolalloc", "Number of function arguments added");
Statistic<> NumCloned ("poolalloc", "Number of functions cloned");
- Statistic<> NumPools ("poolalloc", "Number of poolinit's inserted");
+ Statistic<> NumPools ("poolalloc", "Number of pools allocated");
+ Statistic<> NumPoolFree ("poolalloc", "Number of poolfree's elided");
const Type *VoidPtrTy;
@@ -38,6 +43,9 @@
RegisterOpt<PoolAllocate>
X("poolalloc", "Pool allocate disjoint data structures");
+
+ cl::opt<bool> DisableInitDestroyOpt("poolalloc-force-simple-pool-init",
+ cl::desc("Always insert poolinit/pooldestroy calls at start and exit of functions"));
}
void PoolAllocate::getAnalysisUsage(AnalysisUsage &AU) const {
@@ -543,7 +551,21 @@
// Create pool construction/destruction code
if (!NodesToPA.empty())
- InitializeAndDestroyPools(NewF, NodesToPA, FI.PoolDescriptors);
+ InitializeAndDestroyPools(NewF, NodesToPA, FI.PoolDescriptors,
+ PoolUses, PoolFrees);
+}
+
+template<class IteratorTy>
+static void AllOrNoneInSet(IteratorTy S, IteratorTy E,
+ std::set<BasicBlock*> &Blocks, bool &AllIn,
+ bool &NoneIn) {
+ AllIn = true;
+ NoneIn = true;
+ for (; S != E; ++S)
+ if (Blocks.count(*S))
+ NoneIn = false;
+ else
+ AllIn = false;
}
/// InitializeAndDestroyPools - This inserts calls to poolinit and pooldestroy
@@ -551,41 +573,170 @@
///
void PoolAllocate::InitializeAndDestroyPools(Function &F,
const std::vector<DSNode*> &NodesToPA,
- std::map<DSNode*, Value*> &PoolDescriptors) {
+ std::map<DSNode*, Value*> &PoolDescriptors,
+ std::set<std::pair<AllocaInst*, Instruction*> > &PoolUses,
+ std::set<std::pair<AllocaInst*, CallInst*> > &PoolFrees) {
TargetData &TD = getAnalysis<TargetData>();
-
- // Insert poolinit calls after all of the allocas...
- Instruction *InsertPoint;
- for (BasicBlock::iterator I = F.front().begin();
- isa<AllocaInst>(InsertPoint = I); ++I)
- /*empty*/;
+ std::vector<Instruction*> PoolInitPoints;
+ std::vector<Instruction*> PoolDestroyPoints;
+
+ if (DisableInitDestroyOpt) {
+ // Insert poolinit calls after all of the allocas...
+ Instruction *InsertPoint;
+ for (BasicBlock::iterator I = F.front().begin();
+ isa<AllocaInst>(InsertPoint = I); ++I)
+ /*empty*/;
+ PoolInitPoints.push_back(InsertPoint);
+
+ for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
+ if (isa<ReturnInst>(BB->getTerminator()))
+ PoolDestroyPoints.push_back(BB->getTerminator());
+ }
// Insert all of the poolalloc calls in the start of the function.
for (unsigned i = 0, e = NodesToPA.size(); i != e; ++i) {
DSNode *Node = NodesToPA[i];
- // Create a new alloca instruction for the pool...
- Value *PD = PoolDescriptors[Node];
- Value *ElSize;
+ Value *ElSize =
+ ConstantUInt::get(Type::UIntTy, Node->getType()->isSized() ?
+ TD.getTypeSize(Node->getType()) : 4);
- // Void types in DS graph are never used
- if (Node->getType() != Type::VoidTy) {
- ElSize = ConstantUInt::get(Type::UIntTy, TD.getTypeSize(Node->getType()));
- } else {
- ElSize = ConstantUInt::get(Type::UIntTy, 1);
- }
+ AllocaInst *PD = cast<AllocaInst>(PoolDescriptors[Node]);
+
+ // Convert the PoolUses/PoolFrees sets into something specific to this pool.
+ std::set<BasicBlock*> UsingBlocks;
+ std::set<BasicBlock*> FreeingBlocks;
- // Insert the call to initialize the pool...
- new CallInst(PoolInit, make_vector(PD, ElSize, 0), "", InsertPoint);
- }
+ std::set<std::pair<AllocaInst*, Instruction*> >::iterator PUI =
+ PoolUses.lower_bound(std::make_pair(PD, (Instruction*)0));
+ if (PUI != PoolUses.end() && PUI->first < PD) ++PUI;
+ for (; PUI != PoolUses.end() && PUI->first == PD; ++PUI)
+ UsingBlocks.insert(PUI->second->getParent());
+
+ std::set<std::pair<AllocaInst*, CallInst*> >::iterator PFI =
+ PoolFrees.lower_bound(std::make_pair(PD, (CallInst*)0));
+ if (PFI != PoolFrees.end() && PFI->first < PD) ++PFI;
+ for (; PFI != PoolFrees.end() && PFI->first == PD; ++PFI)
+ FreeingBlocks.insert(PUI->second->getParent());
+
+ // To calculate all of the basic blocks which require the pool to be
+ // initialized before, do a depth first search on the CFG from the using
+ // blocks.
+ std::set<BasicBlock*> InitializedBefore;
+ std::set<BasicBlock*> DestroyedAfter;
+ for (std::set<BasicBlock*>::iterator I = UsingBlocks.begin(),
+ E = UsingBlocks.end(); I != E; ++I) {
+ for (df_ext_iterator<BasicBlock*, std::set<BasicBlock*> >
+ DI = df_ext_begin(*I, InitializedBefore),
+ DE = df_ext_end(*I, InitializedBefore); DI != DE; ++DI)
+ /* empty */;
+
+ for (idf_ext_iterator<BasicBlock*, std::set<BasicBlock*> >
+ DI = idf_ext_begin(*I, DestroyedAfter),
+ DE = idf_ext_end(*I, DestroyedAfter); DI != DE; ++DI)
+ /* empty */;
+ }
- // Loop over all of the return nodes in the CFG...
- for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
- if (isa<ReturnInst>(BB->getTerminator()))
- for (unsigned i = 0, e = NodesToPA.size(); i != e; ++i)
- // Insert the pooldestroy call for this pool.
- new CallInst(PoolDestroy, make_vector(PoolDescriptors[NodesToPA[i]], 0),
- "", BB->getTerminator());
+ // Now that we have created the sets, intersect them.
+ std::set<BasicBlock*> LiveBlocks;
+ std::set_intersection(InitializedBefore.begin(), InitializedBefore.end(),
+ DestroyedAfter.begin(), DestroyedAfter.end(),
+ std::inserter(LiveBlocks, LiveBlocks.end()));
+ InitializedBefore.clear();
+ DestroyedAfter.clear();
+
+ // Keep track of the blocks we have inserted poolinit/destroy in
+ std::set<BasicBlock*> PoolInitInsertedBlocks, PoolDestroyInsertedBlocks;
+
+ std::cerr << "POOL: " << PD->getName() << " information:\n";
+ std::cerr << " Live in blocks: ";
+ for (std::set<BasicBlock*>::iterator I = LiveBlocks.begin(),
+ E = LiveBlocks.end(); I != E; ++I) {
+ BasicBlock *BB = *I;
+ TerminatorInst *Term = BB->getTerminator();
+ std::cerr << BB->getName() << " ";
+
+ // Check the predecessors of this block. If any preds are not in the
+ // set, or if there are no preds, insert a pool init.
+ bool AllIn, NoneIn;
+ AllOrNoneInSet(pred_begin(BB), pred_end(BB), LiveBlocks, AllIn, NoneIn);
+
+ if (NoneIn) {
+ if (!PoolInitInsertedBlocks.count(BB)) {
+ BasicBlock::iterator It = BB->begin();
+ // Move through all of the instructions not in the pool
+ while (!PoolUses.count(std::make_pair(PD, It)))
+ ++It; // Advance past non-users
+ PoolInitPoints.push_back(It);
+ PoolInitInsertedBlocks.insert(BB);
+ }
+ } else if (!AllIn) {
+ TryAgainPred:
+ for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
+ if (!LiveBlocks.count(*PI) && !PoolInitInsertedBlocks.count(*PI)) {
+ if (SplitCriticalEdge(BB, PI))
+ // If the critical edge was split, *PI was invalidated
+ goto TryAgainPred;
+
+ // Insert at the end of the predecessor, before the terminator.
+ PoolInitPoints.push_back((*PI)->getTerminator());
+ PoolInitInsertedBlocks.insert(*PI);
+ }
+ }
+ // Check the successors of this block. If some succs are not in the set,
+ // insert destroys on those successor edges. If all succs are not in the
+ // set, insert a destroy in this block.
+ AllOrNoneInSet(succ_begin(BB), succ_end(BB), LiveBlocks, AllIn, NoneIn);
+
+ if (NoneIn) {
+ // Insert before the terminator.
+ if (!PoolDestroyInsertedBlocks.count(BB)) {
+ BasicBlock::iterator It = Term;
+
+ // Rewind to the first using insruction
+ while (!PoolUses.count(std::make_pair(PD, It)))
+ --It;
+
+ // Insert after the first using instruction
+ PoolDestroyPoints.push_back(++It);
+ PoolDestroyInsertedBlocks.insert(BB);
+ }
+ } else if (!AllIn) {
+ for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI)
+ if (!LiveBlocks.count(*SI) && !PoolDestroyInsertedBlocks.count(*SI)) {
+ // If this edge is critical, split it.
+ SplitCriticalEdge(BB, SI);
+
+ // Insert at entry to the successor, but after any PHI nodes.
+ BasicBlock::iterator It = (*SI)->begin();
+ while (isa<PHINode>(It)) ++It;
+ PoolDestroyPoints.push_back(It);
+ PoolDestroyInsertedBlocks.insert(*SI);
+ }
+ }
+ }
+ std::cerr << "\n Init in blocks: ";
+
+ // Insert the calls to initialize the pool...
+ for (unsigned i = 0, e = PoolInitPoints.size(); i != e; ++i) {
+ new CallInst(PoolInit, make_vector((Value*)PD, ElSize, 0), "",
+ PoolInitPoints[i]);
+ std::cerr << PoolInitPoints[i]->getParent()->getName() << " ";
+ }
+ PoolInitPoints.clear();
+
+ std::cerr << "\n Destroy in blocks: ";
+
+ // Loop over all of the places to insert pooldestroy's...
+ for (unsigned i = 0, e = PoolDestroyPoints.size(); i != e; ++i) {
+ // Insert the pooldestroy call for this pool.
+ new CallInst(PoolDestroy, make_vector((Value*)PD, 0), "",
+ PoolDestroyPoints[i]);
+ std::cerr << PoolDestroyPoints[i]->getParent()->getName() << " ";
+ }
+ PoolDestroyPoints.clear();
+ std::cerr << "\n\n";
+ }
}
More information about the llvm-commits
mailing list