From 1d9b973fd7e60e4149678a03aac762551c846f13 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 27 May 2010 19:09:06 +0000 Subject: [PATCH] Teach instCombine to remove malloc+free if malloc's only uses are comparisons to null. Patch by Matti Niemenmaa. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@104871 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/InstCombine/InstCombine.h | 1 + .../InstCombine/InstCombineCalls.cpp | 2 + .../InstCombine/InstCombineCompares.cpp | 29 --------- .../InstCombine/InstructionCombining.cpp | 63 ++++++++++++++----- test/Transforms/InstCombine/badmalloc.ll | 1 + .../InstCombine/malloc-free-delete.ll | 20 ++++-- 6 files changed, 66 insertions(+), 50 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h index c7b04a4a83a..5509b4f6304 100644 --- a/lib/Transforms/InstCombine/InstCombine.h +++ b/lib/Transforms/InstCombine/InstCombine.h @@ -178,6 +178,7 @@ public: Instruction *visitPHINode(PHINode &PN); Instruction *visitGetElementPtrInst(GetElementPtrInst &GEP); Instruction *visitAllocaInst(AllocaInst &AI); + Instruction *visitMalloc(Instruction &FI); Instruction *visitFree(Instruction &FI); Instruction *visitLoadInst(LoadInst &LI); Instruction *visitStoreInst(StoreInst &SI); diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 38e7b6ec2d1..08a6ff41ebb 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -250,6 +250,8 @@ Instruction *InstCombiner::SimplifyMemSet(MemSetInst *MI) { Instruction *InstCombiner::visitCallInst(CallInst &CI) { if (isFreeCall(&CI)) return visitFree(CI); + if (isMalloc(&CI)) + return visitMalloc(CI); // If the caller function is nounwind, mark the call as nounwind, even if the // callee isn't. diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index 861cf92d281..2b4998f3c31 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1924,35 +1924,6 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { } break; } - case Instruction::Call: - // If we have (malloc != null), and if the malloc has a single use, we - // can assume it is successful and remove the malloc. - if (isMalloc(LHSI) && LHSI->hasOneUse() && - isa(RHSC)) { - // Need to explicitly erase malloc call here, instead of adding it to - // Worklist, because it won't get DCE'd from the Worklist since - // isInstructionTriviallyDead() returns false for function calls. - // It is OK to replace LHSI/MallocCall with Undef because the - // instruction that uses it will be erased via Worklist. - if (extractMallocCall(LHSI)) { - LHSI->replaceAllUsesWith(UndefValue::get(LHSI->getType())); - EraseInstFromFunction(*LHSI); - return ReplaceInstUsesWith(I, - ConstantInt::get(Type::getInt1Ty(I.getContext()), - !I.isTrueWhenEqual())); - } - if (CallInst* MallocCall = extractMallocCallFromBitCast(LHSI)) - if (MallocCall->hasOneUse()) { - MallocCall->replaceAllUsesWith( - UndefValue::get(MallocCall->getType())); - EraseInstFromFunction(*MallocCall); - Worklist.Add(LHSI); // The malloc's bitcast use. - return ReplaceInstUsesWith(I, - ConstantInt::get(Type::getInt1Ty(I.getContext()), - !I.isTrueWhenEqual())); - } - } - break; case Instruction::IntToPtr: // icmp pred inttoptr(X), null -> icmp pred X, 0 if (RHSC->isNullValue() && TD && diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index af9ec5cacff..ab43f7d8818 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -710,6 +710,52 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { return 0; } + + +static bool IsOnlyNullComparedAndFreed(const Value &V) { + for (Value::const_use_iterator UI = V.use_begin(), UE = V.use_end(); + UI != UE; ++UI) { + if (isFreeCall(*UI)) + continue; + if (const ICmpInst *ICI = dyn_cast(*UI)) + if (ICI->isEquality() && isa(ICI->getOperand(1))) + continue; + return false; + } + return true; +} + +Instruction *InstCombiner::visitMalloc(Instruction &MI) { + // If we have a malloc call which is only used in any amount of comparisons + // to null and free calls, delete the calls and replace the comparisons with + // true or false as appropriate. + if (IsOnlyNullComparedAndFreed(MI)) { + for (Value::use_iterator UI = MI.use_begin(), UE = MI.use_end(); + UI != UE;) { + // We can assume that every remaining use is a free call or an icmp eq/ne + // to null, so the cast is safe. + Instruction *I = cast(*UI); + + // Early increment here, as we're about to get rid of the user. + ++UI; + + if (isFreeCall(I)) { + EraseInstFromFunction(*cast(I)); + continue; + } + // Again, the cast is safe. + ICmpInst *C = cast(I); + ReplaceInstUsesWith(*C, ConstantInt::get(Type::getInt1Ty(C->getContext()), + C->isFalseWhenEqual())); + EraseInstFromFunction(*C); + } + return EraseInstFromFunction(MI); + } + return 0; +} + + + Instruction *InstCombiner::visitFree(Instruction &FI) { Value *Op = FI.getOperand(1); @@ -726,23 +772,6 @@ Instruction *InstCombiner::visitFree(Instruction &FI) { if (isa(Op)) return EraseInstFromFunction(FI); - // If we have a malloc call whose only use is a free call, delete both. - 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; } diff --git a/test/Transforms/InstCombine/badmalloc.ll b/test/Transforms/InstCombine/badmalloc.ll index cab23b5af59..f5a623dc77c 100644 --- a/test/Transforms/InstCombine/badmalloc.ll +++ b/test/Transforms/InstCombine/badmalloc.ll @@ -10,6 +10,7 @@ declare void @free(i8*) define i1 @test1() { %A = call noalias i8* @malloc(i64 4) nounwind %B = icmp eq i8* %A, null + store i8 0, i8* %A call void @free(i8* %A) ret i1 %B diff --git a/test/Transforms/InstCombine/malloc-free-delete.ll b/test/Transforms/InstCombine/malloc-free-delete.ll index a4b7496ef40..317786fc564 100644 --- a/test/Transforms/InstCombine/malloc-free-delete.ll +++ b/test/Transforms/InstCombine/malloc-free-delete.ll @@ -1,13 +1,25 @@ -; RUN: opt < %s -instcombine -globaldce -S | FileCheck %s +; RUN: opt < %s -instcombine -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] + %c_19 = alloca i8* + %malloc_206 = malloc i8, i32 10 ; CHECK-NOT: malloc store i8* %malloc_206, i8** %c_19 - %tmp_207 = load i8** %c_19 ; [#uses=1] + %tmp_207 = load i8** %c_19 free i8* %tmp_207 ; CHECK-NOT: free ret i32 0 ; CHECK: ret i32 0 } + +declare i8* @malloc(i32) +declare void @free(i8*) + +define i1 @foo() { +; CHECK: @foo +; CHECK-NEXT: ret i1 false + %m = call i8* @malloc(i32 1) + %z = icmp eq i8* %m, null + call void @free(i8* %m) + ret i1 %z +}