Teach instCombine to remove malloc+free if malloc's only uses are comparisons
authorDuncan Sands <baldrick@free.fr>
Thu, 27 May 2010 19:09:06 +0000 (19:09 +0000)
committerDuncan Sands <baldrick@free.fr>
Thu, 27 May 2010 19:09:06 +0000 (19:09 +0000)
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
lib/Transforms/InstCombine/InstCombineCalls.cpp
lib/Transforms/InstCombine/InstCombineCompares.cpp
lib/Transforms/InstCombine/InstructionCombining.cpp
test/Transforms/InstCombine/badmalloc.ll
test/Transforms/InstCombine/malloc-free-delete.ll

index c7b04a4..5509b4f 100644 (file)
@@ -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);
index 38e7b6e..08a6ff4 100644 (file)
@@ -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.
index 861cf92..2b4998f 100644 (file)
@@ -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<ConstantPointerNull>(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 &&
index af9ec5c..ab43f7d 100644 (file)
@@ -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<ICmpInst>(*UI))
+      if (ICI->isEquality() && isa<ConstantPointerNull>(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<Instruction>(*UI);
+
+      // Early increment here, as we're about to get rid of the user.
+      ++UI;
+
+      if (isFreeCall(I)) {
+        EraseInstFromFunction(*cast<CallInst>(I));
+        continue;
+      }
+      // Again, the cast is safe.
+      ICmpInst *C = cast<ICmpInst>(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<ConstantPointerNull>(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<Instruction>(Op));
-      }
-    } else {
-      // Op is a call to malloc
-      if (Op->hasOneUse()) {
-        EraseInstFromFunction(FI);
-        return EraseInstFromFunction(*cast<Instruction>(Op));
-      }
-    }
-  }
-
   return 0;
 }
 
index cab23b5..f5a623d 100644 (file)
@@ -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
index a4b7496..317786f 100644 (file)
@@ -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*              ; <i8**> [#uses=2]
-        %malloc_206 = malloc i8, i32 10         ; <i8*> [#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              ; <i8*> [#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
+}