Index: include/llvm/Analysis/MemoryBuiltins.h =================================================================== --- include/llvm/Analysis/MemoryBuiltins.h +++ include/llvm/Analysis/MemoryBuiltins.h @@ -93,6 +93,11 @@ /// reallocates memory (e.g., realloc). bool isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI); +/// Tests if a value is a call or invoke to a library function that +/// reallocates memory (e.g., new). +bool isOpNewLikeFn(const Value *V, const TargetLibraryInfo *TLI, + bool LookThroughBitCast = false); + //===----------------------------------------------------------------------===// // malloc Call Utility Functions. // Index: lib/Analysis/MemoryBuiltins.cpp =================================================================== --- lib/Analysis/MemoryBuiltins.cpp +++ lib/Analysis/MemoryBuiltins.cpp @@ -276,6 +276,13 @@ return getAllocationDataForFunction(F, ReallocLike, TLI).hasValue(); } +/// Tests if a value is a call or invoke to a library function that +/// reallocates memory (e.g., new). +bool llvm::isOpNewLikeFn(const Value *V, const TargetLibraryInfo *TLI, + bool LookThroughBitCast) { + return getAllocationData(V, OpNewLike, TLI, LookThroughBitCast).hasValue(); +} + /// extractMallocCall - Returns the corresponding CallInst if the instruction /// is a malloc call. Since CallInst::CreateMalloc() only creates calls, we /// ignore InvokeInst here. Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -4177,8 +4177,42 @@ return nullptr; } +static void annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) { + CallInst *CI = cast(&Call); + ConstantInt *Op0C = dyn_cast(CI->getOperand(0)); + if (isMallocLikeFn(CI, TLI) && Op0C && !Op0C->isNullValue()) { + CI->addAttribute(AttributeList::ReturnIndex, + Attribute::getWithDereferenceableOrNullBytes( + CI->getContext(), Op0C->getZExtValue())); + } else if (isOpNewLikeFn(CI, TLI) && Op0C && !Op0C->isNullValue()) { + CI->addAttribute(AttributeList::ReturnIndex, + Attribute::getWithDereferenceableBytes( + CI->getContext(), Op0C->getZExtValue())); + } else if (isReallocLikeFn(CI, TLI)) { + ConstantInt *Op1C = dyn_cast(CI->getOperand(1)); + if (Op1C && !Op1C->isNullValue()) + CI->addAttribute(AttributeList::ReturnIndex, + Attribute::getWithDereferenceableOrNullBytes( + CI->getContext(), Op1C->getZExtValue())); + } else if (isCallocLikeFn(CI, TLI) && Op0C && !Op0C->isNullValue()) { + ConstantInt *Op1C = dyn_cast(CI->getOperand(1)); + if (Op1C && !Op1C->isNullValue()) { + bool Overflow; + const APInt &N = Op0C->getValue(); + APInt Size = N.umul_ov(Op1C->getValue(), Overflow); + if (!Overflow) + CI->addAttribute(AttributeList::ReturnIndex, + Attribute::getWithDereferenceableOrNullBytes( + CI->getContext(), Size.getZExtValue())); + } + } +} + /// Improvements for call, callbr and invoke instructions. Instruction *InstCombiner::visitCallBase(CallBase &Call) { + if (isAllocationFn(&Call, &TLI)) + annotateAnyAllocSite(Call, &TLI); + if (isAllocLikeFn(&Call, &TLI)) return visitAllocSite(Call);