From: Chris Lattner Date: Mon, 1 Sep 2003 03:14:56 +0000 (+0000) Subject: Change the RaiseAllocations pass to be a Pass instead of a BasicBlock pass. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=2dbfa03fd8554d9045a95d3297a5d4164bddf128;p=oota-llvm.git Change the RaiseAllocations pass to be a Pass instead of a BasicBlock pass. This makes it more efficient: it doesn't have to scan the whole program, so it performs work proportional to the number of malloc/free calls in the program, not the size of the program. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8280 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/IPO/RaiseAllocations.cpp b/lib/Transforms/IPO/RaiseAllocations.cpp index a1ad2c2918f..62355be8780 100644 --- a/lib/Transforms/IPO/RaiseAllocations.cpp +++ b/lib/Transforms/IPO/RaiseAllocations.cpp @@ -5,13 +5,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/IPO.h" #include "llvm/Module.h" #include "llvm/DerivedTypes.h" #include "llvm/iMemory.h" #include "llvm/iOther.h" #include "llvm/Pass.h" +#include "llvm/Support/CallSite.h" #include "Support/Statistic.h" namespace { @@ -20,7 +20,7 @@ namespace { // RaiseAllocations - Turn %malloc and %free calls into the appropriate // instruction. // - class RaiseAllocations : public BasicBlockPass { + class RaiseAllocations : public Pass { Function *MallocFunc; // Functions in the module we are processing Function *FreeFunc; // Initialized by doPassInitializationVirt public: @@ -29,12 +29,11 @@ namespace { // doPassInitialization - For the raise allocations pass, this finds a // declaration for malloc and free if they exist. // - bool doInitialization(Module &M); + void doInitialization(Module &M); - // runOnBasicBlock - This method does the actual work of converting - // instructions over, assuming that the pass has already been initialized. + // run - This method does the actual work of converting instructions over. // - bool runOnBasicBlock(BasicBlock &BB); + bool run(Module &M); }; RegisterOpt @@ -48,15 +47,15 @@ Pass *createRaiseAllocationsPass() { } -bool RaiseAllocations::doInitialization(Module &M) { - // If the module has a symbol table, they might be referring to the malloc - // and free functions. If this is the case, grab the method pointers that - // the module is using. - // - // Lookup %malloc and %free in the symbol table, for later use. If they - // don't exist, or are not external, we do not worry about converting calls - // to that function into the appropriate instruction. - // +// If the module has a symbol table, they might be referring to the malloc and +// free functions. If this is the case, grab the method pointers that the +// module is using. +// +// Lookup %malloc and %free in the symbol table, for later use. If they don't +// exist, or are not external, we do not worry about converting calls to that +// function into the appropriate instruction. +// +void RaiseAllocations::doInitialization(Module &M) { const FunctionType *MallocType = // Get the type for malloc FunctionType::get(PointerType::get(Type::SByteTy), std::vector(1, Type::ULongTy), false); @@ -100,52 +99,74 @@ bool RaiseAllocations::doInitialization(Module &M) { FreeFunc = M.getFunction("free", FreeType); } - // Don't mess with locally defined versions of these functions... if (MallocFunc && !MallocFunc->isExternal()) MallocFunc = 0; if (FreeFunc && !FreeFunc->isExternal()) FreeFunc = 0; - return false; } -// runOnBasicBlock - Process a basic block, fixing it up... +// run - Transform calls into instructions... // -bool RaiseAllocations::runOnBasicBlock(BasicBlock &BB) { +bool RaiseAllocations::run(Module &M) { + // Find the malloc/free prototypes... + doInitialization(M); + bool Changed = false; - BasicBlock::InstListType &BIL = BB.getInstList(); - - for (BasicBlock::iterator BI = BB.begin(); BI != BB.end(); ++BI) { - Instruction *I = BI; - - if (CallInst *CI = dyn_cast(I)) { - if (CI->getCalledValue() == MallocFunc) { // Replace call to malloc? - Value *Source = CI->getOperand(1); - - // If no prototype was provided for malloc, we may need to cast the - // source size. - if (Source->getType() != Type::UIntTy) - Source = new CastInst(Source, Type::UIntTy, "MallocAmtCast", BI); - - std::string Name(CI->getName()); CI->setName(""); - BI = new MallocInst(Type::SByteTy, Source, Name, BI); - CI->replaceAllUsesWith(BI); - BIL.erase(I); - Changed = true; - ++NumRaised; - } else if (CI->getCalledValue() == FreeFunc) { // Replace call to free? - // If no prototype was provided for free, we may need to cast the - // source pointer. This should be really uncommon, but it's necessary - // just in case we are dealing with wierd code like this: - // free((long)ptr); - // - Value *Source = CI->getOperand(1); - if (!isa(Source->getType())) - Source = new CastInst(Source, PointerType::get(Type::SByteTy), - "FreePtrCast", BI); - BI = new FreeInst(Source, BI); - BIL.erase(I); - Changed = true; - ++NumRaised; + + // First, process all of the malloc calls... + if (MallocFunc) { + std::vector Users(MallocFunc->use_begin(), MallocFunc->use_end()); + while (!Users.empty()) { + if (Instruction *I = dyn_cast(Users.back())) { + CallSite CS = CallSite::get(I); + if (CS.getInstruction() && CS.getCalledFunction() == MallocFunc && + CS.arg_begin() != CS.arg_end()) { + Value *Source = *CS.arg_begin(); + + // If no prototype was provided for malloc, we may need to cast the + // source size. + if (Source->getType() != Type::UIntTy) + Source = new CastInst(Source, Type::UIntTy, "MallocAmtCast", I); + + std::string Name(I->getName()); I->setName(""); + MallocInst *MI = new MallocInst(Type::SByteTy, Source, Name, I); + I->replaceAllUsesWith(MI); + MI->getParent()->getInstList().erase(I); + Changed = true; + ++NumRaised; + } + } + + Users.pop_back(); + } + } + + // Next, process all free calls... + if (FreeFunc) { + std::vector Users(FreeFunc->use_begin(), FreeFunc->use_end()); + + while (!Users.empty()) { + if (Instruction *I = dyn_cast(Users.back())) { + CallSite CS = CallSite::get(I); + if (CS.getInstruction() && CS.getCalledFunction() == FreeFunc && + CS.arg_begin() != CS.arg_end()) { + + // If no prototype was provided for free, we may need to cast the + // source pointer. This should be really uncommon, but it's necessary + // just in case we are dealing with wierd code like this: + // free((long)ptr); + // + Value *Source = *CS.arg_begin(); + if (!isa(Source->getType())) + Source = new CastInst(Source, PointerType::get(Type::SByteTy), + "FreePtrCast", I); + new FreeInst(Source, I); + I->getParent()->getInstList().erase(I); + Changed = true; + ++NumRaised; + } } + + Users.pop_back(); } }