summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/Passes.html12
-rw-r--r--include/llvm-c/Transforms/IPO.h2
-rw-r--r--include/llvm/Analysis/MallocHelper.h11
-rw-r--r--include/llvm/Instructions.h3
-rw-r--r--include/llvm/LinkAllPasses.h1
-rw-r--r--include/llvm/Support/StandardPasses.h2
-rw-r--r--include/llvm/Transforms/IPO.h7
-rw-r--r--lib/Analysis/IPA/Andersens.cpp4
-rw-r--r--lib/Analysis/IPA/GlobalsModRef.cpp7
-rw-r--r--lib/Analysis/MallocHelper.cpp26
-rw-r--r--lib/Analysis/MemoryDependenceAnalysis.cpp8
-rw-r--r--lib/AsmParser/LLParser.cpp7
-rw-r--r--lib/AsmParser/LLParser.h2
-rw-r--r--lib/Bitcode/Reader/BitcodeReader.cpp3
-rw-r--r--lib/Transforms/IPO/CMakeLists.txt1
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp5
-rw-r--r--lib/Transforms/IPO/IPO.cpp2
-rw-r--r--lib/Transforms/IPO/RaiseAllocations.cpp173
-rw-r--r--lib/Transforms/Scalar/DeadStoreElimination.cpp14
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp40
-rw-r--r--lib/Transforms/Scalar/SCCP.cpp5
-rw-r--r--lib/Transforms/Utils/Local.cpp3
-rw-r--r--lib/Transforms/Utils/LowerAllocations.cpp6
-rw-r--r--lib/VMCore/Instructions.cpp45
-rw-r--r--test/Transforms/InstCombine/malloc-free-delete.ll6
-rw-r--r--test/Transforms/RaiseAllocations/2004-11-08-FreeUseCrash.ll10
-rw-r--r--test/Transforms/RaiseAllocations/2007-10-17-InvokeFree.ll17
-rw-r--r--test/Transforms/RaiseAllocations/FreeCastConstantExpr.ll11
-rw-r--r--test/Transforms/RaiseAllocations/dg.exp3
-rwxr-xr-xutils/findoptdiff2
30 files changed, 169 insertions, 269 deletions
diff --git a/docs/Passes.html b/docs/Passes.html
index bb17bee77c..36e0419ad2 100644
--- a/docs/Passes.html
+++ b/docs/Passes.html
@@ -158,7 +158,6 @@ perl -e '$/ = undef; for (split(/\n/, <>)) { s:^ *///? ?::; print " <p>\n" if !
<tr><td><a href="#memcpyopt">-memcpyopt</a></td><td>Optimize use of memcpy and friends</td></tr>
<tr><td><a href="#mergereturn">-mergereturn</a></td><td>Unify function exit nodes</td></tr>
<tr><td><a href="#prune-eh">-prune-eh</a></td><td>Remove unused exception handling info</td></tr>
-<tr><td><a href="#raiseallocs">-raiseallocs</a></td><td>Raise allocations from calls to instructions</td></tr>
<tr><td><a href="#reassociate">-reassociate</a></td><td>Reassociate expressions</td></tr>
<tr><td><a href="#reg2mem">-reg2mem</a></td><td>Demote all values to stack slots</td></tr>
<tr><td><a href="#scalarrepl">-scalarrepl</a></td><td>Scalar Replacement of Aggregates</td></tr>
@@ -1504,17 +1503,6 @@ if (X &lt; 3) {</pre>
<!-------------------------------------------------------------------------- -->
<div class="doc_subsection">
- <a name="raiseallocs">Raise allocations from calls to instructions</a>
-</div>
-<div class="doc_text">
- <p>
- Converts <tt>@malloc</tt> and <tt>@free</tt> calls to <tt>malloc</tt> and
- <tt>free</tt> instructions.
- </p>
-</div>
-
-<!-------------------------------------------------------------------------- -->
-<div class="doc_subsection">
<a name="reassociate">Reassociate expressions</a>
</div>
<div class="doc_text">
diff --git a/include/llvm-c/Transforms/IPO.h b/include/llvm-c/Transforms/IPO.h
index 9bc947f4d8..0a94315f62 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 e0c4d2c9e4..be307c02ae 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 9a990e7eb9..f7e7a3dbf9 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 3342ea89c5..9335976f33 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 c71e6b94fa..611e786448 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 9189c430cb..5e17904422 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 b5129a7d3b..e37a9dbb7a 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<GetElementPtrInst>(*UI)) {
if (AnalyzeUsesOfFunction(GEP)) return true;
+ } else if (isa<FreeInst>(*UI) || isFreeCall(*UI)) {
+ return false;
} else if (CallInst *CI = dyn_cast<CallInst>(*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<ICmpInst>(*UI)) {
if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
return true; // Allow comparison against null.
- } else if (isa<FreeInst>(*UI)) {
- return false;
} else {
return true;
}
diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp
index 7949288340..d83ea48080 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<BitCastInst>(*UI)) {
if (AnalyzeUsesOfPointer(BCI, Readers, Writers, OkayStoreDest))
return true;
+ } else if (isa<FreeInst>(*UI) || isFreeCall(*UI)) {
+ Writers.push_back(cast<Instruction>(*UI)->getParent()->getParent());
} else if (CallInst *CI = dyn_cast<CallInst>(*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<ICmpInst>(*UI)) {
if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
return true; // Allow comparison against null.
- } else if (FreeInst *F = dyn_cast<FreeInst>(*UI)) {
- Writers.push_back(F->getParent()->getParent());
} else {
return true;
}
@@ -439,7 +439,8 @@ void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) {
if (cast<StoreInst>(*II).isVolatile())
// Treat volatile stores as reading memory somewhere.
FunctionEffect |= Ref;
- } else if (isMalloc(&cast<Instruction>(*II)) || isa<FreeInst>(*II)) {
+ } else if (isMalloc(&cast<Instruction>(*II)) || isa<FreeInst>(*II) ||
+ isFreeCall(&cast<Instruction>(*II))) {
FunctionEffect |= ModRef;
}
diff --git a/lib/Analysis/MallocHelper.cpp b/lib/Analysis/MallocHelper.cpp
index e7bb41eeec..511de9d6a5 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<CallInst>(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 c3aa5bc930..ce7674003f 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<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
// Debug intrinsics don't cause dependences.
if (isa<DbgInfoIntrinsic>(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<CallInst>(QueryInst) || isa<InvokeInst>(QueryInst)) {
CallSite QueryCS = CallSite::get(QueryInst);
bool isReadOnly = AA->onlyReadsMemory(QueryCS);
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index 271567bd1e..52fd2b21e1 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<PointerType>(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 5dd6a2e700..b6877bc7c1 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 3a385cbe38..ffd330c74e 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 5c28801555..92bef3bb75 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 9ced2e89a7..0bc086f432 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 43066076ca..83e8624fe0 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 deb4405754..0000000000
--- 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 <algorithm>
-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<RaiseAllocations>
-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<const Type*>(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<User*> Users(FreeFunc->use_begin(), FreeFunc->use_end());
- std::vector<Value*> EqPointers; // Values equal to FreeFunc
-
- while (!Users.empty()) {
- User *U = Users.back();
- Users.pop_back();
-
- if (Instruction *I = dyn_cast<Instruction>(U)) {
- if (isa<InvokeInst>(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<PointerType>(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<InvokeInst>(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<GlobalValue>(U)) {
- Users.insert(Users.end(), GV->use_begin(), GV->use_end());
- EqPointers.push_back(GV);
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(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 a7b3e7524f..f55d8b2acc 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<StoreInst>(Inst) && !isa<FreeInst>(Inst))
+ if (!isa<StoreInst>(Inst) && !isa<FreeInst>(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<FreeInst>(Inst)) {
- MadeChange |= handleFreeWithNonTrivialDependency(FI, InstDep);
+ if (isa<FreeInst>(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<AliasAnalysis>();
StoreInst *Dependency = dyn_cast_or_null<StoreInst>(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<FreeInst>(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 21554c108d..be4f775731 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<UndefValue>(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<ConstantPointerNull>(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<Instruction>(Op));
+ }
+ } else {
+ // Op is a call to malloc
+ if (Op->hasOneUse()) {
+ EraseInstFromFunction(FI);
+ return EraseInstFromFunction(*cast<Instruction>(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 e3dd54e8bc..1bb5f4ae7f 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 b62261119c..940f5a9ec4 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<FreeInst>(BBI) ||
+ if (isa<FreeInst>(BBI) || isFreeCall(BBI) ||
(isa<CallInst>(BBI) && BBI->mayWriteToMemory() &&
!isa<DbgInfoIntrinsic>(BBI)))
return false;
diff --git a/lib/Transforms/Utils/LowerAllocations.cpp b/lib/Transforms/Utils/LowerAllocations.cpp
index 9c9113daa9..f64a30f5e8 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<FreeInst>(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 99a28594e6..60e203a7e0 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<PointerType>(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 fd91e447bd..a4b7496ef4 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* ; <i8**> [#uses=2]
%malloc_206 = malloc i8, i32 10 ; <i8*> [#uses=1]
+; CHECK-NOT: malloc
store i8* %malloc_206, i8** %c_19
%tmp_207 = load i8** %c_19 ; <i8*> [#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 75e02e84fa..0000000000
--- 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 ) ; <i32> [#uses=1]
- %tmp.14 = inttoptr i32 %tmp.13 to i32* ; <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 675bb3d829..0000000000
--- 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 1cf072910a..0000000000
--- 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 f2005891a5..0000000000
--- 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 36620d932c..4f8d08dbff 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 {