From 1d9d4bdc993c384342603e4354762eb36c1c569f Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Thu, 10 Sep 2009 04:36:43 +0000 Subject: [PATCH] Add malloc call utility functions. Patch by Victor Hernandez. llvm-svn: 81426 --- llvm/include/llvm/Analysis/MallocHelper.h | 86 ++++++++ llvm/include/llvm/Instructions.h | 12 ++ llvm/lib/Analysis/MallocHelper.cpp | 202 ++++++++++++++++++ .../lib/Transforms/Utils/LowerAllocations.cpp | 58 +---- llvm/lib/VMCore/Instructions.cpp | 111 ++++++++++ 5 files changed, 417 insertions(+), 52 deletions(-) create mode 100644 llvm/include/llvm/Analysis/MallocHelper.h create mode 100644 llvm/lib/Analysis/MallocHelper.cpp diff --git a/llvm/include/llvm/Analysis/MallocHelper.h b/llvm/include/llvm/Analysis/MallocHelper.h new file mode 100644 index 000000000000..06959ab6b399 --- /dev/null +++ b/llvm/include/llvm/Analysis/MallocHelper.h @@ -0,0 +1,86 @@ +//===- llvm/Analysis/MallocHelper.h ---- Identify malloc calls --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This family of functions identifies calls to malloc, bitcasts of malloc +// calls, and the types and array sizes associated with them. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_MALLOCHELPER_H +#define LLVM_ANALYSIS_MALLOCHELPER_H + +namespace llvm { +class BitCastInst; +class CallInst; +class Instruction; +class PointerType; +class Twine; +class Type; +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 +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 +/// ignore InvokeInst here. +const CallInst* extractMallocCall(const Value* I); +CallInst* extractMallocCall(Value* I); + +/// extractMallocCallFromBitCast - Returns the corresponding CallInst if the +/// instruction is a bitcast of the result of a malloc call. +const CallInst* extractMallocCallFromBitCast(const Value* I); +CallInst* extractMallocCallFromBitCast(Value* I); + +/// isArrayMalloc - Returns the corresponding CallInst if the instruction +/// matches the malloc call IR generated by CallInst::CreateMalloc(). This +/// means that it is a malloc call with one bitcast use AND the malloc call's +/// size argument is: +/// 1. a constant not equal to the malloc's allocated type +/// or +/// 2. the result of a multiplication by the malloc's allocated type +/// 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); + +/// getMallocType - Returns the PointerType resulting from the malloc call. +/// This PointerType is the result type of the call's only bitcast use. +/// If there is no unique bitcast use, then return NULL. +const PointerType* getMallocType(const CallInst* CI); + +/// getMallocAllocatedType - Returns the Type allocated by malloc call. This +/// Type is the result type of the call's only bitcast use. If there is no +/// unique bitcast use, then return NULL. +const Type* getMallocAllocatedType(const CallInst* CI); + +/// getMallocArraySize - Returns the array size of a malloc call. The array +/// size is computated in 1 of 3 ways: +/// 1. If the element type if of size 1, then array size is the argument to +/// malloc. +/// 2. Else if the malloc's argument is a constant, the array size is that +/// argument divided by the element type's size. +/// 3. Else the malloc argument must be a multiplication and the array size is +/// the first operand of the multiplication. +/// This function returns constant 1 if: +/// 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); + +} // End llvm namespace + +#endif diff --git a/llvm/include/llvm/Instructions.h b/llvm/include/llvm/Instructions.h index e208f37868ab..637e3555fb48 100644 --- a/llvm/include/llvm/Instructions.h +++ b/llvm/include/llvm/Instructions.h @@ -1033,6 +1033,18 @@ public: BasicBlock *InsertAtEnd) { return new(1) CallInst(F, NameStr, InsertAtEnd); } + /// CreateMalloc - Generate the IR for a call to malloc: + /// 1. Compute the malloc call's argument as the specified type's size, + /// possibly multiplied by the array size if the array size is not + /// 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 = ""); ~CallInst(); diff --git a/llvm/lib/Analysis/MallocHelper.cpp b/llvm/lib/Analysis/MallocHelper.cpp new file mode 100644 index 000000000000..5001110c6af2 --- /dev/null +++ b/llvm/lib/Analysis/MallocHelper.cpp @@ -0,0 +1,202 @@ +//===-- MallocHelper.cpp - Functions to identify malloc calls -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This family of functions identifies calls to malloc, bitcasts of malloc +// calls, and the types and array sizes associated with them. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/MallocHelper.h" +#include "llvm/Constants.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// 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. +bool llvm::isMalloc(Value* I) { + return extractMallocCall(I) || extractMallocCallFromBitCast(I); +} + +bool llvm::isMalloc(const Value* I) { + return extractMallocCall(I) || extractMallocCallFromBitCast(I); +} + +static bool isMallocCall(const CallInst *CI) { + 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; +} + +/// extractMallocCall - Returns the corresponding CallInst if the instruction +/// is a malloc call. Since CallInst::CreateMalloc() only creates calls, we +/// ignore InvokeInst here. +const CallInst* llvm::extractMallocCall(const Value* I) { + const CallInst *CI = dyn_cast(I); + return (isMallocCall(CI)) ? CI : NULL; +} + +CallInst* llvm::extractMallocCall(Value* I) { + CallInst *CI = dyn_cast(I); + return (isMallocCall(CI)) ? CI : NULL; +} + +static bool isBitCastOfMallocCall(const BitCastInst* BCI) { + if (!BCI) + return false; + + return isMallocCall(dyn_cast(BCI->getOperand(0))); +} + +/// extractMallocCallFromBitCast - Returns the corresponding CallInst if the +/// instruction is a bitcast of the result of a malloc call. +CallInst* llvm::extractMallocCallFromBitCast(Value* I) { + BitCastInst *BCI = dyn_cast(I); + return (isBitCastOfMallocCall(BCI)) ? cast(BCI->getOperand(0)) : NULL; +} + +const CallInst* llvm::extractMallocCallFromBitCast(const Value* I) { + const BitCastInst *BCI = dyn_cast(I); + return (isBitCastOfMallocCall(BCI)) ? cast(BCI->getOperand(0)) : NULL; +} + +static bool isArrayMallocHelper(const CallInst *CI) { + 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; + + for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end(); + UI != E; ) + if (!isa(cast(*UI++))) + 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); + + if (isa(MallocArg)) + return (MallocArg == ElementSize) ? false : true; + + BinaryOperator *BI = dyn_cast(MallocArg); + if (!BI) + return false; + + if (BI->getOpcode() != Instruction::Mul) + return false; + + if (BI->getOperand(1) != ElementSize) + return false; + + return true; +} + +/// isArrayMalloc - Returns the corresponding CallInst if the instruction +/// matches the malloc call IR generated by CallInst::CreateMalloc(). This +/// means that it is a malloc call with one bitcast use AND the malloc call's +/// size argument is: +/// 1. a constant not equal to the malloc's allocated type +/// or +/// 2. the result of a multiplication by the malloc's allocated type +/// Otherwise it returns NULL. +/// The unique bitcast is needed to determine the type/size of the array +/// allocation. +CallInst* llvm::isArrayMalloc(Value* I) { + CallInst *CI = extractMallocCall(I); + return (isArrayMallocHelper(CI)) ? CI : NULL; +} + +const CallInst* llvm::isArrayMalloc(const Value* I) { + const CallInst *CI = extractMallocCall(I); + return (isArrayMallocHelper(CI)) ? CI : NULL; +} + +/// getMallocType - Returns the PointerType resulting from the malloc call. +/// This PointerType is the result type of the call's only bitcast use. +/// If there is no unique bitcast use, then return NULL. +const PointerType* llvm::getMallocType(const CallInst* CI) { + assert(isMalloc(CI) && "GetMallocType and not malloc call"); + + const BitCastInst* BCI = NULL; + + // 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(cast(*UI++)); + + return BCI ? reinterpret_cast(BCI->getDestTy()) : NULL; +} + +/// getMallocAllocatedType - Returns the Type allocated by malloc call. This +/// Type is the result type of the call's only bitcast use. If there is no +/// unique bitcast use, then return NULL. +const Type* llvm::getMallocAllocatedType(const CallInst* CI) { + const PointerType* PT = getMallocType(CI); + return PT ? PT->getElementType() : NULL; +} + +/// isConstantOne - Return true only if val is constant int 1. +static bool isConstantOne(Value *val) { + return isa(val) && cast(val)->isOne(); +} + +/// getMallocArraySize - Returns the array size of a malloc call. The array +/// size is computated in 1 of 3 ways: +/// 1. If the element type if of size 1, then array size is the argument to +/// malloc. +/// 2. Else if the malloc's argument is a constant, the array size is that +/// argument divided by the element type's size. +/// 3. Else the malloc argument must be a multiplication and the array size is +/// the first operand of the multiplication. +/// This function returns constant 1 if: +/// 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) { + // Match CreateMalloc's use of constant 1 array-size for non-array mallocs. + if (!isArrayMalloc(CI)) + 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(ElementSize), + MallocArg->getType()); + + Constant* CO = dyn_cast(MallocArg); + BinaryOperator* BO = dyn_cast(MallocArg); + assert(isConstantOne(ElementSize) || CO || BO && + "getMallocArraySize and malformed malloc IR"); + + if (isConstantOne(ElementSize)) + return MallocArg; + + if (CO) + return ConstantExpr::getUDiv(CO, ElementSize); + + assert(BO && "getMallocArraySize not constant but not multiplication either"); + return BO->getOperand(0); +} diff --git a/llvm/lib/Transforms/Utils/LowerAllocations.cpp b/llvm/lib/Transforms/Utils/LowerAllocations.cpp index 7276d55fc4ef..cc1f6ea5e50a 100644 --- a/llvm/lib/Transforms/Utils/LowerAllocations.cpp +++ b/llvm/lib/Transforms/Utils/LowerAllocations.cpp @@ -33,13 +33,13 @@ namespace { /// @free calls. /// class VISIBILITY_HIDDEN LowerAllocations : public BasicBlockPass { - Constant *MallocFunc; // Functions in the module we are processing - Constant *FreeFunc; // Initialized by doInitialization + Constant *FreeFunc; // Functions in the module we are processing + // Initialized by doInitialization bool LowerMallocArgToInteger; public: static char ID; // Pass ID, replacement for typeid explicit LowerAllocations(bool LowerToInt = false) - : BasicBlockPass(&ID), MallocFunc(0), FreeFunc(0), + : BasicBlockPass(&ID), FreeFunc(0), LowerMallocArgToInteger(LowerToInt) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -88,10 +88,6 @@ Pass *llvm::createLowerAllocationsPass(bool LowerMallocArgToInteger) { // bool LowerAllocations::doInitialization(Module &M) { const Type *BPTy = PointerType::getUnqual(Type::getInt8Ty(M.getContext())); - // Prototype malloc as "char* malloc(...)", because we don't know in - // doInitialization whether size_t is int or long. - FunctionType *FT = FunctionType::get(BPTy, true); - MallocFunc = M.getOrInsertFunction("malloc", FT); FreeFunc = M.getOrInsertFunction("free" , Type::getVoidTy(M.getContext()), BPTy, (Type *)0); return true; @@ -102,7 +98,7 @@ bool LowerAllocations::doInitialization(Module &M) { // bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) { bool Changed = false; - assert(MallocFunc && FreeFunc && "Pass not initialized!"); + assert(FreeFunc && "Pass not initialized!"); BasicBlock::InstListType &BBIL = BB.getInstList(); @@ -112,50 +108,8 @@ 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(I)) { - const Type *AllocTy = MI->getType()->getElementType(); - - // malloc(type) becomes i8 *malloc(size) - Value *MallocArg; - if (LowerMallocArgToInteger) - MallocArg = ConstantInt::get(Type::getInt64Ty(BB.getContext()), - TD.getTypeAllocSize(AllocTy)); - else - MallocArg = ConstantExpr::getSizeOf(AllocTy); - MallocArg = - ConstantExpr::getTruncOrBitCast(cast(MallocArg), - IntPtrTy); - - if (MI->isArrayAllocation()) { - if (isa(MallocArg) && - cast(MallocArg)->isOne()) { - MallocArg = MI->getOperand(0); // Operand * 1 = Operand - } else if (Constant *CO = dyn_cast(MI->getOperand(0))) { - CO = - ConstantExpr::getIntegerCast(CO, IntPtrTy, false /*ZExt*/); - MallocArg = ConstantExpr::getMul(CO, - cast(MallocArg)); - } else { - Value *Scale = MI->getOperand(0); - if (Scale->getType() != IntPtrTy) - Scale = CastInst::CreateIntegerCast(Scale, IntPtrTy, false /*ZExt*/, - "", I); - - // Multiply it by the array size if necessary... - MallocArg = BinaryOperator::Create(Instruction::Mul, Scale, - MallocArg, "", I); - } - } - - // Create the call to Malloc. - CallInst *MCall = CallInst::Create(MallocFunc, MallocArg, "", I); - MCall->setTailCall(); - - // Create a cast instruction to convert to the right type... - Value *MCast; - if (MCall->getType() != Type::getVoidTy(BB.getContext())) - MCast = new BitCastInst(MCall, MI->getType(), "", I); - else - MCast = Constant::getNullValue(MI->getType()); + Value *MCast = CallInst::CreateMalloc(I, MI->getType(), IntPtrTy, + MI->getOperand(0)); // Replace all uses of the old malloc inst with the cast inst MI->replaceAllUsesWith(MCast); diff --git a/llvm/lib/VMCore/Instructions.cpp b/llvm/lib/VMCore/Instructions.cpp index 9d8e0477eed9..a03587107cca 100644 --- a/llvm/lib/VMCore/Instructions.cpp +++ b/llvm/lib/VMCore/Instructions.cpp @@ -16,6 +16,7 @@ #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/Instructions.h" +#include "llvm/Module.h" #include "llvm/Operator.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Support/ErrorHandling.h" @@ -440,6 +441,116 @@ bool CallInst::paramHasAttr(unsigned i, Attributes attr) const { return false; } +/// IsConstantOne - Return true only if val is constant int 1 +static bool IsConstantOne(Value *val) { + assert(val && "IsConstantOne does not work with NULL val"); + return isa(val) && cast(val)->isOne(); +} + +static Value *checkArraySize(Value *Amt, const Type *IntPtrTy) { + if (!Amt) + Amt = ConstantInt::get(IntPtrTy, 1); + else { + assert(!isa(Amt) && + "Passed basic block into malloc size parameter! Use other ctor"); + assert(Amt->getType() == IntPtrTy && + "Malloc array size is not an intptr!"); + } + return Amt; +} + +static Value *createMalloc(Instruction *InsertBefore, BasicBlock *InsertAtEnd, + const Type *AllocTy, const Type *IntPtrTy, + Value *ArraySize, const Twine &NameStr) { + assert((!InsertBefore && InsertAtEnd || InsertBefore && !InsertAtEnd) && + "createMalloc needs only InsertBefore or InsertAtEnd"); + const PointerType *AllocPtrType = dyn_cast(AllocTy); + assert(AllocPtrType && "CreateMalloc passed a non-pointer allocation type"); + + ArraySize = checkArraySize(ArraySize, IntPtrTy); + + // malloc(type) becomes i8 *malloc(size) + Value *AllocSize = ConstantExpr::getSizeOf(AllocPtrType->getElementType()); + AllocSize = ConstantExpr::getTruncOrBitCast(cast(AllocSize), + IntPtrTy); + if (!IsConstantOne(ArraySize)) + if (IsConstantOne(AllocSize)) { + AllocSize = ArraySize; // Operand * 1 = Operand + } else if (Constant *CO = dyn_cast(ArraySize)) { + Constant *Scale = ConstantExpr::getIntegerCast(CO, IntPtrTy, + false /*ZExt*/); + // Malloc arg is constant product of type size and array size + AllocSize = ConstantExpr::getMul(Scale, cast(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); + else + AllocSize = BinaryOperator::CreateMul(Scale, AllocSize, + "", InsertAtEnd); + } + + // 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); + CallInst *MCall = NULL; + if (InsertBefore) + MCall = CallInst::Create(MallocFunc, AllocSize, NameStr, InsertBefore); + else + MCall = CallInst::Create(MallocFunc, AllocSize, NameStr, InsertAtEnd); + MCall->setTailCall(); + + // Create a cast instruction to convert to the right type... + const Type* VoidT = Type::getVoidTy(BB->getContext()); + assert(MCall->getType() != VoidT && "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; +} + +/// CreateMalloc - Generate the IR for a call to malloc: +/// 1. Compute the malloc call's argument as the specified type's size, +/// possibly multiplied by the array size if the array size is not +/// 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); +} + +/// CreateMalloc - Generate the IR for a call to malloc: +/// 1. Compute the malloc call's argument as the specified type's size, +/// possibly multiplied by the array size if the array size is not +/// constant 1. +/// 2. Call malloc with that argument. +/// 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); +} //===----------------------------------------------------------------------===// // InvokeInst Implementation