From 66284e063a1e46500acae48bdc0e4a00652021d1 Mon Sep 17 00:00:00 2001 From: Victor Hernandez Date: Sat, 24 Oct 2009 04:23:03 +0000 Subject: [PATCH] Auto-upgrade free instructions to calls to the builtin free function. Update all analysis passes and transforms to treat free calls just like FreeInst. Remove RaiseAllocations and all its tests since FreeInst no longer needs to be raised. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@84987 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/Passes.html | 12 -- include/llvm-c/Transforms/IPO.h | 2 +- include/llvm/Analysis/MallocHelper.h | 11 +- include/llvm/Instructions.h | 3 + include/llvm/LinkAllPasses.h | 1 - include/llvm/Support/StandardPasses.h | 2 - include/llvm/Transforms/IPO.h | 7 - lib/Analysis/IPA/Andersens.cpp | 4 +- lib/Analysis/IPA/GlobalsModRef.cpp | 7 +- lib/Analysis/MallocHelper.cpp | 26 ++++ lib/Analysis/MemoryDependenceAnalysis.cpp | 8 + lib/AsmParser/LLParser.cpp | 7 +- lib/AsmParser/LLParser.h | 2 +- lib/Bitcode/Reader/BitcodeReader.cpp | 3 +- lib/Transforms/IPO/CMakeLists.txt | 1 - lib/Transforms/IPO/GlobalOpt.cpp | 5 +- lib/Transforms/IPO/IPO.cpp | 2 +- lib/Transforms/IPO/RaiseAllocations.cpp | 173 --------------------- lib/Transforms/Scalar/DeadStoreElimination.cpp | 14 +- lib/Transforms/Scalar/InstructionCombining.cpp | 40 +++++ lib/Transforms/Scalar/SCCP.cpp | 5 +- lib/Transforms/Utils/Local.cpp | 3 +- lib/Transforms/Utils/LowerAllocations.cpp | 6 +- lib/VMCore/Instructions.cpp | 45 ++++++ test/Transforms/InstCombine/malloc-free-delete.ll | 6 +- .../RaiseAllocations/2004-11-08-FreeUseCrash.ll | 10 -- .../RaiseAllocations/2007-10-17-InvokeFree.ll | 17 -- .../RaiseAllocations/FreeCastConstantExpr.ll | 11 -- test/Transforms/RaiseAllocations/dg.exp | 3 - utils/findoptdiff | 2 +- 30 files changed, 169 insertions(+), 269 deletions(-) delete mode 100644 lib/Transforms/IPO/RaiseAllocations.cpp delete mode 100644 test/Transforms/RaiseAllocations/2004-11-08-FreeUseCrash.ll delete mode 100644 test/Transforms/RaiseAllocations/2007-10-17-InvokeFree.ll delete mode 100644 test/Transforms/RaiseAllocations/FreeCastConstantExpr.ll delete mode 100644 test/Transforms/RaiseAllocations/dg.exp diff --git a/docs/Passes.html b/docs/Passes.html index bb17bee77c3..36e0419ad28 100644 --- a/docs/Passes.html +++ b/docs/Passes.html @@ -158,7 +158,6 @@ perl -e '$/ = undef; for (split(/\n/, <>)) { s:^ *///? ?::; print "

\n" if ! -memcpyoptOptimize use of memcpy and friends -mergereturnUnify function exit nodes -prune-ehRemove unused exception handling info --raiseallocsRaise allocations from calls to instructions -reassociateReassociate expressions -reg2memDemote all values to stack slots -scalarreplScalar Replacement of Aggregates @@ -1504,17 +1503,6 @@ if (X < 3) {

- Raise allocations from calls to instructions -
-
-

- Converts @malloc and @free calls to malloc and - free instructions. -

