[llvm-commits] [llvm] r158919 - in /llvm/trunk: include/llvm/Analysis/MemoryBuiltins.h lib/Analysis/BasicAliasAnalysis.cpp lib/Analysis/IPA/GlobalsModRef.cpp lib/Analysis/MemoryBuiltins.cpp lib/Analysis/MemoryDependenceAnalysis.cpp lib/Transforms/InstCombine/InstCombineCalls.cpp lib/Transforms/InstCombine/InstructionCombining.cpp lib/Transforms/Scalar/DeadStoreElimination.cpp lib/Transforms/Scalar/GVN.cpp lib/Transforms/Utils/Local.cpp test/Transforms/InstCombine/objsize.ll

Hal Finkel hfinkel at anl.gov
Wed Jun 27 12:52:23 PDT 2012


On Wed, 27 Jun 2012 20:42:22 +0100
Nuno Lopes <nunoplopes at sapo.pt> wrote:

> Hi,
> 
> Well, it's not broken. It's just saying it doesn't know how to deal  
> with that instruction.
> Is there any thing we can do about this instruction, or should we
> just ignore it?

Probably ignore it. Nadav, do you have any thoughts on this?

 -Hal

> 
> Nuno
> 
> 
> Quoting Hal Finkel <hfinkel at anl.gov>:
> 
> > Nuno,
> >
> > I think that something here is broken w.r.t. pointer vectors.
> > When testing the vectorizer I see errors in the debug output
> > like this:
> >
> > ObjectSizeOffsetVisitor unknown instruction:  %arrayidx7.v.r1 =
> > extractelement <2 x double*> %arrayidx7, i32 0
> >
> >  -Hal
> >
> > On Thu, 21 Jun 2012 15:45:29 -0000
> > Nuno Lopes <nunoplopes at sapo.pt> wrote:
> >
> >> Author: nlopes
> >> Date: Thu Jun 21 10:45:28 2012
> >> New Revision: 158919
> >>
> >> URL: http://llvm.org/viewvc/llvm-project?rev=158919&view=rev
> >> Log:
> >> refactor the MemoryBuiltin analysis:
> >>  - provide more extensive set of functions to detect library
> >> allocation functions (e.g., malloc, calloc, strdup, etc)
> >>  - provide an API to compute the size and offset of an object
> >> pointed by
> >>
> >> Move a few clients (GVN, AA, instcombine, ...) to the new API.
> >> This implementation is a lot more aggressive than each of the
> >> custom implementations being replaced.
> >>
> >> Patch reviewed by Nick Lewycky and Chandler Carruth, thanks.
> >>
> >> Modified:
> >>     llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h
> >>     llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
> >>     llvm/trunk/lib/Analysis/IPA/GlobalsModRef.cpp
> >>     llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
> >>     llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp
> >>     llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
> >>     llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp
> >>     llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
> >>     llvm/trunk/lib/Transforms/Scalar/GVN.cpp
> >>     llvm/trunk/lib/Transforms/Utils/Local.cpp
> >>     llvm/trunk/test/Transforms/InstCombine/objsize.ll
> >>
> >> Modified: llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h (original)
> >> +++ llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h Thu Jun 21
> >> 10:45:28 2012 @@ -15,6 +15,14 @@ #ifndef
> >> LLVM_ANALYSIS_MEMORYBUILTINS_H #define
> >> LLVM_ANALYSIS_MEMORYBUILTINS_H
> >>
> >> +#include "llvm/ADT/DenseMap.h"
> >> +#include "llvm/ADT/SmallPtrSet.h"
> >> +#include "llvm/Operator.h"
> >> +#include "llvm/Support/DataTypes.h"
> >> +#include "llvm/Support/InstVisitor.h"
> >> +#include "llvm/Support/IRBuilder.h"
> >> +#include "llvm/Support/TargetFolder.h"
> >> +
> >>  namespace llvm {
> >>  class CallInst;
> >>  class PointerType;
> >> @@ -22,24 +30,50 @@
> >>  class Type;
> >>  class Value;
> >>
> >> +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates or +/// reallocates memory (either malloc, calloc,
> >> realloc, or strdup like). +bool isAllocationFn(const Value *V, bool
> >> LookThroughBitCast = false); +
> >> +/// \brief Tests if a value is a call to a function that returns a
> >> NoAlias +/// pointer (including malloc/calloc/strdup-like
> >> functions). +bool isNoAliasFn(const Value *V, bool
> >> LookThroughBitCast = false); +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates +/// uninitialized memory (such as malloc).
> >> +bool isMallocLikeFn(const Value *V, bool LookThroughBitCast =
> >> false); +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates +/// zero-filled memory (such as calloc).
> >> +bool isCallocLikeFn(const Value *V, bool LookThroughBitCast =
> >> false); +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates +/// memory (either malloc, calloc, or strdup like).
> >> +bool isAllocLikeFn(const Value *V, bool LookThroughBitCast =
> >> false); +
> >> +/// \brief Tests if a value is a call to a library function that
> >> reallocates +/// memory (such as realloc).
> >> +bool isReallocLikeFn(const Value *V, bool LookThroughBitCast =
> >> false); +
> >> +
> >>   
> >> //===----------------------------------------------------------------------===//
> >>  //  malloc Call Utility Functions.
> >>  //
> >>
> >> -/// isMalloc - Returns true if the value is either a malloc call
> >> or a bitcast of -/// the result of a malloc call
> >> -bool isMalloc(const 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);
> >> +static inline CallInst *extractMallocCall(Value *I) {
> >> +  return const_cast<CallInst*>(extractMallocCall((const
> >> 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);
> >> +static inline CallInst *extractMallocCallFromBitCast(Value *I) {
> >> +  return const_cast<CallInst*>(extractMallocCallFromBitCast((const
> >> Value*)I)); +}
> >>
> >>  /// isArrayMalloc - Returns the corresponding CallInst if the
> >> instruction /// is a call to malloc whose array size can be
> >> determined and the array size @@ -67,7 +101,7 @@
> >>  /// determined.
> >>  Value *getMallocArraySize(CallInst *CI, const TargetData *TD,
> >>                            bool LookThroughSExt = false);
> >> -
> >> +
> >>
> >>   
> >> //===----------------------------------------------------------------------===//
> >>  //  calloc Call Utility Functions.
> >> @@ -76,7 +110,9 @@
> >>  /// extractCallocCall - Returns the corresponding CallInst if the
> >> instruction /// is a calloc call.
> >>  const CallInst *extractCallocCall(const Value *I);
> >> -CallInst *extractCallocCall(Value *I);
> >> +static inline CallInst *extractCallocCall(Value *I) {
> >> +  return const_cast<CallInst*>(extractCallocCall((const
> >> Value*)I)); +}
> >>
> >>
> >>   
> >> //===----------------------------------------------------------------------===//
> >> @@ -90,6 +126,126 @@
> >>    return const_cast<CallInst*>(isFreeCall((const Value*)I));
> >>  }
> >>
> >> +
> >> +//===----------------------------------------------------------------------===//
> >> +//  Utility functions to compute size of objects.
> >> +//
> >> +
> >> +/// \brief Compute the size of the object pointed by Ptr. Returns
> >> true and the +/// object size in Size if successful, and false
> >> otherwise. +/// If RoundToAlign is true, then Size is rounded up to
> >> the aligment of allocas, +/// byval arguments, and global
> >> variables. +bool getObjectSize(const Value *Ptr, uint64_t &Size,
> >> const TargetData *TD,
> >> +                   bool RoundToAlign = false);
> >> +
> >> +
> >> +
> >> +typedef std::pair<APInt, APInt> SizeOffsetType;
> >> +
> >> +/// \brief Evaluate the size and offset of an object ponted by a
> >> Value* +/// statically. Fails if size or offset are not known at
> >> compile time. +class ObjectSizeOffsetVisitor
> >> +  : public InstVisitor<ObjectSizeOffsetVisitor, SizeOffsetType> {
> >> +
> >> +  const TargetData *TD;
> >> +  bool RoundToAlign;
> >> +  unsigned IntTyBits;
> >> +  APInt Zero;
> >> +
> >> +  APInt align(APInt Size, uint64_t Align);
> >> +
> >> +  SizeOffsetType unknown() {
> >> +    return std::make_pair(APInt(), APInt());
> >> +  }
> >> +
> >> +public:
> >> +  ObjectSizeOffsetVisitor(const TargetData *TD, LLVMContext
> >> &Context,
> >> +                          bool RoundToAlign = false);
> >> +
> >> +  SizeOffsetType compute(Value *V);
> >> +
> >> +  bool knownSize(SizeOffsetType &SizeOffset) {
> >> +    return SizeOffset.first.getBitWidth() > 1;
> >> +  }
> >> +
> >> +  bool knownOffset(SizeOffsetType &SizeOffset) {
> >> +    return SizeOffset.second.getBitWidth() > 1;
> >> +  }
> >> +
> >> +  bool bothKnown(SizeOffsetType &SizeOffset) {
> >> +    return knownSize(SizeOffset) && knownOffset(SizeOffset);
> >> +  }
> >> +
> >> +  SizeOffsetType visitAllocaInst(AllocaInst &I);
> >> +  SizeOffsetType visitArgument(Argument &A);
> >> +  SizeOffsetType visitCallSite(CallSite CS);
> >> +  SizeOffsetType visitConstantPointerNull(ConstantPointerNull&);
> >> +  SizeOffsetType visitExtractValueInst(ExtractValueInst &I);
> >> +  SizeOffsetType visitGEPOperator(GEPOperator &GEP);
> >> +  SizeOffsetType visitGlobalVariable(GlobalVariable &GV);
> >> +  SizeOffsetType visitIntToPtrInst(IntToPtrInst&);
> >> +  SizeOffsetType visitLoadInst(LoadInst &I);
> >> +  SizeOffsetType visitPHINode(PHINode&);
> >> +  SizeOffsetType visitSelectInst(SelectInst &I);
> >> +  SizeOffsetType visitUndefValue(UndefValue&);
> >> +  SizeOffsetType visitInstruction(Instruction &I);
> >> +};
> >> +
> >> +typedef std::pair<Value*, Value*> SizeOffsetEvalType;
> >> +typedef IRBuilder<true, TargetFolder> BuilderTy;
> >> +typedef DenseMap<const Value*, SizeOffsetEvalType> CacheMapTy;
> >> +typedef SmallPtrSet<const Value*, 8> PtrSetTy;
> >> +
> >> +
> >> +/// \brief Evaluate the size and offset of an object ponted by a
> >> Value*. +/// May create code to compute the result at run-time.
> >> +class ObjectSizeOffsetEvaluator
> >> +  : public InstVisitor<ObjectSizeOffsetEvaluator,
> >> SizeOffsetEvalType> { +
> >> +  const TargetData *TD;
> >> +  LLVMContext &Context;
> >> +  BuilderTy Builder;
> >> +  ObjectSizeOffsetVisitor Visitor;
> >> +  IntegerType *IntTy;
> >> +  Value *Zero;
> >> +  CacheMapTy CacheMap;
> >> +  PtrSetTy SeenVals;
> >> +
> >> +  SizeOffsetEvalType unknown() {
> >> +    return std::make_pair((Value*)0, (Value*)0);
> >> +  }
> >> +  SizeOffsetEvalType compute_(Value *V);
> >> +
> >> +public:
> >> +  ObjectSizeOffsetEvaluator(const TargetData *TD, LLVMContext
> >> &Context);
> >> +  SizeOffsetEvalType compute(Value *V);
> >> +
> >> +  bool knownSize(SizeOffsetEvalType &SizeOffset) {
> >> +    return SizeOffset.first;
> >> +  }
> >> +
> >> +  bool knownOffset(SizeOffsetEvalType &SizeOffset) {
> >> +    return SizeOffset.second;
> >> +  }
> >> +
> >> +  bool anyKnown(SizeOffsetEvalType &SizeOffset) {
> >> +    return knownSize(SizeOffset) || knownOffset(SizeOffset);
> >> +  }
> >> +
> >> +  bool bothKnown(SizeOffsetEvalType &SizeOffset) {
> >> +    return knownSize(SizeOffset) && knownOffset(SizeOffset);
> >> +  }
> >> +
> >> +  SizeOffsetEvalType visitAllocaInst(AllocaInst &I);
> >> +  SizeOffsetEvalType visitCallSite(CallSite CS);
> >> +  SizeOffsetEvalType visitGEPOperator(GEPOperator &GEP);
> >> +  SizeOffsetEvalType visitIntToPtrInst(IntToPtrInst&);
> >> +  SizeOffsetEvalType visitLoadInst(LoadInst &I);
> >> +  SizeOffsetEvalType visitPHINode(PHINode &PHI);
> >> +  SizeOffsetEvalType visitSelectInst(SelectInst &I);
> >> +  SizeOffsetEvalType visitInstruction(Instruction &I);
> >> +};
> >> +
> >>  } // End llvm namespace
> >>
> >>  #endif
> >>
> >> Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original) +++
> >> llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Thu Jun 21 10:45:28
> >> 2012 @@ -86,47 +86,10 @@ /// UnknownSize if unknown.
> >>  static uint64_t getObjectSize(const Value *V, const TargetData
> >> &TD, bool RoundToAlign = false) {
> >> -  Type *AccessTy;
> >> -  unsigned Align;
> >> -  if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
> >> -    if (!GV->hasDefinitiveInitializer())
> >> -      return AliasAnalysis::UnknownSize;
> >> -    AccessTy = GV->getType()->getElementType();
> >> -    Align = GV->getAlignment();
> >> -  } else if (const AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
> >> -    if (!AI->isArrayAllocation())
> >> -      AccessTy = AI->getType()->getElementType();
> >> -    else
> >> -      return AliasAnalysis::UnknownSize;
> >> -    Align = AI->getAlignment();
> >> -  } else if (const CallInst* CI = extractMallocCall(V)) {
> >> -    if (!RoundToAlign && !isArrayMalloc(V, &TD))
> >> -      // The size is the argument to the malloc call.
> >> -      if (const ConstantInt* C =
> >> dyn_cast<ConstantInt>(CI->getArgOperand(0)))
> >> -        return C->getZExtValue();
> >> -    return AliasAnalysis::UnknownSize;
> >> -  } else if (const Argument *A = dyn_cast<Argument>(V)) {
> >> -    if (A->hasByValAttr()) {
> >> -      AccessTy =
> >> cast<PointerType>(A->getType())->getElementType();
> >> -      Align = A->getParamAlignment();
> >> -    } else {
> >> -      return AliasAnalysis::UnknownSize;
> >> -    }
> >> -  } else {
> >> -    return AliasAnalysis::UnknownSize;
> >> -  }
> >> -
> >> -  if (!AccessTy->isSized())
> >> -    return AliasAnalysis::UnknownSize;
> >> -
> >> -  uint64_t Size = TD.getTypeAllocSize(AccessTy);
> >> -  // If there is an explicitly specified alignment, and we need to
> >> -  // take alignment into account, round up the size. (If the
> >> alignment
> >> -  // is implicit, getTypeAllocSize is sufficient.)
> >> -  if (RoundToAlign && Align)
> >> -    Size = RoundUpToAlignment(Size, Align);
> >> -
> >> -  return Size;
> >> +  uint64_t Size;
> >> +  if (getObjectSize(V, Size, &TD, RoundToAlign))
> >> +    return Size;
> >> +  return AliasAnalysis::UnknownSize;
> >>  }
> >>
> >>  /// isObjectSmallerThan - Return true if we can prove that the
> >> object specified
> >>
> >> Modified: llvm/trunk/lib/Analysis/IPA/GlobalsModRef.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/IPA/GlobalsModRef.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Analysis/IPA/GlobalsModRef.cpp (original) +++
> >> llvm/trunk/lib/Analysis/IPA/GlobalsModRef.cpp Thu Jun 21 10:45:28
> >> 2012 @@ -329,15 +329,8 @@ // Check the value being stored.
> >>        Value *Ptr = GetUnderlyingObject(SI->getOperand(0));
> >>
> >> -      if (isMalloc(Ptr)) {
> >> -        // Okay, easy case.
> >> -      } else if (CallInst *CI = dyn_cast<CallInst>(Ptr)) {
> >> -        Function *F = CI->getCalledFunction();
> >> -        if (!F || !F->isDeclaration()) return false;     // Too
> >> hard to analyze.
> >> -        if (F->getName() != "calloc") return false;   // Not
> >> calloc.
> >> -      } else {
> >> +      if (!isAllocLikeFn(Ptr))
> >>          return false;  // Too hard to analyze.
> >> -      }
> >>
> >>        // Analyze all uses of the allocation.  If any of them are
> >> used in a // non-simple way (e.g. stored to another global) bail
> >> out. @@ -454,19 +447,18 @@
> >>        for (inst_iterator II = inst_begin(SCC[i]->getFunction()),
> >>               E = inst_end(SCC[i]->getFunction());
> >>             II != E && FunctionEffect != ModRef; ++II)
> >> -        if (isa<LoadInst>(*II)) {
> >> +        if (LoadInst *LI = dyn_cast<LoadInst>(&*II)) {
> >>            FunctionEffect |= Ref;
> >> -          if (cast<LoadInst>(*II).isVolatile())
> >> +          if (LI->isVolatile())
> >>              // Volatile loads may have side-effects, so mark them
> >> as writing // memory (for example, a flag inside the processor).
> >>              FunctionEffect |= Mod;
> >> -        } else if (isa<StoreInst>(*II)) {
> >> +        } else if (StoreInst *SI = dyn_cast<StoreInst>(&*II)) {
> >>            FunctionEffect |= Mod;
> >> -          if (cast<StoreInst>(*II).isVolatile())
> >> +          if (SI->isVolatile())
> >>              // Treat volatile stores as reading memory somewhere.
> >>              FunctionEffect |= Ref;
> >> -        } else if (isMalloc(&cast<Instruction>(*II)) ||
> >> -                   isFreeCall(&cast<Instruction>(*II))) {
> >> +        } else if (isAllocationFn(&*II) || isFreeCall(&*II)) {
> >>            FunctionEffect |= ModRef;
> >>          } else if (IntrinsicInst *Intrinsic =
> >> dyn_cast<IntrinsicInst>(&*II)) { // The callgraph doesn't include
> >> intrinsic calls.
> >>
> >> Modified: llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryBuiltins.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Analysis/MemoryBuiltins.cpp (original) +++
> >> llvm/trunk/lib/Analysis/MemoryBuiltins.cpp Thu Jun 21 10:45:28 2012
> >> @@ -12,80 +12,165 @@ //
> >>   
> >> //===----------------------------------------------------------------------===//
> >>
> >> +#define DEBUG_TYPE "memory-builtins"
> >> +#include "llvm/ADT/Statistic.h"
> >> +#include "llvm/ADT/STLExtras.h"
> >>  #include "llvm/Analysis/MemoryBuiltins.h"
> >> -#include "llvm/Constants.h"
> >> +#include "llvm/GlobalVariable.h"
> >>  #include "llvm/Instructions.h"
> >> +#include "llvm/Intrinsics.h"
> >> +#include "llvm/Metadata.h"
> >>  #include "llvm/Module.h"
> >>  #include "llvm/Analysis/ValueTracking.h"
> >> +#include "llvm/Support/Debug.h"
> >> +#include "llvm/Support/MathExtras.h"
> >> +#include "llvm/Support/raw_ostream.h"
> >>  #include "llvm/Target/TargetData.h"
> >> +#include "llvm/Transforms/Utils/Local.h"
> >>  using namespace llvm;
> >>
> >> -//===----------------------------------------------------------------------===//
> >> -//  malloc Call Utility Functions.
> >> -//
> >> +enum AllocType {
> >> +  MallocLike         = 1<<0, // allocates
> >> +  CallocLike         = 1<<1, // allocates + bzero
> >> +  ReallocLike        = 1<<2, // reallocates
> >> +  StrDupLike         = 1<<3,
> >> +  AllocLike          = MallocLike | CallocLike | StrDupLike,
> >> +  AnyAlloc           = MallocLike | CallocLike | ReallocLike |
> >> StrDupLike +};
> >> +
> >> +struct AllocFnsTy {
> >> +  const char *Name;
> >> +  AllocType AllocTy;
> >> +  unsigned char NumParams;
> >> +  // First and Second size parameters (or -1 if unused)
> >> +  unsigned char FstParam, SndParam;
> >> +};
> >> +
> >> +static const AllocFnsTy AllocationFnData[] = {
> >> +  {"malloc",         MallocLike,  1, 0,  -1},
> >> +  {"valloc",         MallocLike,  1, 0,  -1},
> >> +  {"_Znwj",          MallocLike,  1, 0,  -1}, // operator
> >> new(unsigned int)
> >> +  {"_Znwm",          MallocLike,  1, 0,  -1}, // operator
> >> new(unsigned long)
> >> +  {"_Znaj",          MallocLike,  1, 0,  -1}, // operator
> >> new[](unsigned int)
> >> +  {"_Znam",          MallocLike,  1, 0,  -1}, // operator
> >> new[](unsigned long)
> >> +  {"posix_memalign", MallocLike,  3, 2,  -1},
> >> +  {"calloc",         CallocLike,  2, 0,  1},
> >> +  {"realloc",        ReallocLike, 2, 1,  -1},
> >> +  {"reallocf",       ReallocLike, 2, 1,  -1},
> >> +  {"strdup",         StrDupLike,  1, -1, -1},
> >> +  {"strndup",        StrDupLike,  2, -1, -1}
> >> +};
> >> +
> >> +
> >> +static Function *getCalledFunction(const Value *V, bool
> >> LookThroughBitCast) {
> >> +  if (LookThroughBitCast)
> >> +    V = V->stripPointerCasts();
> >> +  const CallInst *CI = dyn_cast<CallInst>(V);
> >> +  if (!CI)
> >> +    return 0;
> >>
> >> -/// isMalloc - Returns true if the value is either a malloc call
> >> or a -/// bitcast of the result of a malloc call.
> >> -bool llvm::isMalloc(const Value *I) {
> >> -  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
> >> +  Function *Callee = CI->getCalledFunction();
> >> +  if (!Callee || !Callee->isDeclaration())
> >> +    return 0;
> >> +  return Callee;
> >>  }
> >>
> >> -static bool isMallocCall(const CallInst *CI) {
> >> -  if (!CI)
> >> -    return false;
> >> +/// \brief Returns the allocation data for the given value if it
> >> is a call to a +/// known allocation function, and NULL otherwise.
> >> +static const AllocFnsTy *getAllocationData(const Value *V,
> >> AllocType AllocTy,
> >> +                                           bool
> >> LookThroughBitCast = false) {
> >> +  Function *Callee = getCalledFunction(V, LookThroughBitCast);
> >> +  if (!Callee)
> >> +    return 0;
> >>
> >> -  Function *Callee = CI->getCalledFunction();
> >> -  if (Callee == 0 || !Callee->isDeclaration())
> >> -    return false;
> >> -  if (Callee->getName() != "malloc" &&
> >> -      Callee->getName() != "_Znwj" && // operator new(unsigned
> >> int)
> >> -      Callee->getName() != "_Znwm" && // operator new(unsigned
> >> long)
> >> -      Callee->getName() != "_Znaj" && // operator new[](unsigned
> >> int)
> >> -      Callee->getName() != "_Znam")   // operator new[](unsigned
> >> long)
> >> -    return false;
> >> +  unsigned i = 0;
> >> +  bool found = false;
> >> +  for ( ; i < array_lengthof(AllocationFnData); ++i) {
> >> +    if (Callee->getName() == AllocationFnData[i].Name) {
> >> +      found = true;
> >> +      break;
> >> +    }
> >> +  }
> >> +  if (!found)
> >> +    return 0;
> >>
> >> -  // Check malloc prototype.
> >> -  // FIXME: workaround for PR5130, this will be obsolete when a
> >> nobuiltin
> >> -  // attribute will exist.
> >> +  const AllocFnsTy *FnData = &AllocationFnData[i];
> >> +  if ((FnData->AllocTy & AllocTy) == 0)
> >> +    return 0;
> >> +
> >> +  // Check function prototype.
> >> +  // FIXME: Check the nobuiltin metadata?? (PR5130)
> >> +  unsigned FstParam = FnData->FstParam;
> >> +  unsigned SndParam = FnData->SndParam;
> >>    FunctionType *FTy = Callee->getFunctionType();
> >> -  return FTy->getReturnType() ==
> >> Type::getInt8PtrTy(FTy->getContext()) &&
> >> -         FTy->getNumParams() == 1 &&
> >> -         (FTy->getParamType(0)->isIntegerTy(32) ||
> >> -          FTy->getParamType(0)->isIntegerTy(64));
> >> +
> >> +  if (FTy->getReturnType() ==
> >> Type::getInt8PtrTy(FTy->getContext()) &&
> >> +      FTy->getNumParams() == FnData->NumParams &&
> >> +      (FstParam == (unsigned char)-1 ||
> >> +       (FTy->getParamType(FstParam)->isIntegerTy(32) ||
> >> +        FTy->getParamType(FstParam)->isIntegerTy(64))) &&
> >> +      (SndParam == (unsigned char)-1 ||
> >> +       FTy->getParamType(SndParam)->isIntegerTy(32) ||
> >> +       FTy->getParamType(SndParam)->isIntegerTy(64)))
> >> +    return FnData;
> >> +  return 0;
> >>  }
> >>
> >> -/// 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<CallInst>(I);
> >> -  return (isMallocCall(CI)) ? CI : NULL;
> >> +static bool hasNoAliasAttr(const Value *V, bool
> >> LookThroughBitCast) {
> >> +  Function *Callee = getCalledFunction(V, LookThroughBitCast);
> >> +  return Callee && Callee->hasFnAttr(Attribute::NoAlias);
> >>  }
> >>
> >> -CallInst *llvm::extractMallocCall(Value *I) {
> >> -  CallInst *CI = dyn_cast<CallInst>(I);
> >> -  return (isMallocCall(CI)) ? CI : NULL;
> >> +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates or +/// reallocates memory (either malloc, calloc,
> >> realloc, or strdup like). +bool llvm::isAllocationFn(const Value
> >> *V, bool LookThroughBitCast) {
> >> +  return getAllocationData(V, AnyAlloc, LookThroughBitCast);
> >>  }
> >>
> >> -static bool isBitCastOfMallocCall(const BitCastInst *BCI) {
> >> -  if (!BCI)
> >> -    return false;
> >> -
> >> -  return isMallocCall(dyn_cast<CallInst>(BCI->getOperand(0)));
> >> +/// \brief Tests if a value is a call to a function that returns a
> >> NoAlias +/// pointer (including malloc/calloc/strdup-like
> >> functions). +bool llvm::isNoAliasFn(const Value *V, bool
> >> LookThroughBitCast) {
> >> +  return isAllocLikeFn(V, LookThroughBitCast) ||
> >> +         hasNoAliasAttr(V, LookThroughBitCast);
> >>  }
> >>
> >> -/// 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<BitCastInst>(I);
> >> -  return (isBitCastOfMallocCall(BCI)) ?
> >> cast<CallInst>(BCI->getOperand(0))
> >> -                                      : NULL;
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates +/// uninitialized memory (such as malloc).
> >> +bool llvm::isMallocLikeFn(const Value *V, bool
> >> LookThroughBitCast) {
> >> +  return getAllocationData(V, MallocLike, LookThroughBitCast);
> >> +}
> >> +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates +/// zero-filled memory (such as calloc).
> >> +bool llvm::isCallocLikeFn(const Value *V, bool
> >> LookThroughBitCast) {
> >> +  return getAllocationData(V, CallocLike, LookThroughBitCast);
> >> +}
> >> +
> >> +/// \brief Tests if a value is a call to a library function that
> >> allocates +/// memory (either malloc, calloc, or strdup like).
> >> +bool llvm::isAllocLikeFn(const Value *V, bool LookThroughBitCast)
> >> {
> >> +  return getAllocationData(V, AllocLike, LookThroughBitCast);
> >>  }
> >>
> >> +/// \brief Tests if a value is a call to a library function that
> >> reallocates +/// memory (such as realloc).
> >> +bool llvm::isReallocLikeFn(const Value *V, bool
> >> LookThroughBitCast) {
> >> +  return getAllocationData(V, ReallocLike, LookThroughBitCast);
> >> +}
> >> +
> >> +/// 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) {
> >> +  return isMallocLikeFn(I) ? cast<CallInst>(I) : 0;
> >> +}
> >> +
> >> +/// extractMallocCallFromBitCast - Returns the corresponding
> >> CallInst if the +/// instruction is a bitcast of the result of a
> >> malloc call. const CallInst
> >> *llvm::extractMallocCallFromBitCast(const Value *I) { const
> >> BitCastInst *BCI = dyn_cast<BitCastInst>(I);
> >> -  return (isBitCastOfMallocCall(BCI)) ?
> >> cast<CallInst>(BCI->getOperand(0))
> >> -                                      : NULL;
> >> +  return BCI ? extractMallocCall(BCI->getOperand(0)) : 0;
> >>  }
> >>
> >>  static Value *computeArraySize(const CallInst *CI, const
> >> TargetData *TD, @@ -134,7 +219,7 @@
> >>  ///   1: PointerType is the bitcast's result type.
> >>  ///  >1: Unique PointerType cannot be determined, return NULL.
> >>  PointerType *llvm::getMallocType(const CallInst *CI) {
> >> -  assert(isMalloc(CI) && "getMallocType and not malloc call");
> >> +  assert(isMallocLikeFn(CI) && "getMallocType and not malloc
> >> call");
> >>
> >>    PointerType *MallocType = NULL;
> >>    unsigned NumOfBitCastUses = 0;
> >> @@ -176,53 +261,17 @@
> >>  /// determined.
> >>  Value *llvm::getMallocArraySize(CallInst *CI, const TargetData
> >> *TD, bool LookThroughSExt) {
> >> -  assert(isMalloc(CI) && "getMallocArraySize and not malloc
> >> call");
> >> +  assert(isMallocLikeFn(CI) && "getMallocArraySize and not malloc
> >> call"); return computeArraySize(CI, TD, LookThroughSExt);
> >>  }
> >>
> >>
> >> -//===----------------------------------------------------------------------===//
> >> -//  calloc Call Utility Functions.
> >> -//
> >> -
> >> -static bool isCallocCall(const CallInst *CI) {
> >> -  if (!CI)
> >> -    return false;
> >> -
> >> -  Function *Callee = CI->getCalledFunction();
> >> -  if (Callee == 0 || !Callee->isDeclaration())
> >> -    return false;
> >> -  if (Callee->getName() != "calloc")
> >> -    return false;
> >> -
> >> -  // Check malloc prototype.
> >> -  // FIXME: workaround for PR5130, this will be obsolete when a
> >> nobuiltin
> >> -  // attribute exists.
> >> -  FunctionType *FTy = Callee->getFunctionType();
> >> -  return FTy->getReturnType() ==
> >> Type::getInt8PtrTy(FTy->getContext()) &&
> >> -  FTy->getNumParams() == 2 &&
> >> -  ((FTy->getParamType(0)->isIntegerTy(32) &&
> >> -    FTy->getParamType(1)->isIntegerTy(32)) ||
> >> -   (FTy->getParamType(0)->isIntegerTy(64) &&
> >> -    FTy->getParamType(1)->isIntegerTy(64)));
> >> -}
> >> -
> >>  /// extractCallocCall - Returns the corresponding CallInst if the
> >> instruction /// is a calloc call.
> >>  const CallInst *llvm::extractCallocCall(const Value *I) {
> >> -  const CallInst *CI = dyn_cast<CallInst>(I);
> >> -  return isCallocCall(CI) ? CI : 0;
> >> +  return isCallocLikeFn(I) ? cast<CallInst>(I) : 0;
> >>  }
> >>
> >> -CallInst *llvm::extractCallocCall(Value *I) {
> >> -  CallInst *CI = dyn_cast<CallInst>(I);
> >> -  return isCallocCall(CI) ? CI : 0;
> >> -}
> >> -
> >> -
> >> -//===----------------------------------------------------------------------===//
> >> -//  free Call Utility Functions.
> >> -//
> >>
> >>  /// isFreeCall - Returns non-null if the value is a call to the
> >> builtin free() const CallInst *llvm::isFreeCall(const Value *I) {
> >> @@ -251,3 +300,388 @@
> >>
> >>    return CI;
> >>  }
> >> +
> >> +
> >> +
> >> +//===----------------------------------------------------------------------===//
> >> +//  Utility functions to compute size of objects.
> >> +//
> >> +
> >> +
> >> +/// \brief Compute the size of the object pointed by Ptr. Returns
> >> true and the +/// object size in Size if successful, and false
> >> otherwise. +/// If RoundToAlign is true, then Size is rounded up to
> >> the aligment of allocas, +/// byval arguments, and global
> >> variables. +bool llvm::getObjectSize(const Value *Ptr, uint64_t
> >> &Size, const TargetData *TD,
> >> +                         bool RoundToAlign) {
> >> +  if (!TD)
> >> +    return false;
> >> +
> >> +  ObjectSizeOffsetVisitor Visitor(TD, Ptr->getContext(),
> >> RoundToAlign);
> >> +  SizeOffsetType Data = Visitor.compute(const_cast<Value*>(Ptr));
> >> +  if (!Visitor.bothKnown(Data))
> >> +    return false;
> >> +
> >> +  APInt ObjSize = Data.first, Offset = Data.second;
> >> +  // check for overflow
> >> +  if (Offset.slt(0) || ObjSize.ult(Offset))
> >> +    Size = 0;
> >> +  else
> >> +    Size = (ObjSize - Offset).getZExtValue();
> >> +  return true;
> >> +}
> >> +
> >> +
> >> +STATISTIC(ObjectVisitorArgument,
> >> +          "Number of arguments with unsolved size and offset");
> >> +STATISTIC(ObjectVisitorLoad,
> >> +          "Number of load instructions with unsolved size and
> >> offset"); +
> >> +
> >> +APInt ObjectSizeOffsetVisitor::align(APInt Size, uint64_t Align) {
> >> +  if (RoundToAlign && Align)
> >> +    return APInt(IntTyBits,
> >> RoundUpToAlignment(Size.getZExtValue(), Align));
> >> +  return Size;
> >> +}
> >> +
> >> +ObjectSizeOffsetVisitor::ObjectSizeOffsetVisitor(const TargetData
> >> *TD,
> >> +                                                 LLVMContext
> >> &Context,
> >> +                                                 bool
> >> RoundToAlign) +: TD(TD), RoundToAlign(RoundToAlign) {
> >> +  IntegerType *IntTy = TD->getIntPtrType(Context);
> >> +  IntTyBits = IntTy->getBitWidth();
> >> +  Zero = APInt::getNullValue(IntTyBits);
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::compute(Value *V) {
> >> +  V = V->stripPointerCasts();
> >> +
> >> +  if (GEPOperator *GEP = dyn_cast<GEPOperator>(V))
> >> +    return visitGEPOperator(*GEP);
> >> +  if (Instruction *I = dyn_cast<Instruction>(V))
> >> +    return visit(*I);
> >> +  if (Argument *A = dyn_cast<Argument>(V))
> >> +    return visitArgument(*A);
> >> +  if (ConstantPointerNull *P = dyn_cast<ConstantPointerNull>(V))
> >> +    return visitConstantPointerNull(*P);
> >> +  if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
> >> +    return visitGlobalVariable(*GV);
> >> +  if (UndefValue *UV = dyn_cast<UndefValue>(V))
> >> +    return visitUndefValue(*UV);
> >> +  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
> >> +    if (CE->getOpcode() == Instruction::IntToPtr)
> >> +      return unknown(); // clueless
> >> +
> >> +  DEBUG(dbgs() << "ObjectSizeOffsetVisitor::compute() unhandled
> >> value: " << *V
> >> +        << '\n');
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst
> >> &I) {
> >> +  if (!I.getAllocatedType()->isSized())
> >> +    return unknown();
> >> +
> >> +  APInt Size(IntTyBits,
> >> TD->getTypeAllocSize(I.getAllocatedType()));
> >> +  if (!I.isArrayAllocation())
> >> +    return std::make_pair(align(Size, I.getAlignment()), Zero);
> >> +
> >> +  Value *ArraySize = I.getArraySize();
> >> +  if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
> >> +    Size *= C->getValue().zextOrSelf(IntTyBits);
> >> +    return std::make_pair(align(Size, I.getAlignment()), Zero);
> >> +  }
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::visitArgument(Argument
> >> &A) {
> >> +  // no interprocedural analysis is done at the moment
> >> +  if (!A.hasByValAttr()) {
> >> +    ++ObjectVisitorArgument;
> >> +    return unknown();
> >> +  }
> >> +  PointerType *PT = cast<PointerType>(A.getType());
> >> +  APInt Size(IntTyBits,
> >> TD->getTypeAllocSize(PT->getElementType()));
> >> +  return std::make_pair(align(Size, A.getParamAlignment()), Zero);
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite
> >> CS) {
> >> +  const AllocFnsTy *FnData =
> >> getAllocationData(CS.getInstruction(), AnyAlloc);
> >> +  if (!FnData)
> >> +    return unknown();
> >> +
> >> +  // handle strdup-like functions separately
> >> +  if (FnData->AllocTy == StrDupLike) {
> >> +    // TODO
> >> +    return unknown();
> >> +  }
> >> +
> >> +  ConstantInt *Arg =
> >> dyn_cast<ConstantInt>(CS.getArgument(FnData->FstParam));
> >> +  if (!Arg)
> >> +    return unknown();
> >> +
> >> +  APInt Size = Arg->getValue();
> >> +  // size determined by just 1 parameter
> >> +  if (FnData->SndParam == (unsigned char)-1)
> >> +    return std::make_pair(Size, Zero);
> >> +
> >> +  Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->SndParam));
> >> +  if (!Arg)
> >> +    return unknown();
> >> +
> >> +  Size *= Arg->getValue();
> >> +  return std::make_pair(Size, Zero);
> >> +
> >> +  // TODO: handle more standard functions (+ wchar cousins):
> >> +  // - strdup / strndup
> >> +  // - strcpy / strncpy
> >> +  // - strcat / strncat
> >> +  // - memcpy / memmove
> >> +  // - strcat / strncat
> >> +  // - memset
> >> +}
> >> +
> >> +SizeOffsetType
> >> +ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull&)
> >> {
> >> +  return std::make_pair(Zero, Zero);
> >> +}
> >> +
> >> +SizeOffsetType
> >> +ObjectSizeOffsetVisitor::visitExtractValueInst(ExtractValueInst&)
> >> {
> >> +  // Easy cases were already folded by previous passes.
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType
> >> ObjectSizeOffsetVisitor::visitGEPOperator(GEPOperator &GEP) {
> >> +  SizeOffsetType PtrData = compute(GEP.getPointerOperand());
> >> +  if (!bothKnown(PtrData) || !GEP.hasAllConstantIndices())
> >> +    return unknown();
> >> +
> >> +  SmallVector<Value*, 8> Ops(GEP.idx_begin(), GEP.idx_end());
> >> +  APInt
> >> Offset(IntTyBits,TD->getIndexedOffset(GEP.getPointerOperandType(),Ops));
> >> +  return std::make_pair(PtrData.first, PtrData.second + Offset);
> >> +}
> >> +
> >> +SizeOffsetType
> >> ObjectSizeOffsetVisitor::visitGlobalVariable(GlobalVariable &GV){
> >> +  if (!GV.hasDefinitiveInitializer())
> >> +    return unknown();
> >> +
> >> +  APInt Size(IntTyBits,
> >> TD->getTypeAllocSize(GV.getType()->getElementType()));
> >> +  return std::make_pair(align(Size, GV.getAlignment()), Zero);
> >> +}
> >> +
> >> +SizeOffsetType
> >> ObjectSizeOffsetVisitor::visitIntToPtrInst(IntToPtrInst&) {
> >> +  // clueless
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::visitLoadInst(LoadInst&) {
> >> +  ++ObjectVisitorLoad;
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::visitPHINode(PHINode&) {
> >> +  // too complex to analyze statically.
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType ObjectSizeOffsetVisitor::visitSelectInst(SelectInst
> >> &I) {
> >> +  SizeOffsetType TrueSide  = compute(I.getTrueValue());
> >> +  SizeOffsetType FalseSide = compute(I.getFalseValue());
> >> +  if (bothKnown(TrueSide) && bothKnown(FalseSide) && TrueSide ==
> >> FalseSide)
> >> +    return TrueSide;
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetType
> >> ObjectSizeOffsetVisitor::visitUndefValue(UndefValue&) {
> >> +  return std::make_pair(Zero, Zero);
> >> +}
> >> +
> >> +SizeOffsetType
> >> ObjectSizeOffsetVisitor::visitInstruction(Instruction &I) {
> >> +  DEBUG(dbgs() << "ObjectSizeOffsetVisitor unknown instruction:"
> >> << I << '\n');
> >> +  return unknown();
> >> +}
> >> +
> >> +
> >> +ObjectSizeOffsetEvaluator::ObjectSizeOffsetEvaluator(const
> >> TargetData *TD,
> >> +                                                     LLVMContext
> >> &Context) +: TD(TD), Context(Context), Builder(Context,
> >> TargetFolder(TD)), +Visitor(TD, Context) {
> >> +  IntTy = TD->getIntPtrType(Context);
> >> +  Zero = ConstantInt::get(IntTy, 0);
> >> +}
> >> +
> >> +SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute(Value *V) {
> >> +  SizeOffsetEvalType Result = compute_(V);
> >> +
> >> +  if (!bothKnown(Result)) {
> >> +    // erase everything that was computed in this iteration from
> >> the cache, so
> >> +    // that no dangling references are left behind. We could be a
> >> bit smarter if
> >> +    // we kept a dependency graph. It's probably not worth the
> >> complexity.
> >> +    for (PtrSetTy::iterator I=SeenVals.begin(), E=SeenVals.end();
> >> I != E; ++I) {
> >> +      CacheMapTy::iterator CacheIt = CacheMap.find(*I);
> >> +      // non-computable results can be safely cached
> >> +      if (CacheIt != CacheMap.end() && anyKnown(CacheIt->second))
> >> +        CacheMap.erase(CacheIt);
> >> +    }
> >> +  }
> >> +
> >> +  SeenVals.clear();
> >> +  return Result;
> >> +}
> >> +
> >> +SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute_(Value *V) {
> >> +  SizeOffsetType Const = Visitor.compute(V);
> >> +  if (Visitor.bothKnown(Const))
> >> +    return std::make_pair(ConstantInt::get(Context, Const.first),
> >> +                          ConstantInt::get(Context,
> >> Const.second)); +
> >> +  V = V->stripPointerCasts();
> >> +
> >> +  // check cache
> >> +  CacheMapTy::iterator CacheIt = CacheMap.find(V);
> >> +  if (CacheIt != CacheMap.end())
> >> +    return CacheIt->second;
> >> +
> >> +  // always generate code immediately before the instruction being
> >> +  // processed, so that the generated code dominates the same BBs
> >> +  Instruction *PrevInsertPoint = Builder.GetInsertPoint();
> >> +  if (Instruction *I = dyn_cast<Instruction>(V))
> >> +    Builder.SetInsertPoint(I);
> >> +
> >> +  // record the pointers that were handled in this run, so that
> >> they can be
> >> +  // cleaned later if something fails
> >> +  SeenVals.insert(V);
> >> +
> >> +  // now compute the size and offset
> >> +  SizeOffsetEvalType Result;
> >> +  if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
> >> +    Result = visitGEPOperator(*GEP);
> >> +  } else if (Instruction *I = dyn_cast<Instruction>(V)) {
> >> +    Result = visit(*I);
> >> +  } else if (isa<Argument>(V) ||
> >> +             (isa<ConstantExpr>(V) &&
> >> +              cast<ConstantExpr>(V)->getOpcode() ==
> >> Instruction::IntToPtr) ||
> >> +             isa<GlobalVariable>(V)) {
> >> +    // ignore values where we cannot do more than what
> >> ObjectSizeVisitor can
> >> +    Result = unknown();
> >> +  } else {
> >> +    DEBUG(dbgs() << "ObjectSizeOffsetEvaluator::compute()
> >> unhandled value: "
> >> +          << *V << '\n');
> >> +    Result = unknown();
> >> +  }
> >> +
> >> +  if (PrevInsertPoint)
> >> +    Builder.SetInsertPoint(PrevInsertPoint);
> >> +
> >> +  // Don't reuse CacheIt since it may be invalid at this point.
> >> +  CacheMap[V] = Result;
> >> +  return Result;
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) {
> >> +  if (!I.getAllocatedType()->isSized())
> >> +    return unknown();
> >> +
> >> +  // must be a VLA
> >> +  assert(I.isArrayAllocation());
> >> +  Value *ArraySize = I.getArraySize();
> >> +  Value *Size = ConstantInt::get(ArraySize->getType(),
> >> +
> >> TD->getTypeAllocSize(I.getAllocatedType()));
> >> +  Size = Builder.CreateMul(Size, ArraySize);
> >> +  return std::make_pair(Size, Zero);
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> ObjectSizeOffsetEvaluator::visitCallSite(CallSite CS) {
> >> +  const AllocFnsTy *FnData =
> >> getAllocationData(CS.getInstruction(), AnyAlloc);
> >> +  if (!FnData)
> >> +    return unknown();
> >> +
> >> +  // handle strdup-like functions separately
> >> +  if (FnData->AllocTy == StrDupLike) {
> >> +    // TODO
> >> +    return unknown();
> >> +  }
> >> +
> >> +  Value *FirstArg  = CS.getArgument(FnData->FstParam);
> >> +  if (FnData->SndParam == (unsigned char)-1)
> >> +    return std::make_pair(FirstArg, Zero);
> >> +
> >> +  Value *SecondArg = CS.getArgument(FnData->SndParam);
> >> +  Value *Size = Builder.CreateMul(FirstArg, SecondArg);
> >> +  return std::make_pair(Size, Zero);
> >> +
> >> +  // TODO: handle more standard functions (+ wchar cousins):
> >> +  // - strdup / strndup
> >> +  // - strcpy / strncpy
> >> +  // - strcat / strncat
> >> +  // - memcpy / memmove
> >> +  // - strcat / strncat
> >> +  // - memset
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> +ObjectSizeOffsetEvaluator::visitGEPOperator(GEPOperator &GEP) {
> >> +  SizeOffsetEvalType PtrData = compute_(GEP.getPointerOperand());
> >> +  if (!bothKnown(PtrData))
> >> +    return unknown();
> >> +
> >> +  Value *Offset = EmitGEPOffset(&Builder, *TD, &GEP);
> >> +  Offset = Builder.CreateAdd(PtrData.second, Offset);
> >> +  return std::make_pair(PtrData.first, Offset);
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> ObjectSizeOffsetEvaluator::visitIntToPtrInst(IntToPtrInst&) {
> >> +  // clueless
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> ObjectSizeOffsetEvaluator::visitLoadInst(LoadInst&) {
> >> +  return unknown();
> >> +}
> >> +
> >> +SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitPHINode(PHINode
> >> &PHI) {
> >> +  // create 2 PHIs: one for size and another for offset
> >> +  PHINode *SizePHI   = Builder.CreatePHI(IntTy,
> >> PHI.getNumIncomingValues());
> >> +  PHINode *OffsetPHI = Builder.CreatePHI(IntTy,
> >> PHI.getNumIncomingValues()); +
> >> +  // insert right away in the cache to handle recursive PHIs
> >> +  CacheMap[&PHI] = std::make_pair(SizePHI, OffsetPHI);
> >> +
> >> +  // compute offset/size for each PHI incoming pointer
> >> +  for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e;
> >> ++i) { +
> >> Builder.SetInsertPoint(PHI.getIncomingBlock(i)->getFirstInsertionPt());
> >> +    SizeOffsetEvalType EdgeData =
> >> compute_(PHI.getIncomingValue(i)); +
> >> +    if (!bothKnown(EdgeData)) {
> >> +      OffsetPHI->replaceAllUsesWith(UndefValue::get(IntTy));
> >> +      OffsetPHI->eraseFromParent();
> >> +      SizePHI->replaceAllUsesWith(UndefValue::get(IntTy));
> >> +      SizePHI->eraseFromParent();
> >> +      return unknown();
> >> +    }
> >> +    SizePHI->addIncoming(EdgeData.first, PHI.getIncomingBlock(i));
> >> +    OffsetPHI->addIncoming(EdgeData.second,
> >> PHI.getIncomingBlock(i));
> >> +  }
> >> +  return std::make_pair(SizePHI, OffsetPHI);
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> ObjectSizeOffsetEvaluator::visitSelectInst(SelectInst &I) {
> >> +  SizeOffsetEvalType TrueSide  = compute_(I.getTrueValue());
> >> +  SizeOffsetEvalType FalseSide = compute_(I.getFalseValue());
> >> +
> >> +  if (!bothKnown(TrueSide) || !bothKnown(FalseSide))
> >> +    return unknown();
> >> +  if (TrueSide == FalseSide)
> >> +    return TrueSide;
> >> +
> >> +  Value *Size = Builder.CreateSelect(I.getCondition(),
> >> TrueSide.first,
> >> +                                     FalseSide.first);
> >> +  Value *Offset = Builder.CreateSelect(I.getCondition(),
> >> TrueSide.second,
> >> +                                       FalseSide.second);
> >> +  return std::make_pair(Size, Offset);
> >> +}
> >> +
> >> +SizeOffsetEvalType
> >> ObjectSizeOffsetEvaluator::visitInstruction(Instruction &I) {
> >> +  DEBUG(dbgs() << "ObjectSizeOffsetEvaluator unknown instruction:"
> >> << I <<'\n');
> >> +  return unknown();
> >> +}
> >>
> >> Modified: llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp (original)
> >> +++ llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp Thu Jun 21
> >> 10:45:28 2012 @@ -474,8 +474,7 @@ // a subsequent bitcast of the
> >> malloc call result.  There can be stores to // the malloced memory
> >> between the malloc call and its bitcast uses, and we // need to
> >> continue scanning until the malloc call.
> >> -    if (isa<AllocaInst>(Inst) ||
> >> -        (isa<CallInst>(Inst) && extractMallocCall(Inst))) {
> >> +    if (isa<AllocaInst>(Inst) || isNoAliasFn(Inst)) {
> >>        const Value *AccessPtr = GetUnderlyingObject(MemLoc.Ptr,
> >> TD);
> >>
> >>        if (AccessPtr == Inst || AA->isMustAlias(Inst, AccessPtr))
> >>
> >> Modified:
> >> llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
> >> (original) +++
> >> llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp Thu Jun
> >> 21 10:45:28 2012 @@ -172,7 +172,7 @@ Instruction
> >> *InstCombiner::visitCallInst(CallInst &CI) { if (isFreeCall(&CI))
> >> return visitFree(CI);
> >> -  if (extractMallocCall(&CI) || extractCallocCall(&CI))
> >> +  if (isAllocLikeFn(&CI))
> >>      return visitMalloc(CI);
> >>
> >>    // If the caller function is nounwind, mark the call as
> >> nounwind, even if the @@ -246,84 +246,10 @@
> >>    switch (II->getIntrinsicID()) {
> >>    default: break;
> >>    case Intrinsic::objectsize: {
> >> -    // We need target data for just about everything so depend on
> >> it.
> >> -    if (!TD) return 0;
> >> -
> >> -    Type *ReturnTy = CI.getType();
> >> -    uint64_t DontKnow = II->getArgOperand(1) ==
> >> Builder->getTrue() ? 0 : -1ULL; -
> >> -    // Get to the real allocated thing and offset as fast as
> >> possible.
> >> -    Value *Op1 = II->getArgOperand(0)->stripPointerCasts();
> >> -
> >> -    uint64_t Offset = 0;
> >> -    uint64_t Size = -1ULL;
> >> -
> >> -    // Try to look through constant GEPs.
> >> -    if (GEPOperator *GEP = dyn_cast<GEPOperator>(Op1)) {
> >> -      if (!GEP->hasAllConstantIndices()) return 0;
> >> -
> >> -      // Get the current byte offset into the thing. Use the
> >> original
> >> -      // operand in case we're looking through a bitcast.
> >> -      SmallVector<Value*, 8> Ops(GEP->idx_begin(),
> >> GEP->idx_end());
> >> -      if (!GEP->getPointerOperandType()->isPointerTy())
> >> -        return 0;
> >> -      Offset = TD->getIndexedOffset(GEP->getPointerOperandType(),
> >> Ops); -
> >> -      Op1 = GEP->getPointerOperand()->stripPointerCasts();
> >> -
> >> -      // Make sure we're not a constant offset from an external
> >> -      // global.
> >> -      if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op1))
> >> -        if (!GV->hasDefinitiveInitializer()) return 0;
> >> -    }
> >> -
> >> -    // If we've stripped down to a single global variable that we
> >> -    // can know the size of then just return that.
> >> -    if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op1)) {
> >> -      if (GV->hasDefinitiveInitializer()) {
> >> -        Constant *C = GV->getInitializer();
> >> -        Size = TD->getTypeAllocSize(C->getType());
> >> -      } else {
> >> -        // Can't determine size of the GV.
> >> -        Constant *RetVal = ConstantInt::get(ReturnTy, DontKnow);
> >> -        return ReplaceInstUsesWith(CI, RetVal);
> >> -      }
> >> -    } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Op1)) {
> >> -      // Get alloca size.
> >> -      if (AI->getAllocatedType()->isSized()) {
> >> -        Size = TD->getTypeAllocSize(AI->getAllocatedType());
> >> -        if (AI->isArrayAllocation()) {
> >> -          const ConstantInt *C =
> >> dyn_cast<ConstantInt>(AI->getArraySize());
> >> -          if (!C) return 0;
> >> -          Size *= C->getZExtValue();
> >> -        }
> >> -      }
> >> -    } else if (CallInst *MI = extractMallocCall(Op1)) {
> >> -      // Get allocation size.
> >> -      Value *Arg = MI->getArgOperand(0);
> >> -      if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg))
> >> -          Size = CI->getZExtValue();
> >> -
> >> -    } else if (CallInst *MI = extractCallocCall(Op1)) {
> >> -      // Get allocation size.
> >> -      Value *Arg1 = MI->getArgOperand(0);
> >> -      Value *Arg2 = MI->getArgOperand(1);
> >> -      if (ConstantInt *CI1 = dyn_cast<ConstantInt>(Arg1))
> >> -        if (ConstantInt *CI2 = dyn_cast<ConstantInt>(Arg2))
> >> -          Size = (CI1->getValue() *
> >> CI2->getValue()).getZExtValue();
> >> -    }
> >> -
> >> -    // Do not return "I don't know" here. Later optimization
> >> passes could
> >> -    // make it possible to evaluate objectsize to a constant.
> >> -    if (Size == -1ULL)
> >> -      return 0;
> >> -
> >> -    if (Size < Offset) {
> >> -      // Out of bound reference? Negative index normalized to
> >> large
> >> -      // index? Just return "I don't know".
> >> -      return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy,
> >> DontKnow));
> >> -    }
> >> -    return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy,
> >> Size-Offset));
> >> +    uint64_t Size;
> >> +    if (getObjectSize(II->getArgOperand(0), Size, TD))
> >> +      return ReplaceInstUsesWith(CI,
> >> ConstantInt::get(CI.getType(), Size));
> >> +    return 0;
> >>    }
> >>    case Intrinsic::bswap:
> >>      // bswap(bswap(x)) -> x
> >> @@ -768,7 +694,7 @@
> >>      TerminatorInst *TI = II->getParent()->getTerminator();
> >>      bool CannotRemove = false;
> >>      for (++BI; &*BI != TI; ++BI) {
> >> -      if (isa<AllocaInst>(BI) || isMalloc(BI)) {
> >> +      if (isa<AllocaInst>(BI)) {
> >>          CannotRemove = true;
> >>          break;
> >>        }
> >>
> >> Modified:
> >> llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp
> >> (original) +++
> >> llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp Thu
> >> Jun 21 10:45:28 2012 @@ -1068,7 +1068,7 @@ // If the bitcast is of
> >> an allocation, and the allocation will be // converted to match
> >> the type of the cast, don't touch this. if
> >> (isa<AllocaInst>(BCI->getOperand(0)) ||
> >> -            isMalloc(BCI->getOperand(0))) {
> >> +            isAllocationFn(BCI->getOperand(0))) {
> >>            // See if the bitcast simplifies, if so, don't nuke this
> >> GEP yet. if (Instruction *I = visitBitCast(*BCI)) {
> >>              if (I != BCI) {
> >>
> >> Modified: llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
> >> (original) +++
> >> llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp Thu Jun
> >> 21 10:45:28 2012 @@ -275,39 +275,9 @@ }
> >>  static uint64_t getPointerSize(const Value *V, AliasAnalysis &AA)
> >> {
> >> -  const TargetData *TD = AA.getTargetData();
> >> -
> >> -  if (const CallInst *CI = extractMallocCall(V)) {
> >> -    if (const ConstantInt *C =
> >> dyn_cast<ConstantInt>(CI->getArgOperand(0)))
> >> -      return C->getZExtValue();
> >> -  }
> >> -
> >> -  if (const CallInst *CI = extractCallocCall(V)) {
> >> -    if (const ConstantInt *C1 =
> >> dyn_cast<ConstantInt>(CI->getArgOperand(0)))
> >> -      if (const ConstantInt *C2 =
> >> dyn_cast<ConstantInt>(CI->getArgOperand(1)))
> >> -       return (C1->getValue() * C2->getValue()).getZExtValue();
> >> -  }
> >> -
> >> -  if (TD == 0)
> >> -    return AliasAnalysis::UnknownSize;
> >> -
> >> -  if (const AllocaInst *A = dyn_cast<AllocaInst>(V)) {
> >> -    // Get size information for the alloca
> >> -    if (const ConstantInt *C =
> >> dyn_cast<ConstantInt>(A->getArraySize()))
> >> -      return C->getZExtValue() *
> >> TD->getTypeAllocSize(A->getAllocatedType());
> >> -  }
> >> -
> >> -  if (const Argument *A = dyn_cast<Argument>(V)) {
> >> -    if (A->hasByValAttr())
> >> -      if (PointerType *PT = dyn_cast<PointerType>(A->getType()))
> >> -        return TD->getTypeAllocSize(PT->getElementType());
> >> -  }
> >> -
> >> -  if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
> >> -    if (!GV->mayBeOverridden())
> >> -      return
> >> TD->getTypeAllocSize(GV->getType()->getElementType());
> >> -  }
> >> -
> >> +  uint64_t Size;
> >> +  if (getObjectSize(V, Size, AA.getTargetData()))
> >> +    return Size;
> >>    return AliasAnalysis::UnknownSize;
> >>  }
> >>
> >> @@ -705,16 +675,13 @@
> >>    // Find all of the alloca'd pointers in the entry block.
> >>    BasicBlock *Entry = BB.getParent()->begin();
> >>    for (BasicBlock::iterator I = Entry->begin(), E = Entry->end();
> >> I != E; ++I) {
> >> -    if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
> >> -      DeadStackObjects.insert(AI);
> >> +    if (isa<AllocaInst>(I))
> >> +      DeadStackObjects.insert(I);
> >>
> >>      // Okay, so these are dead heap objects, but if the pointer
> >> never escapes // then it's leaked by this function anyways.
> >> -    CallInst *CI = extractMallocCall(I);
> >> -    if (!CI)
> >> -      CI = extractCallocCall(I);
> >> -    if (CI && !PointerMayBeCaptured(CI, true, true))
> >> -      DeadStackObjects.insert(CI);
> >> +    else if (isAllocLikeFn(I) && !PointerMayBeCaptured(I, true,
> >> true))
> >> +      DeadStackObjects.insert(I);
> >>    }
> >>
> >>    // Treat byval arguments the same, stores to them are dead at
> >> the end of the @@ -773,18 +740,8 @@
> >>        continue;
> >>      }
> >>
> >> -    if (AllocaInst *A = dyn_cast<AllocaInst>(BBI)) {
> >> -      DeadStackObjects.remove(A);
> >> -      continue;
> >> -    }
> >> -
> >> -    if (CallInst *CI = extractMallocCall(BBI)) {
> >> -      DeadStackObjects.remove(CI);
> >> -      continue;
> >> -    }
> >> -
> >> -    if (CallInst *CI = extractCallocCall(BBI)) {
> >> -      DeadStackObjects.remove(CI);
> >> +    if (isa<AllocaInst>(BBI) || isAllocLikeFn(BBI)) {
> >> +      DeadStackObjects.remove(BBI);
> >>        continue;
> >>      }
> >>
> >>
> >> Modified: llvm/trunk/lib/Transforms/Scalar/GVN.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GVN.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Transforms/Scalar/GVN.cpp (original) +++
> >> llvm/trunk/lib/Transforms/Scalar/GVN.cpp Thu Jun 21 10:45:28 2012
> >> @@ -1436,7 +1436,7 @@ Instruction *DepInst = DepInfo.getInst();
> >>
> >>      // Loading the allocation -> undef.
> >> -    if (isa<AllocaInst>(DepInst) || isMalloc(DepInst) ||
> >> +    if (isa<AllocaInst>(DepInst) || isMallocLikeFn(DepInst) ||
> >>          // Loading immediately after lifetime begin -> undef.
> >>          isLifetimeStart(DepInst)) {
> >>        ValuesPerBlock.push_back(AvailableValueInBlock::get(DepBB,
> >> @@ -1951,7 +1951,7 @@
> >>    // If this load really doesn't depend on anything, then we must
> >> be loading an // undef value.  This can happen when loading for a
> >> fresh allocation with no // intervening stores, for example.
> >> -  if (isa<AllocaInst>(DepInst) || isMalloc(DepInst)) {
> >> +  if (isa<AllocaInst>(DepInst) || isMallocLikeFn(DepInst)) {
> >>      L->replaceAllUsesWith(UndefValue::get(L->getType()));
> >>      markInstructionForDeletion(L);
> >>      ++NumGVNLoad;
> >>
> >> Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/lib/Transforms/Utils/Local.cpp (original) +++
> >> llvm/trunk/lib/Transforms/Utils/Local.cpp Thu Jun 21 10:45:28 2012
> >> @@ -266,7 +266,7 @@ return isa<UndefValue>(II->getArgOperand(1));
> >>    }
> >>
> >> -  if (extractMallocCall(I) || extractCallocCall(I)) return true;
> >> +  if (isAllocLikeFn(I)) return true;
> >>
> >>    if (CallInst *CI = isFreeCall(I))
> >>      if (Constant *C = dyn_cast<Constant>(CI->getArgOperand(0)))
> >>
> >> Modified: llvm/trunk/test/Transforms/InstCombine/objsize.ll
> >> URL:
> >> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize.ll?rev=158919&r1=158918&r2=158919&view=diff
> >> ==============================================================================
> >> --- llvm/trunk/test/Transforms/InstCombine/objsize.ll (original)
> >> +++ llvm/trunk/test/Transforms/InstCombine/objsize.ll Thu Jun 21
> >> 10:45:28 2012 @@ -42,7 +42,7 @@
> >>  define i1 @baz() nounwind {
> >>  ; CHECK: @baz
> >> -; CHECK-NEXT: ret i1 true
> >> +; CHECK-NEXT: objectsize
> >>    %1 = tail call i32 @llvm.objectsize.i32(i8* getelementptr
> >> inbounds ([0 x i8]* @window, i32 0, i32 0), i1 false) %2 = icmp eq
> >> i32 %1, -1 ret i1 %2
> >>
> >>
> >> _______________________________________________
> >> llvm-commits mailing list
> >> llvm-commits at cs.uiuc.edu
> >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> >
> >
> >
> > --
> > Hal Finkel
> > Postdoctoral Appointee
> > Leadership Computing Facility
> > Argonne National Laboratory



-- 
Hal Finkel
Postdoctoral Appointee
Leadership Computing Facility
Argonne National Laboratory



More information about the llvm-commits mailing list