diff options
-rw-r--r-- | include/llvm/Analysis/MallocHelper.h | 14 | ||||
-rw-r--r-- | include/llvm/Instructions.h | 12 | ||||
-rw-r--r-- | lib/Analysis/MallocHelper.cpp | 96 | ||||
-rw-r--r-- | lib/Transforms/Utils/LowerAllocations.cpp | 8 | ||||
-rw-r--r-- | lib/VMCore/Instruction.cpp | 24 | ||||
-rw-r--r-- | lib/VMCore/Instructions.cpp | 83 | ||||
-rw-r--r-- | lib/VMCore/Verifier.cpp | 10 |
7 files changed, 145 insertions, 102 deletions
diff --git a/include/llvm/Analysis/MallocHelper.h b/include/llvm/Analysis/MallocHelper.h index 06959ab..0588dff 100644 --- a/include/llvm/Analysis/MallocHelper.h +++ b/include/llvm/Analysis/MallocHelper.h @@ -16,11 +16,10 @@ #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 diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 637e355..fbee2af 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -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(); diff --git a/lib/Analysis/MallocHelper.cpp b/lib/Analysis/MallocHelper.cpp index 60930d5..9c1671d 100644 --- a/lib/Analysis/MallocHelper.cpp +++ b/lib/Analysis/MallocHelper.cpp @@ -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); } diff --git a/lib/Transforms/Utils/LowerAllocations.cpp b/lib/Transforms/Utils/LowerAllocations.cpp index cc1f6ea..2df953c 100644 --- a/lib/Transforms/Utils/LowerAllocations.cpp +++ b/lib/Transforms/Utils/LowerAllocations.cpp @@ -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); diff --git a/lib/VMCore/Instruction.cpp b/lib/VMCore/Instruction.cpp index 815dd7e..efa80d1 100644 --- a/lib/VMCore/Instruction.cpp +++ b/lib/VMCore/Instruction.cpp @@ -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(); diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index bf0d042..d479d9a 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -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); } //===----------------------------------------------------------------------===// diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index 140e6bd..f1f6e2e 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -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) { |