[llvm-commits] CVS: poolalloc/lib/PoolAllocate/PoolOptimize.cpp

Chris Lattner lattner at cs.uiuc.edu
Wed Nov 10 15:41:30 PST 2004



Changes in directory poolalloc/lib/PoolAllocate:

PoolOptimize.cpp added (r1.1)

---
Log message:

This little pass improves pool allocated code in several little ways, including
converting pools to use a bump pointer if there are no deallocations to it.


---
Diffs of the changes:  (+218 -0)

Index: poolalloc/lib/PoolAllocate/PoolOptimize.cpp
diff -c /dev/null poolalloc/lib/PoolAllocate/PoolOptimize.cpp:1.1
*** /dev/null	Wed Nov 10 17:41:30 2004
--- poolalloc/lib/PoolAllocate/PoolOptimize.cpp	Wed Nov 10 17:40:49 2004
***************
*** 0 ****
--- 1,218 ----
+ //===-- PoolOptimize.cpp - Optimize pool allocated program ----------------===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by the LLVM research group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // This simple pass optimizes a program that has been through pool allocation.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "llvm/Constants.h"
+ #include "llvm/DerivedTypes.h"
+ #include "llvm/Instructions.h"
+ #include "llvm/Pass.h"
+ #include "llvm/Module.h"
+ #include "llvm/ADT/Statistic.h"
+ using namespace llvm;
+ 
+ namespace {
+   Statistic<> NumBumpPtr("poolalloc", "Number of bump pointer pools");
+ 
+   struct PoolOptimize : public ModulePass {
+     bool runOnModule(Module &M);
+   };
+ 
+   RegisterOpt<PoolOptimize>
+   X("pooloptimize", "Optimize a pool allocated program");
+ }
+ 
+ static void getCallsOf(Function *F, std::vector<CallInst*> &Calls) {
+   Calls.clear();
+   for (Value::use_iterator UI = F->use_begin(), E = F->use_end(); UI != E; ++UI)
+     Calls.push_back(cast<CallInst>(*UI));
+ }
+ 
+ bool PoolOptimize::runOnModule(Module &M) {
+   const Type *VoidPtrTy = PointerType::get(Type::SByteTy);
+   const Type *PoolDescPtrTy = PointerType::get(ArrayType::get(VoidPtrTy, 16));
+ 
+ 
+   // Get poolinit function.
+   Function *PoolInit = M.getOrInsertFunction("poolinit", Type::VoidTy,
+                                              PoolDescPtrTy, Type::UIntTy,
+                                              Type::UIntTy, 0);
+ 
+   // Get pooldestroy function.
+   Function *PoolDestroy = M.getOrInsertFunction("pooldestroy", Type::VoidTy,
+                                                 PoolDescPtrTy, 0);
+   
+   // The poolalloc function.
+   Function *PoolAlloc = M.getOrInsertFunction("poolalloc", 
+                                               VoidPtrTy, PoolDescPtrTy,
+                                               Type::UIntTy, 0);
+   
+   // The poolrealloc function.
+   Function *PoolRealloc = M.getOrInsertFunction("poolrealloc",
+                                                 VoidPtrTy, PoolDescPtrTy,
+                                                 VoidPtrTy, Type::UIntTy, 0);
+ 
+   // Get the poolfree function.
+   Function *PoolFree = M.getOrInsertFunction("poolfree", Type::VoidTy,
+                                              PoolDescPtrTy, VoidPtrTy, 0);  
+ 
+ 
+   // Get poolinit_bp function.
+   Function *PoolInitBP = M.getOrInsertFunction("poolinit_bp", Type::VoidTy,
+                                                PoolDescPtrTy, Type::UIntTy, 0);
+   
+   // Get pooldestroy_bp function.
+   Function *PoolDestroyBP = M.getOrInsertFunction("pooldestroy_bp",Type::VoidTy,
+                                                  PoolDescPtrTy, 0);
+   
+   // The poolalloc_bp function.
+   Function *PoolAllocBP = M.getOrInsertFunction("poolalloc_bp", 
+                                                 VoidPtrTy, PoolDescPtrTy,
+                                                 Type::UIntTy, 0);
+ 
+   Function *Realloc = M.getOrInsertFunction("realloc",
+                                             VoidPtrTy, VoidPtrTy, Type::UIntTy,
+                                             0);
+ 
+ 
+   // Optimize poolreallocs
+   std::vector<CallInst*> Calls;
+   getCallsOf(PoolRealloc, Calls);
+   for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
+     CallInst *CI = Calls[i];
+     // poolrealloc(PD, null, X) -> poolalloc(PD, X)
+     if (isa<ConstantPointerNull>(CI->getOperand(2))) {
+       std::vector<Value*> Ops;
+       Ops.push_back(CI->getOperand(1));
+       Ops.push_back(CI->getOperand(3));
+       Value *New = new CallInst(PoolAlloc, Ops, CI->getName(), CI);
+       CI->replaceAllUsesWith(New);
+       CI->eraseFromParent();
+     } else if (isa<Constant>(CI->getOperand(3)) && 
+                cast<Constant>(CI->getOperand(3))->isNullValue()) {
+       // poolrealloc(PD, X, 0) -> poolfree(PD, X)
+       std::vector<Value*> Ops;
+       Ops.push_back(CI->getOperand(1));
+       Ops.push_back(CI->getOperand(2));
+       new CallInst(PoolFree, Ops, "", CI);
+       CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
+       CI->eraseFromParent();
+     } else if (isa<ConstantPointerNull>(CI->getOperand(1))) {
+       // poolrealloc(null, X, Y) -> realloc(X, Y)
+       std::vector<Value*> Ops;
+       Ops.push_back(CI->getOperand(2));
+       Ops.push_back(CI->getOperand(3));
+       Value *New = new CallInst(Realloc, Ops, CI->getName(), CI);
+       CI->replaceAllUsesWith(New);
+       CI->eraseFromParent();
+     }
+   }
+ 
+   // Optimize poolallocs
+   getCallsOf(PoolAlloc, Calls);
+   for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
+     CallInst *CI = Calls[i];
+     // poolalloc(null, X) -> malloc(X)
+     if (isa<Constant>(CI->getOperand(1)) && 
+         cast<Constant>(CI->getOperand(1))->isNullValue()) {
+       Value *New = new MallocInst(Type::SByteTy, CI->getOperand(2),
+                                   CI->getName(), CI);
+       CI->replaceAllUsesWith(New);
+       CI->eraseFromParent();
+     }
+   }
+ 
+   // Optimize poolfrees
+   getCallsOf(PoolFree, Calls);
+   for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
+     CallInst *CI = Calls[i];
+     // poolfree(PD, null) -> noop
+     if (isa<ConstantPointerNull>(CI->getOperand(2)))
+       CI->eraseFromParent();
+     else if (isa<ConstantPointerNull>(CI->getOperand(1))) {
+       // poolfree(null, Ptr) -> free(Ptr)
+       new FreeInst(CI->getOperand(2), CI);
+       CI->eraseFromParent();
+     }
+   }
+       
+   // Transform pools that only have poolinit/destroy/allocate uses into
+   // bump-pointer pools.  Also, delete pools that are unused.  Find pools by
+   // looking for pool inits in the program.
+   getCallsOf(PoolInit, Calls);
+   std::set<Value*> Pools;
+   for (unsigned i = 0, e = Calls.size(); i != e; ++i)
+     Pools.insert(Calls[i]->getOperand(1));
+ 
+   // Loop over all of the pools processing each as we find it.
+   for (std::set<Value*>::iterator PI = Pools.begin(), E = Pools.end();
+        PI != E; ++PI) {
+     bool HasPoolAlloc = false, HasOtherUse = false;
+     Value *PoolDesc = *PI;
+     for (Value::use_iterator UI = PoolDesc->use_begin(),
+            E = PoolDesc->use_end(); UI != E; ++UI) {
+       if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
+         if (CI->getCalledFunction() == PoolInit ||
+             CI->getCalledFunction() == PoolDestroy) {
+           // ignore
+         } else if (CI->getCalledFunction() == PoolAlloc) {
+           HasPoolAlloc = true;
+         } else {
+           HasOtherUse = true;
+           break;
+         }
+       } else {
+         HasOtherUse = true;
+         break;
+       }
+     }
+ 
+     // Can we optimize it?
+     if (!HasOtherUse) {
+       // Yes, if there are uses at all, nuke the pool init, destroy, and the PD.
+       if (!HasPoolAlloc) {
+         while (!PoolDesc->use_empty())
+           cast<Instruction>(PoolDesc->use_back())->eraseFromParent();
+         if (AllocaInst *AI = dyn_cast<AllocaInst>(PoolDesc))
+           AI->eraseFromParent();
+         else
+           cast<GlobalVariable>(PoolDesc)->eraseFromParent();
+       } else {
+         // Convert all of the pool descriptor users to the BumpPtr flavor.
+         std::vector<User*> PDUsers(PoolDesc->use_begin(), PoolDesc->use_end());
+         
+         while (!PDUsers.empty()) {
+           CallInst *CI = cast<CallInst>(PDUsers.back());
+           PDUsers.pop_back();
+           std::vector<Value*> Args;
+           if (CI->getCalledFunction() == PoolAlloc) {
+             Args.assign(CI->op_begin()+1, CI->op_end());
+             Value *New = new CallInst(PoolAllocBP, Args, CI->getName(), CI);
+             CI->replaceAllUsesWith(New);
+             CI->eraseFromParent();
+           } else if (CI->getCalledFunction() == PoolInit) {
+             Args.assign(CI->op_begin()+1, CI->op_end());
+             Args.erase(Args.begin()+1); // Drop the size argument.
+             Value *New = new CallInst(PoolInitBP, Args, "", CI);
+             CI->eraseFromParent();
+           } else {
+             assert(CI->getCalledFunction() == PoolDestroy);
+             Args.assign(CI->op_begin()+1, CI->op_end());
+             Value *New = new CallInst(PoolDestroyBP, Args, "", CI);
+             CI->eraseFromParent();
+           }
+         }
+         ++NumBumpPtr;
+       }
+     }
+   }
+   return true;
+ }





More information about the llvm-commits mailing list