-
- - -
Reassociate expressions
diff --git a/include/llvm-c/Transforms/IPO.h b/include/llvm-c/Transforms/IPO.h index 9bc947f4d8a..0a94315f62b 100644 --- a/include/llvm-c/Transforms/IPO.h +++ b/include/llvm-c/Transforms/IPO.h @@ -54,7 +54,7 @@ void LLVMAddLowerSetJmpPass(LLVMPassManagerRef PM); /** See llvm::createPruneEHPass function. */ void LLVMAddPruneEHPass(LLVMPassManagerRef PM); -/** See llvm::createRaiseAllocationsPass function. */ +// FIXME: Remove in LLVM 3.0. void LLVMAddRaiseAllocationsPass(LLVMPassManagerRef PM); /** See llvm::createStripDeadPrototypesPass function. */ diff --git a/include/llvm/Analysis/MallocHelper.h b/include/llvm/Analysis/MallocHelper.h index e0c4d2c9e4a..be307c02aed 100644 --- a/include/llvm/Analysis/MallocHelper.h +++ b/include/llvm/Analysis/MallocHelper.h @@ -27,8 +27,8 @@ class Value; // malloc Call Utility Functions. // -/// isMalloc - Returns true if the the value is either a malloc call or a -/// bitcast of the result of a malloc call +/// isMalloc - Returns true if the value is either a malloc call or a bitcast of +/// the result of a malloc call bool isMalloc(const Value* I); /// extractMallocCall - Returns the corresponding CallInst if the instruction @@ -79,6 +79,13 @@ const Type* getMallocAllocatedType(const CallInst* CI); /// determined. Value* getMallocArraySize(CallInst* CI, LLVMContext &Context, const TargetData* TD); + +//===----------------------------------------------------------------------===// +// free Call Utility Functions. +// + +/// isFreeCall - Returns true if the the value is a call to the builtin free() +bool isFreeCall(const Value* I); } // End llvm namespace diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 9a990e7eb96..f7e7a3dbf99 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -956,6 +956,9 @@ public: const Type *IntPtrTy, const Type *AllocTy, Value *ArraySize = 0, Function* MallocF = 0, const Twine &Name = ""); + /// CreateFree - Generate the IR for a call to the builtin free function. + static void CreateFree(Value* Source, Instruction *InsertBefore); + static Instruction* CreateFree(Value* Source, BasicBlock *InsertAtEnd); ~CallInst(); diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 3342ea89c56..9335976f33a 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -107,7 +107,6 @@ namespace { (void) llvm::createPostDomPrinterPass(); (void) llvm::createPostDomOnlyViewerPass(); (void) llvm::createPostDomViewerPass(); - (void) llvm::createRaiseAllocationsPass(); (void) llvm::createReassociatePass(); (void) llvm::createSCCPPass(); (void) llvm::createScalarReplAggregatesPass(); diff --git a/include/llvm/Support/StandardPasses.h b/include/llvm/Support/StandardPasses.h index c71e6b94fa2..611e7864482 100644 --- a/include/llvm/Support/StandardPasses.h +++ b/include/llvm/Support/StandardPasses.h @@ -96,8 +96,6 @@ namespace llvm { return; } - if (UnitAtATime) - PM->add(createRaiseAllocationsPass()); // call %malloc -> malloc inst PM->add(createCFGSimplificationPass()); // Clean up disgusting code if (UnitAtATime) { PM->add(createGlobalOptimizerPass()); // Optimize out global vars diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h index 9189c430cbb..5e179044229 100644 --- a/include/llvm/Transforms/IPO.h +++ b/include/llvm/Transforms/IPO.h @@ -69,13 +69,6 @@ ModulePass *createGlobalOptimizerPass(); //===----------------------------------------------------------------------===// -/// createRaiseAllocationsPass - Return a new pass that transforms malloc and -/// free function calls into malloc and free instructions. -/// -ModulePass *createRaiseAllocationsPass(); - - -//===----------------------------------------------------------------------===// /// createDeadTypeEliminationPass - Return a new pass that eliminates symbol /// table entries for types that are never used. /// diff --git a/lib/Analysis/IPA/Andersens.cpp b/lib/Analysis/IPA/Andersens.cpp index b5129a7d3ba..e37a9dbb7ac 100644 --- a/lib/Analysis/IPA/Andersens.cpp +++ b/lib/Analysis/IPA/Andersens.cpp @@ -1017,6 +1017,8 @@ bool Andersens::AnalyzeUsesOfFunction(Value *V) { } } else if (GetElementPtrInst *GEP = dyn_cast(*UI)) { if (AnalyzeUsesOfFunction(GEP)) return true; + } else if (isa(*UI) || isFreeCall(*UI)) { + return false; } else if (CallInst *CI = dyn_cast(*UI)) { // Make sure that this is just the function being called, not that it is // passing into the function. @@ -1038,8 +1040,6 @@ bool Andersens::AnalyzeUsesOfFunction(Value *V) { } else if (ICmpInst *ICI = dyn_cast(*UI)) { if (!isa(ICI->getOperand(1))) return true; // Allow comparison against null. - } else if (isa(*UI)) { - return false; } else { return true; } diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index 7949288340a..d83ea48080c 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -240,6 +240,8 @@ bool GlobalsModRef::AnalyzeUsesOfPointer(Value *V, } else if (BitCastInst *BCI = dyn_cast(*UI)) { if (AnalyzeUsesOfPointer(BCI, Readers, Writers, OkayStoreDest)) return true; + } else if (isa(*UI) || isFreeCall(*UI)) { + Writers.push_back(cast(*UI)->getParent()->getParent()); } else if (CallInst *CI = dyn_cast(*UI)) { // Make sure that this is just the function being called, not that it is // passing into the function. @@ -261,8 +263,6 @@ bool GlobalsModRef::AnalyzeUsesOfPointer(Value *V, } else if (ICmpInst *ICI = dyn_cast(*UI)) { if (!isa(ICI->getOperand(1))) return true; // Allow comparison against null. - } else if (FreeInst *F = dyn_cast(*UI)) { - Writers.push_back(F->getParent()->getParent()); } else { return true; } @@ -439,7 +439,8 @@ void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) { if (cast(*II).isVolatile()) // Treat volatile stores as reading memory somewhere. FunctionEffect |= Ref; - } else if (isMalloc(&cast(*II)) || isa(*II)) { + } else if (isMalloc(&cast(*II)) || isa(*II) || + isFreeCall(&cast(*II))) { FunctionEffect |= ModRef; } diff --git a/lib/Analysis/MallocHelper.cpp b/lib/Analysis/MallocHelper.cpp index e7bb41eeec2..511de9d6a51 100644 --- a/lib/Analysis/MallocHelper.cpp +++ b/lib/Analysis/MallocHelper.cpp @@ -263,3 +263,29 @@ Value* llvm::getMallocArraySize(CallInst* CI, LLVMContext &Context, assert(BO && "getMallocArraySize not constant but not multiplication either"); return BO->getOperand(0); } + +/// isFreeCall - Returns true if the the value is a call to the builtin free() +bool llvm::isFreeCall(const Value* I) { + const CallInst *CI = dyn_cast(I); + if (!CI) + return false; + + const Module* M = CI->getParent()->getParent()->getParent(); + Function *FreeFunc = M->getFunction("free"); + + if (CI->getOperand(0) != FreeFunc) + return false; + + // Check free prototype. + // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin + // attribute will exist. + const FunctionType *FTy = FreeFunc->getFunctionType(); + if (FTy->getReturnType() != Type::getVoidTy(M->getContext())) + return false; + if (FTy->getNumParams() != 1) + return false; + if (FTy->param_begin()->get() != Type::getInt8PtrTy(M->getContext())) + return false; + + return true; +} diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index c3aa5bc9306..ce7674003fe 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -118,6 +118,10 @@ getCallSiteDependencyFrom(CallSite CS, bool isReadOnlyCall, // FreeInsts erase the entire structure PointerSize = ~0ULL; + } else if (isFreeCall(Inst)) { + Pointer = Inst->getOperand(0); + // calls to free() erase the entire structure + PointerSize = ~0ULL; } else if (isa(Inst) || isa(Inst)) { // Debug intrinsics don't cause dependences. if (isa(Inst)) continue; @@ -314,6 +318,10 @@ MemDepResult MemoryDependenceAnalysis::getDependency(Instruction *QueryInst) { MemPtr = LI->getPointerOperand(); MemSize = AA->getTypeStoreSize(LI->getType()); } + } else if (isFreeCall(QueryInst)) { + MemPtr = QueryInst->getOperand(0); + // calls to free() erase the entire structure, not just a field. + MemSize = ~0UL; } else if (isa(QueryInst) || isa(QueryInst)) { CallSite QueryCS = CallSite::get(QueryInst); bool isReadOnly = AA->onlyReadsMemory(QueryCS); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 271567bd1e9..52fd2b21e1a 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -2800,7 +2800,7 @@ bool LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, // Memory. case lltok::kw_alloca: return ParseAlloc(Inst, PFS); case lltok::kw_malloc: return ParseAlloc(Inst, PFS, BB, false); - case lltok::kw_free: return ParseFree(Inst, PFS); + case lltok::kw_free: return ParseFree(Inst, PFS, BB); case lltok::kw_load: return ParseLoad(Inst, PFS, false); case lltok::kw_store: return ParseStore(Inst, PFS, false); case lltok::kw_volatile: @@ -3496,12 +3496,13 @@ bool LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS, /// ParseFree /// ::= 'free' TypeAndValue -bool LLParser::ParseFree(Instruction *&Inst, PerFunctionState &PFS) { +bool LLParser::ParseFree(Instruction *&Inst, PerFunctionState &PFS, + BasicBlock* BB) { Value *Val; LocTy Loc; if (ParseTypeAndValue(Val, Loc, PFS)) return true; if (!isa(Val->getType())) return Error(Loc, "operand to free must be a pointer"); - Inst = new FreeInst(Val); + Inst = CallInst::CreateFree(Val, BB); return false; } diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 5dd6a2e7007..b6877bc7c11 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -280,7 +280,7 @@ namespace llvm { bool ParseCall(Instruction *&I, PerFunctionState &PFS, bool isTail); bool ParseAlloc(Instruction *&I, PerFunctionState &PFS, BasicBlock *BB = 0, bool isAlloca = true); - bool ParseFree(Instruction *&I, PerFunctionState &PFS); + bool ParseFree(Instruction *&I, PerFunctionState &PFS, BasicBlock *BB); bool ParseLoad(Instruction *&I, PerFunctionState &PFS, bool isVolatile); bool ParseStore(Instruction *&I, PerFunctionState &PFS, bool isVolatile); bool ParseGetResult(Instruction *&I, PerFunctionState &PFS); diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 3a385cbe382..ffd330c74ec 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2073,7 +2073,8 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum != Record.size()) return Error("Invalid FREE record"); - I = new FreeInst(Op); + if (!CurBB) return Error("Invalid free instruction with no BB"); + I = CallInst::CreateFree(Op, CurBB); InstructionList.push_back(I); break; } diff --git a/lib/Transforms/IPO/CMakeLists.txt b/lib/Transforms/IPO/CMakeLists.txt index 5c288015554..92bef3bb75e 100644 --- a/lib/Transforms/IPO/CMakeLists.txt +++ b/lib/Transforms/IPO/CMakeLists.txt @@ -19,7 +19,6 @@ add_llvm_library(LLVMipo PartialInlining.cpp PartialSpecialization.cpp PruneEH.cpp - RaiseAllocations.cpp StripDeadPrototypes.cpp StripSymbols.cpp StructRetPromotion.cpp diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 9ced2e89a7e..0bc086f432c 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -1364,10 +1364,11 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, OrigBB->getParent()); BasicBlock *NextBlock = BasicBlock::Create(Context, "next", OrigBB->getParent()); - BranchInst::Create(FreeBlock, NextBlock, Cmp, NullPtrBlock); + Instruction *BI = BranchInst::Create(FreeBlock, NextBlock, + Cmp, NullPtrBlock); // Fill in FreeBlock. - new FreeInst(GVVal, FreeBlock); + CallInst::CreateFree(GVVal, BI); new StoreInst(Constant::getNullValue(GVVal->getType()), FieldGlobals[i], FreeBlock); BranchInst::Create(NextBlock, FreeBlock); diff --git a/lib/Transforms/IPO/IPO.cpp b/lib/Transforms/IPO/IPO.cpp index 43066076ca6..83e8624fe09 100644 --- a/lib/Transforms/IPO/IPO.cpp +++ b/lib/Transforms/IPO/IPO.cpp @@ -63,7 +63,7 @@ void LLVMAddPruneEHPass(LLVMPassManagerRef PM) { } void LLVMAddRaiseAllocationsPass(LLVMPassManagerRef PM) { - unwrap(PM)->add(createRaiseAllocationsPass()); + // FIXME: Remove in LLVM 3.0. } void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM) { diff --git a/lib/Transforms/IPO/RaiseAllocations.cpp b/lib/Transforms/IPO/RaiseAllocations.cpp deleted file mode 100644 index deb4405754d..00000000000 --- a/lib/Transforms/IPO/RaiseAllocations.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//===- RaiseAllocations.cpp - Convert @free calls to insts ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the RaiseAllocations pass which convert free calls to free -// instructions. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "raiseallocs" -#include "llvm/Transforms/IPO.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/Instructions.h" -#include "llvm/Pass.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/Compiler.h" -#include "llvm/ADT/Statistic.h" -#include -using namespace llvm; - -STATISTIC(NumRaised, "Number of allocations raised"); - -namespace { - // RaiseAllocations - Turn @free calls into the appropriate - // instruction. - // - class VISIBILITY_HIDDEN RaiseAllocations : public ModulePass { - Function *FreeFunc; // Functions in the module we are processing - // Initialized by doPassInitializationVirt - public: - static char ID; // Pass identification, replacement for typeid - RaiseAllocations() - : ModulePass(&ID), FreeFunc(0) {} - - // doPassInitialization - For the raise allocations pass, this finds a - // declaration for free if it exists. - // - void doInitialization(Module &M); - - // run - This method does the actual work of converting instructions over. - // - bool runOnModule(Module &M); - }; -} // end anonymous namespace - -char RaiseAllocations::ID = 0; -static RegisterPass -X("raiseallocs", "Raise allocations from calls to instructions"); - -// createRaiseAllocationsPass - The interface to this file... -ModulePass *llvm::createRaiseAllocationsPass() { - return new RaiseAllocations(); -} - - -// If the module has a symbol table, they might be referring to the free -// function. If this is the case, grab the method pointers that the module is -// using. -// -// Lookup @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) { - // Get free prototype if it exists! - FreeFunc = M.getFunction("free"); - if (FreeFunc) { - const FunctionType* TyWeHave = FreeFunc->getFunctionType(); - - // Get the expected prototype for void free(i8*) - const FunctionType *Free1Type = - FunctionType::get(Type::getVoidTy(M.getContext()), - std::vector(1, PointerType::getUnqual( - Type::getInt8Ty(M.getContext()))), - false); - - if (TyWeHave != Free1Type) { - // Check to see if the prototype was forgotten, giving us - // void (...) * free - // This handles the common forward declaration of: 'void free();' - const FunctionType* Free2Type = - FunctionType::get(Type::getVoidTy(M.getContext()), true); - - if (TyWeHave != Free2Type) { - // One last try, check to see if we can find free as - // int (...)* free. This handles the case where NOTHING was declared. - const FunctionType* Free3Type = - FunctionType::get(Type::getInt32Ty(M.getContext()), true); - - if (TyWeHave != Free3Type) { - // Give up. - FreeFunc = 0; - } - } - } - } - - // Don't mess with locally defined versions of these functions... - if (FreeFunc && !FreeFunc->isDeclaration()) FreeFunc = 0; -} - -// run - Transform calls into instructions... -// -bool RaiseAllocations::runOnModule(Module &M) { - // Find the free prototype... - doInitialization(M); - - bool Changed = false; - - // Process all free calls... - if (FreeFunc) { - std::vector Users(FreeFunc->use_begin(), FreeFunc->use_end()); - std::vector EqPointers; // Values equal to FreeFunc - - while (!Users.empty()) { - User *U = Users.back(); - Users.pop_back(); - - if (Instruction *I = dyn_cast(U)) { - if (isa(I)) - continue; - CallSite CS = CallSite::get(I); - if (CS.getInstruction() && !CS.arg_empty() && - (CS.getCalledFunction() == FreeFunc || - std::find(EqPointers.begin(), EqPointers.end(), - CS.getCalledValue()) != EqPointers.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 weird code like this: - // free((long)ptr); - // - Value *Source = *CS.arg_begin(); - if (!isa(Source->getType())) - Source = new IntToPtrInst(Source, - Type::getInt8PtrTy(M.getContext()), - "FreePtrCast", I); - new FreeInst(Source, I); - - // If the old instruction was an invoke, add an unconditional branch - // before the invoke, which will become the new terminator. - if (InvokeInst *II = dyn_cast(I)) - BranchInst::Create(II->getNormalDest(), I); - - // Delete the old call site - if (I->getType() != Type::getVoidTy(M.getContext())) - I->replaceAllUsesWith(UndefValue::get(I->getType())); - I->eraseFromParent(); - Changed = true; - ++NumRaised; - } - } else if (GlobalValue *GV = dyn_cast(U)) { - Users.insert(Users.end(), GV->use_begin(), GV->use_end()); - EqPointers.push_back(GV); - } else if (ConstantExpr *CE = dyn_cast(U)) { - if (CE->isCast()) { - Users.insert(Users.end(), CE->use_begin(), CE->use_end()); - EqPointers.push_back(CE); - } - } - } - } - - return Changed; -} diff --git a/lib/Transforms/Scalar/DeadStoreElimination.cpp b/lib/Transforms/Scalar/DeadStoreElimination.cpp index a7b3e7524fa..f55d8b2accb 100644 --- a/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/MallocHelper.h" #include "llvm/Analysis/MemoryDependenceAnalysis.h" #include "llvm/Target/TargetData.h" #include "llvm/Transforms/Utils/Local.h" @@ -49,7 +50,7 @@ namespace { } bool runOnBasicBlock(BasicBlock &BB); - bool handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep); + bool handleFreeWithNonTrivialDependency(Instruction *F, MemDepResult Dep); bool handleEndBlock(BasicBlock &BB); bool RemoveUndeadPointers(Value* Ptr, uint64_t killPointerSize, BasicBlock::iterator& BBI, @@ -88,7 +89,7 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) { Instruction *Inst = BBI++; // If we find a store or a free, get its memory dependence. - if (!isa(Inst) && !isa(Inst)) + if (!isa(Inst) && !isa(Inst) && !isFreeCall(Inst)) continue; // Don't molest volatile stores or do queries that will return "clobber". @@ -103,8 +104,8 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) { if (InstDep.isNonLocal()) continue; // Handle frees whose dependencies are non-trivial. - if (FreeInst *FI = dyn_cast(Inst)) { - MadeChange |= handleFreeWithNonTrivialDependency(FI, InstDep); + if (isa(Inst) || isFreeCall(Inst)) { + MadeChange |= handleFreeWithNonTrivialDependency(Inst, InstDep); continue; } @@ -165,7 +166,7 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) { /// handleFreeWithNonTrivialDependency - Handle frees of entire structures whose /// dependency is a store to a field of that structure. -bool DSE::handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep) { +bool DSE::handleFreeWithNonTrivialDependency(Instruction *F, MemDepResult Dep) { AliasAnalysis &AA = getAnalysis(); StoreInst *Dependency = dyn_cast_or_null(Dep.getInst()); @@ -175,7 +176,8 @@ bool DSE::handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep) { Value *DepPointer = Dependency->getPointerOperand()->getUnderlyingObject(); // Check for aliasing. - if (AA.alias(F->getPointerOperand(), 1, DepPointer, 1) != + Value* FreeVal = isa(F) ? F->getOperand(0) : F->getOperand(1); + if (AA.alias(FreeVal, 1, DepPointer, 1) != AliasAnalysis::MustAlias) return false; diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index 21554c108d6..be4f7757317 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -286,6 +286,7 @@ namespace { Instruction *visitGetElementPtrInst(GetElementPtrInst &GEP); Instruction *visitAllocaInst(AllocaInst &AI); Instruction *visitFreeInst(FreeInst &FI); + Instruction *visitFree(Instruction &FI); Instruction *visitLoadInst(LoadInst &LI); Instruction *visitStoreInst(StoreInst &SI); Instruction *visitBranchInst(BranchInst &BI); @@ -9747,6 +9748,9 @@ Instruction *InstCombiner::SimplifyMemSet(MemSetInst *MI) { /// the heavy lifting. /// Instruction *InstCombiner::visitCallInst(CallInst &CI) { + if (isFreeCall(&CI)) + return visitFree(CI); + // If the caller function is nounwind, mark the call as nounwind, even if the // callee isn't. if (CI.getParent()->getParent()->doesNotThrow() && @@ -11337,6 +11341,42 @@ Instruction *InstCombiner::visitFreeInst(FreeInst &FI) { return 0; } +Instruction *InstCombiner::visitFree(Instruction &FI) { + Value *Op = FI.getOperand(1); + + // free undef -> unreachable. + if (isa(Op)) { + // Insert a new store to null because we cannot modify the CFG here. + new StoreInst(ConstantInt::getTrue(*Context), + UndefValue::get(Type::getInt1PtrTy(*Context)), &FI); + return EraseInstFromFunction(FI); + } + + // If we have 'free null' delete the instruction. This can happen in stl code + // when lots of inlining happens. + if (isa(Op)) + return EraseInstFromFunction(FI); + + // FIXME: Bring back free (gep X, 0,0,0,0) into free(X) transform + + if (isMalloc(Op)) { + if (CallInst* CI = extractMallocCallFromBitCast(Op)) { + if (Op->hasOneUse() && CI->hasOneUse()) { + EraseInstFromFunction(FI); + EraseInstFromFunction(*CI); + return EraseInstFromFunction(*cast(Op)); + } + } else { + // Op is a call to malloc + if (Op->hasOneUse()) { + EraseInstFromFunction(FI); + return EraseInstFromFunction(*cast(Op)); + } + } + } + + return 0; +} /// InstCombineLoadCast - Fold 'load (cast P)' -> cast (load P)' when possible. static Instruction *InstCombineLoadCast(InstCombiner &IC, LoadInst &LI, diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index e3dd54e8bcf..1bb5f4ae7fd 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -30,6 +30,7 @@ #include "llvm/LLVMContext.h" #include "llvm/Pass.h" #include "llvm/Analysis/ConstantFolding.h" +#include "llvm/Analysis/MallocHelper.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Support/CallSite.h" @@ -400,7 +401,9 @@ private: void visitStoreInst (Instruction &I); void visitLoadInst (LoadInst &I); void visitGetElementPtrInst(GetElementPtrInst &I); - void visitCallInst (CallInst &I) { + void visitCallInst (CallInst &I) { + if (isFreeCall(&I)) + return; visitCallSite(CallSite::get(&I)); } void visitInvokeInst (InvokeInst &II) { diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index b62261119c7..940f5a9ec46 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/DebugInfo.h" +#include "llvm/Analysis/MallocHelper.h" #include "llvm/Analysis/ProfileInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/GetElementPtrTypeIterator.h" @@ -59,7 +60,7 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom) { // If we see a free or a call which may write to memory (i.e. which might do // a free) the pointer could be marked invalid. - if (isa(BBI) || + if (isa(BBI) || isFreeCall(BBI) || (isa(BBI) && BBI->mayWriteToMemory() && !isa(BBI))) return false; diff --git a/lib/Transforms/Utils/LowerAllocations.cpp b/lib/Transforms/Utils/LowerAllocations.cpp index 9c9113daa93..f64a30f5e80 100644 --- a/lib/Transforms/Utils/LowerAllocations.cpp +++ b/lib/Transforms/Utils/LowerAllocations.cpp @@ -102,12 +102,8 @@ bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) { // Loop over all of the instructions, looking for free instructions for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) { if (FreeInst *FI = dyn_cast(I)) { - Value *PtrCast = - new BitCastInst(FI->getOperand(0), - Type::getInt8PtrTy(BB.getContext()), "", I); - // Insert a call to the free function... - CallInst::Create(FreeFunc, PtrCast, "", I)->setTailCall(); + CallInst::CreateFree(FI->getOperand(0), I); // Delete the old free instruction I = --BBIL.erase(I); diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 99a28594e6c..60e203a7e0b 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -559,6 +559,51 @@ Instruction *CallInst::CreateMalloc(BasicBlock *InsertAtEnd, ArraySize, MallocF, Name); } +static Instruction* createFree(Value* Source, Instruction *InsertBefore, + BasicBlock *InsertAtEnd) { + assert(((!InsertBefore && InsertAtEnd) || (InsertBefore && !InsertAtEnd)) && + "createFree needs either InsertBefore or InsertAtEnd"); + assert(isa(Source->getType()) && + "Can not free something of nonpointer type!"); + + BasicBlock* BB = InsertBefore ? InsertBefore->getParent() : InsertAtEnd; + Module* M = BB->getParent()->getParent(); + + const Type *VoidTy = Type::getVoidTy(M->getContext()); + const Type *IntPtrTy = Type::getInt8PtrTy(M->getContext()); + // prototype free as "void free(void*)" + Constant *FreeFunc = M->getOrInsertFunction("free", VoidTy, IntPtrTy, NULL); + + CallInst* Result = NULL; + Value *PtrCast = Source; + if (InsertBefore) { + if (Source->getType() != IntPtrTy) + PtrCast = new BitCastInst(Source, IntPtrTy, "", InsertBefore); + Result = CallInst::Create(FreeFunc, PtrCast, "", InsertBefore); + } else { + if (Source->getType() != IntPtrTy) + PtrCast = new BitCastInst(Source, IntPtrTy, "", InsertAtEnd); + Result = CallInst::Create(FreeFunc, PtrCast, ""); + } + Result->setTailCall(); + + return Result; +} + +/// CreateFree - Generate the IR for a call to the builtin free function. +void CallInst::CreateFree(Value* Source, Instruction *InsertBefore) { + createFree(Source, InsertBefore, NULL); +} + +/// CreateFree - Generate the IR for a call to the builtin free function. +/// Note: This function does not add the call to the basic block, that is the +/// responsibility of the caller. +Instruction* CallInst::CreateFree(Value* Source, BasicBlock *InsertAtEnd) { + Instruction* FreeCall = createFree(Source, NULL, InsertAtEnd); + assert(FreeCall && "CreateFree did not create a CallInst"); + return FreeCall; +} + //===----------------------------------------------------------------------===// // InvokeInst Implementation //===----------------------------------------------------------------------===// diff --git a/test/Transforms/InstCombine/malloc-free-delete.ll b/test/Transforms/InstCombine/malloc-free-delete.ll index fd91e447bdd..a4b7496ef40 100644 --- a/test/Transforms/InstCombine/malloc-free-delete.ll +++ b/test/Transforms/InstCombine/malloc-free-delete.ll @@ -1,11 +1,13 @@ -; RUN: opt < %s -instcombine -S | grep {ret i32 0} -; RUN: opt < %s -instcombine -globaldce -S | not grep malloc +; RUN: opt < %s -instcombine -globaldce -S | FileCheck %s ; PR1201 define i32 @main(i32 %argc, i8** %argv) { %c_19 = alloca i8* ; [#uses=2] %malloc_206 = malloc i8, i32 10 ; [#uses=1] +; CHECK-NOT: malloc store i8* %malloc_206, i8** %c_19 %tmp_207 = load i8** %c_19 ; [#uses=1] free i8* %tmp_207 +; CHECK-NOT: free ret i32 0 +; CHECK: ret i32 0 } diff --git a/test/Transforms/RaiseAllocations/2004-11-08-FreeUseCrash.ll b/test/Transforms/RaiseAllocations/2004-11-08-FreeUseCrash.ll deleted file mode 100644 index 75e02e84fac..00000000000 --- a/test/Transforms/RaiseAllocations/2004-11-08-FreeUseCrash.ll +++ /dev/null @@ -1,10 +0,0 @@ -; RUN: opt < %s -raiseallocs -disable-output - -define void @main() { - %tmp.13 = call i32 (...)* @free( i32 32 ) ; [#uses=1] - %tmp.14 = inttoptr i32 %tmp.13 to i32* ; [#uses=0] - ret void -} - -declare i32 @free(...) - diff --git a/test/Transforms/RaiseAllocations/2007-10-17-InvokeFree.ll b/test/Transforms/RaiseAllocations/2007-10-17-InvokeFree.ll deleted file mode 100644 index 675bb3d829f..00000000000 --- a/test/Transforms/RaiseAllocations/2007-10-17-InvokeFree.ll +++ /dev/null @@ -1,17 +0,0 @@ -; RUN: opt < %s -raiseallocs -stats -disable-output |& \ -; RUN: not grep {Number of allocations raised} -define void @foo() { -entry: - %buffer = alloca i16* - %tmp = load i16** %buffer, align 8 - invoke i32(...)* @free(i16* %tmp) - to label %invcont unwind label %unwind -invcont: - br label %finally -unwind: - br label %finally -finally: - ret void -} -declare i32 @free(...) - diff --git a/test/Transforms/RaiseAllocations/FreeCastConstantExpr.ll b/test/Transforms/RaiseAllocations/FreeCastConstantExpr.ll deleted file mode 100644 index 1cf072910a6..00000000000 --- a/test/Transforms/RaiseAllocations/FreeCastConstantExpr.ll +++ /dev/null @@ -1,11 +0,0 @@ -; This situation can occur due to the funcresolve pass. -; -; RUN: opt < %s -raiseallocs -S | not grep call - -declare void @free(i8*) - -define void @test(i32* %P) { - call void bitcast (void (i8*)* @free to void (i32*)*)( i32* %P ) - ret void -} - diff --git a/test/Transforms/RaiseAllocations/dg.exp b/test/Transforms/RaiseAllocations/dg.exp deleted file mode 100644 index f2005891a59..00000000000 --- a/test/Transforms/RaiseAllocations/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]] diff --git a/utils/findoptdiff b/utils/findoptdiff index 36620d932cb..4f8d08dbffe 100755 --- a/utils/findoptdiff +++ b/utils/findoptdiff @@ -70,7 +70,7 @@ dis2="$llvm2/Debug/bin/llvm-dis" opt1="$llvm1/Debug/bin/opt" opt2="$llvm2/Debug/bin/opt" -all_switches="-verify -lowersetjmp -raiseallocs -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -scalarrepl -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" +all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -scalarrepl -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" #counter=0 function tryit { -- 2.11.0