OSDN Git Service

Update malloc call creation code (AllocType is now the element type of the malloc...
authorVictor Hernandez <vhernandez@apple.com>
Fri, 18 Sep 2009 19:20:02 +0000 (19:20 +0000)
committerVictor Hernandez <vhernandez@apple.com>
Fri, 18 Sep 2009 19:20:02 +0000 (19:20 +0000)
In getMallocArraySize(), fix bug in the case that array size is the product of 2 constants.

Extend isArrayMalloc() and getMallocArraySize() to handle case where malloc is used as char array.

Ensure that ArraySize in LowerAllocations::runOnBasicBlock() is correct type.

Extend Instruction::isSafeToSpeculativelyExecute() to handle malloc calls.

Add verification for malloc calls.

Reviewed by Dan Gohman.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@82257 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/MallocHelper.h
include/llvm/Instructions.h
lib/Analysis/MallocHelper.cpp
lib/Transforms/Utils/LowerAllocations.cpp
lib/VMCore/Instruction.cpp
lib/VMCore/Instructions.cpp
lib/VMCore/Verifier.cpp

index 06959ab..0588dff 100644 (file)
 #define LLVM_ANALYSIS_MALLOCHELPER_H
 
 namespace llvm {
-class BitCastInst;
 class CallInst;
-class Instruction;
+class LLVMContext;
 class PointerType;
-class Twine;
+class TargetData;
 class Type;
 class Value;
 
@@ -31,7 +30,6 @@ class Value;
 /// isMalloc - Returns true if the the value is either a malloc call or a
 /// bitcast of the result of a malloc call
 bool isMalloc(const Value* I);
-bool isMalloc(Value* I);
 
 /// extractMallocCall - Returns the corresponding CallInst if the instruction
 /// is a malloc call.  Since CallInst::CreateMalloc() only creates calls, we
@@ -54,8 +52,9 @@ CallInst* extractMallocCallFromBitCast(Value* I);
 /// Otherwise it returns NULL.
 /// The unique bitcast is needed to determine the type/size of the array
 /// allocation.
-CallInst* isArrayMalloc(Value* I);
-const CallInst* isArrayMalloc(const Value* I);
+CallInst* isArrayMalloc(Value* I, LLVMContext &Context, const TargetData* TD);
+const CallInst* isArrayMalloc(const Value* I, LLVMContext &Context,
+                              const TargetData* TD);
 
 /// getMallocType - Returns the PointerType resulting from the malloc call.
 /// This PointerType is the result type of the call's only bitcast use.
@@ -79,7 +78,8 @@ const Type* getMallocAllocatedType(const CallInst* CI);
 ///  1. The malloc call's allocated type cannot be determined.
 ///  2. IR wasn't created by a call to CallInst::CreateMalloc() with a non-NULL
 ///     ArraySize.
-Value* getMallocArraySize(CallInst* CI);
+Value* getMallocArraySize(CallInst* CI, LLVMContext &Context,
+                          const TargetData* TD);
 
 } // End llvm namespace
 
index 637e355..fbee2af 100644 (file)
@@ -1039,12 +1039,12 @@ public:
   ///    constant 1.
   /// 2. Call malloc with that argument.
   /// 3. Bitcast the result of the malloc call to the specified type.
-  static Value *CreateMalloc(Instruction *I,
-                             const Type *AllocTy, const Type *IntPtrTy,
-                             Value *ArraySize = 0, const Twine &NameStr = "");
-  static Value *CreateMalloc(BasicBlock *InsertAtEnd,
-                             const Type *AllocTy, const Type *IntPtrTy,
-                             Value *ArraySize = 0, const Twine &NameStr = "");
+  static Value *CreateMalloc(Instruction *InsertBefore, const Type *IntPtrTy,
+                             const Type *AllocTy, Value *ArraySize = 0,
+                             const Twine &Name = "");
+  static Value *CreateMalloc(BasicBlock *InsertAtEnd, const Type *IntPtrTy,
+                             const Type *AllocTy, Value *ArraySize = 0,
+                             const Twine &Name = "");
 
   ~CallInst();
 
index 60930d5..9c1671d 100644 (file)
@@ -16,6 +16,7 @@
 #include "llvm/Constants.h"
 #include "llvm/Instructions.h"
 #include "llvm/Module.h"
+#include "llvm/Analysis/ConstantFolding.h"
 using namespace llvm;
 
 //===----------------------------------------------------------------------===//
@@ -24,10 +25,6 @@ using namespace llvm;
 
 /// isMalloc - Returns true if the the value is either a malloc call or a
 /// bitcast of the result of a malloc call.
-bool llvm::isMalloc(Value* I) {
-  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
-}
-
 bool llvm::isMalloc(const Value* I) {
   return extractMallocCall(I) || extractMallocCallFromBitCast(I);
 }
@@ -79,40 +76,42 @@ const CallInst* llvm::extractMallocCallFromBitCast(const Value* I) {
                                       : NULL;
 }
 
-static bool isArrayMallocHelper(const CallInst *CI) {
+static bool isArrayMallocHelper(const CallInst *CI, LLVMContext &Context,
+                                const TargetData* TD) {
   if (!CI)
     return false;
 
-  // Only identify array mallocs for mallocs with 1 bitcast use.  The unique 
-  // bitcast is needed to determine the type/size of the array allocation.
-  if (!CI->hasOneUse()) return false;
+  const Type* T = getMallocAllocatedType(CI);
 
-  for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end();
-       UI != E; )
-    if (!isa<BitCastInst>(cast<Instruction>(*UI++)))
-      return false;
+  // We can only indentify an array malloc if we know the type of the malloc 
+  // call.
+  if (!T) return false;
 
-  // malloc arg
   Value* MallocArg = CI->getOperand(1);
-  // element size
-  const Type* T = getMallocAllocatedType(CI);
-  if (!T) return false;
   Constant *ElementSize = ConstantExpr::getSizeOf(T);
-  
+  ElementSize = ConstantExpr::getTruncOrBitCast(ElementSize, 
+                                                MallocArg->getType());
+  Constant *FoldedElementSize = ConstantFoldConstantExpression(
+                                       cast<ConstantExpr>(ElementSize), 
+                                       Context, TD);
+
+
   if (isa<ConstantExpr>(MallocArg))
-    return (MallocArg == ElementSize) ? false : true;
+    return (MallocArg != ElementSize);
 
   BinaryOperator *BI = dyn_cast<BinaryOperator>(MallocArg);
   if (!BI)
     return false;
 
-  if (BI->getOpcode() != Instruction::Mul)
-    return false;
-      
-  if (BI->getOperand(1) != ElementSize)
-    return false;
-        
-  return true;
+  if (BI->getOpcode() == Instruction::Mul)
+    // ArraySize * ElementSize
+    if (BI->getOperand(1) == ElementSize ||
+        (FoldedElementSize && BI->getOperand(1) == FoldedElementSize))
+      return true;
+
+  // TODO: Detect case where MallocArg mul has been transformed to shl.
+
+  return false;
 }
 
 /// isArrayMalloc - Returns the corresponding CallInst if the instruction 
@@ -125,14 +124,16 @@ static bool isArrayMallocHelper(const CallInst *CI) {
 /// Otherwise it returns NULL.
 /// The unique bitcast is needed to determine the type/size of the array
 /// allocation.
-CallInst* llvm::isArrayMalloc(Value* I) {
+CallInst* llvm::isArrayMalloc(Value* I, LLVMContext &Context,
+                              const TargetData* TD) {
   CallInst *CI = extractMallocCall(I);
-  return (isArrayMallocHelper(CI)) ? CI : NULL;
+  return (isArrayMallocHelper(CI, Context, TD)) ? CI : NULL;
 }
 
-const CallInst* llvm::isArrayMalloc(const Value* I) {
+const CallInst* llvm::isArrayMalloc(const Value* I, LLVMContext &Context,
+                                    const TargetData* TD) {
   const CallInst *CI = extractMallocCall(I);
-  return (isArrayMallocHelper(CI)) ? CI : NULL;
+  return (isArrayMallocHelper(CI, Context, TD)) ? CI : NULL;
 }
 
 /// getMallocType - Returns the PointerType resulting from the malloc call.
@@ -142,14 +143,24 @@ const PointerType* llvm::getMallocType(const CallInst* CI) {
   assert(isMalloc(CI) && "GetMallocType and not malloc call");
   
   const BitCastInst* BCI = NULL;
+  
+  // Determine if CallInst has a bitcast use.
+  for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end();
+       UI != E; )
+    if ((BCI = dyn_cast<BitCastInst>(cast<Instruction>(*UI++))))
+      break;
+
+  // Malloc call has 1 bitcast use and no other uses, so type is the bitcast's
+  // destination type.
+  if (BCI && CI->hasOneUse())
+    return cast<PointerType>(BCI->getDestTy());
 
-  // Determine type only if there is only 1 bitcast use of CI.
-  if (CI->hasOneUse())
-    for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end();
-         UI != E; )
-      BCI = dyn_cast<BitCastInst>(cast<Instruction>(*UI++));
+  // Malloc call was not bitcast, so the type is the malloc's return type, i8*.
+  if (!BCI)
+    return cast<PointerType>(CI->getType());
 
-  return BCI ? reinterpret_cast<const PointerType*>(BCI->getDestTy()) : NULL;
+  // Type could not be determined.
+  return NULL;
 }
 
 /// getMallocAllocatedType - Returns the Type allocated by malloc call. This
@@ -177,15 +188,16 @@ static bool isConstantOne(Value *val) {
 ///  1. The malloc call's allocated type cannot be determined.
 ///  2. IR wasn't created by a call to CallInst::CreateMalloc() with a non-NULL
 ///     ArraySize.
-Value* llvm::getMallocArraySize(CallInst* CI) {
+Value* llvm::getMallocArraySize(CallInst* CI, LLVMContext &Context,
+                                const TargetData* TD) {
   // Match CreateMalloc's use of constant 1 array-size for non-array mallocs.
-  if (!isArrayMalloc(CI))
+  if (!isArrayMalloc(CI, Context, TD))
     return ConstantInt::get(CI->getOperand(1)->getType(), 1);
 
   Value* MallocArg = CI->getOperand(1);
   assert(getMallocAllocatedType(CI) && "getMallocArraySize and no type");
   Constant *ElementSize = ConstantExpr::getSizeOf(getMallocAllocatedType(CI));
-  ElementSize = ConstantExpr::getTruncOrBitCast(cast<Constant>(ElementSize)
+  ElementSize = ConstantExpr::getTruncOrBitCast(ElementSize
                                                 MallocArg->getType());
 
   Constant* CO = dyn_cast<Constant>(MallocArg);
@@ -195,10 +207,12 @@ Value* llvm::getMallocArraySize(CallInst* CI) {
       
   if (isConstantOne(ElementSize))
     return MallocArg;
+    
+  if (CO)
+    return CO->getOperand(0);
+    
+  // TODO: Detect case where MallocArg mul has been transformed to shl.
 
-  if (CO) 
-    return ConstantExpr::getUDiv(CO, ElementSize);
-  
   assert(BO && "getMallocArraySize not constant but not multiplication either");
   return BO->getOperand(0);
 }
index cc1f6ea..2df953c 100644 (file)
@@ -108,8 +108,12 @@ bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) {
   // Loop over all of the instructions, looking for malloc or free instructions
   for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
     if (MallocInst *MI = dyn_cast<MallocInst>(I)) {
-      Value *MCast = CallInst::CreateMalloc(I, MI->getType(), IntPtrTy,
-                                            MI->getOperand(0));
+      Value *ArraySize = MI->getOperand(0);
+      if (ArraySize->getType() != IntPtrTy)
+        ArraySize = CastInst::CreateIntegerCast(ArraySize, IntPtrTy,
+                                                false /*ZExt*/, "", I);
+      Value *MCast = CallInst::CreateMalloc(I, IntPtrTy,
+                                            MI->getAllocatedType(), ArraySize);
 
       // Replace all uses of the old malloc inst with the cast inst
       MI->replaceAllUsesWith(MCast);
index 815dd7e..efa80d1 100644 (file)
@@ -16,6 +16,7 @@
 #include "llvm/Function.h"
 #include "llvm/Constants.h"
 #include "llvm/GlobalVariable.h"
+#include "llvm/Module.h"
 #include "llvm/Support/CallSite.h"
 #include "llvm/Support/LeakDetector.h"
 using namespace llvm;
@@ -375,6 +376,27 @@ bool Instruction::isCommutative(unsigned op) {
   }
 }
 
+// Code here matches isMalloc from MallocHelper, which is not in VMCore.
+static bool isMalloc(const Value* I) {
+  const CallInst *CI = dyn_cast<CallInst>(I);
+  if (!CI) {
+       const BitCastInst *BCI = dyn_cast<BitCastInst>(I);
+       if (!BCI) return false;
+
+    CI = dyn_cast<CallInst>(BCI->getOperand(0));
+  }
+
+  if (!CI) return false;
+
+  const Module* M = CI->getParent()->getParent()->getParent();
+  Constant *MallocFunc = M->getFunction("malloc");
+
+  if (CI->getOperand(0) != MallocFunc)
+    return false;
+
+  return true;
+}
+
 bool Instruction::isSafeToSpeculativelyExecute() const {
   for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
     if (Constant *C = dyn_cast<Constant>(getOperand(i)))
@@ -400,7 +422,7 @@ bool Instruction::isSafeToSpeculativelyExecute() const {
   case Load: {
     if (cast<LoadInst>(this)->isVolatile())
       return false;
-    if (isa<AllocationInst>(getOperand(0)))
+    if (isa<AllocationInst>(getOperand(0)) || isMalloc(getOperand(0)))
       return true;
     if (GlobalVariable *GV = dyn_cast<GlobalVariable>(getOperand(0)))
       return !GV->hasExternalWeakLinkage();
index bf0d042..d479d9a 100644 (file)
@@ -460,19 +460,20 @@ static Value *checkArraySize(Value *Amt, const Type *IntPtrTy) {
 }
 
 static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd,
-                           const Type *AllocTy, const Type *IntPtrTy,
+                           const Type *IntPtrTy, const Type *AllocTy,
                            Value *ArraySize, const Twine &NameStr) {
   assert(((!InsertBefore && InsertAtEnd) || (InsertBefore && !InsertAtEnd)) &&
-         "createMalloc needs only InsertBefore or InsertAtEnd");
-  const PointerType *AllocPtrType = dyn_cast<PointerType>(AllocTy);
-  assert(AllocPtrType && "CreateMalloc passed a non-pointer allocation type");
-  
+         "createMalloc needs either InsertBefore or InsertAtEnd");
+
+  // malloc(type) becomes: 
+  //       bitcast (i8* malloc(typeSize)) to type*
+  // malloc(type, arraySize) becomes:
+  //       bitcast (i8 *malloc(typeSize*arraySize)) to type*
+  Value *AllocSize = ConstantExpr::getSizeOf(AllocTy);
+  AllocSize = ConstantExpr::getTruncOrBitCast(cast<Constant>(AllocSize),
+                                              IntPtrTy);
   ArraySize = checkArraySize(ArraySize, IntPtrTy);
 
-  // malloc(type) becomes i8 *malloc(size)
-  Value *AllocSize = ConstantExpr::getSizeOf(AllocPtrType->getElementType());
-  AllocSize = ConstantExpr::getTruncOrBitCast(cast<Constant>(AllocSize), 
-                                              IntPtrTy);
   if (!IsConstantOne(ArraySize)) {
     if (IsConstantOne(AllocSize)) {
       AllocSize = ArraySize;         // Operand * 1 = Operand
@@ -482,47 +483,41 @@ static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd,
       // Malloc arg is constant product of type size and array size
       AllocSize = ConstantExpr::getMul(Scale, cast<Constant>(AllocSize));
     } else {
-      Value *Scale = ArraySize;
-      if (Scale->getType() != IntPtrTy) {
-        if (InsertBefore)
-          Scale = CastInst::CreateIntegerCast(Scale, IntPtrTy, false /*ZExt*/,
-                                              "", InsertBefore);
-        else
-          Scale = CastInst::CreateIntegerCast(Scale, IntPtrTy, false /*ZExt*/,
-                                              "", InsertAtEnd);
-      }
       // Multiply type size by the array size...
       if (InsertBefore)
-        AllocSize = BinaryOperator::CreateMul(Scale, AllocSize,
-                                              "", InsertBefore);
+        AllocSize = BinaryOperator::CreateMul(ArraySize, AllocSize,
+                                              "mallocsize", InsertBefore);
       else
-        AllocSize = BinaryOperator::CreateMul(Scale, AllocSize,
-                                              "", InsertAtEnd);
+        AllocSize = BinaryOperator::CreateMul(ArraySize, AllocSize,
+                                              "mallocsize", InsertAtEnd);
     }
   }
 
+  assert(AllocSize->getType() == IntPtrTy && "malloc arg is wrong size");
   // Create the call to Malloc.
   BasicBlock* BB = InsertBefore ? InsertBefore->getParent() : InsertAtEnd;
   Module* M = BB->getParent()->getParent();
   const Type *BPTy = PointerType::getUnqual(Type::getInt8Ty(BB->getContext()));
   // prototype malloc as "void *malloc(size_t)"
-  Constant *MallocFunc = M->getOrInsertFunction("malloc", BPTy, 
-                                                IntPtrTy, NULL);
+  Constant *MallocF = M->getOrInsertFunction("malloc", BPTy, IntPtrTy, NULL);
+  if (!cast<Function>(MallocF)->doesNotAlias(0))
+    cast<Function>(MallocF)->setDoesNotAlias(0);
+  const PointerType *AllocPtrType = PointerType::getUnqual(AllocTy);
   CallInst *MCall = NULL;
-  if (InsertBefore) 
-    MCall = CallInst::Create(MallocFunc, AllocSize, NameStr, InsertBefore);
-  else
-    MCall = CallInst::Create(MallocFunc, AllocSize, NameStr, InsertAtEnd);
+  Value    *MCast = NULL;
+  if (InsertBefore) {
+    MCall = CallInst::Create(MallocF, AllocSize, "malloccall", InsertBefore);
+    // Create a cast instruction to convert to the right type...
+    MCast = new BitCastInst(MCall, AllocPtrType, NameStr, InsertBefore);
+  } else {
+    MCall = CallInst::Create(MallocF, AllocSize, "malloccall", InsertAtEnd);
+    // Create a cast instruction to convert to the right type...
+    MCast = new BitCastInst(MCall, AllocPtrType, NameStr);
+  }
   MCall->setTailCall();
-
-  // Create a cast instruction to convert to the right type...
   assert(MCall->getType() != Type::getVoidTy(BB->getContext()) &&
          "Malloc has void return type");
-  Value *MCast;
-  if (InsertBefore)
-    MCast = new BitCastInst(MCall, AllocPtrType, NameStr, InsertBefore);
-  else
-    MCast = new BitCastInst(MCall, AllocPtrType, NameStr);
+
   return MCast;
 }
 
@@ -532,11 +527,10 @@ static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd,
 ///    constant 1.
 /// 2. Call malloc with that argument.
 /// 3. Bitcast the result of the malloc call to the specified type.
-Value *CallInst::CreateMalloc(Instruction *InsertBefore,
-                              const Type *AllocTy, const Type *IntPtrTy,
-                              Value *ArraySize, const Twine &NameStr) {
-  return createMalloc(InsertBefore, NULL, AllocTy,
-                      IntPtrTy, ArraySize, NameStr);
+Value *CallInst::CreateMalloc(Instruction *InsertBefore, const Type *IntPtrTy,
+                              const Type *AllocTy, Value *ArraySize,
+                              const Twine &Name) {
+  return createMalloc(InsertBefore, NULL, IntPtrTy, AllocTy, ArraySize, Name);
 }
 
 /// CreateMalloc - Generate the IR for a call to malloc:
@@ -547,11 +541,10 @@ Value *CallInst::CreateMalloc(Instruction *InsertBefore,
 /// 3. Bitcast the result of the malloc call to the specified type.
 /// Note: This function does not add the bitcast to the basic block, that is the
 /// responsibility of the caller.
-Value *CallInst::CreateMalloc(BasicBlock *InsertAtEnd,
-                              const Type *AllocTy, const Type *IntPtrTy,
-                              Value *ArraySize, const Twine &NameStr) {
-  return createMalloc(NULL, InsertAtEnd, AllocTy, 
-                      IntPtrTy, ArraySize, NameStr);
+Value *CallInst::CreateMalloc(BasicBlock *InsertAtEnd, const Type *IntPtrTy,
+                              const Type *AllocTy, Value *ArraySize, 
+                              const Twine &Name) {
+  return createMalloc(NULL, InsertAtEnd, IntPtrTy, AllocTy, ArraySize, Name);
 }
 
 //===----------------------------------------------------------------------===//
index 140e6bd..f1f6e2e 100644 (file)
@@ -1143,6 +1143,16 @@ void Verifier::visitCallInst(CallInst &CI) {
   if (Function *F = CI.getCalledFunction())
     if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
       visitIntrinsicFunctionCall(ID, CI);
+
+  // Code here matches isMalloc from MallocHelper, which is not in VMCore.
+  const Module* M = CI.getParent()->getParent()->getParent();
+  Constant *MallocFunc = M->getFunction("malloc");
+
+  if (CI.getOperand(0) == MallocFunc) {
+    const PointerType *PTy =
+        PointerType::getUnqual(Type::getInt8Ty(CI.getParent()->getContext()));
+    Assert1(CI.getType() == PTy, "Malloc call must return i8*", &CI);
+  }
 }
 
 void Verifier::visitInvokeInst(InvokeInst &II) {