diff options
-rw-r--r-- | llvm/lib/Analysis/MemoryBuiltins.cpp | 51 | ||||
-rw-r--r-- | llvm/unittests/Analysis/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/Analysis/MemoryBuiltinsTest.cpp | 50 |
3 files changed, 79 insertions, 23 deletions
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index eaac506dec4..3e464f08f2e 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -109,25 +109,6 @@ static Optional<AllocFnsTy> getAllocationData(const Value *V, AllocType AllocTy, if (!Callee) return None; - // If it has allocsize, we can skip checking if it's a known function. - // - // MallocLike is chosen here because allocsize makes no guarantees about the - // nullness of the result of the function, nor does it deal with strings, nor - // does it require that the memory returned is zeroed out. - const AllocType AllocSizeAllocTy = MallocLike; - if ((AllocTy & AllocSizeAllocTy) == AllocSizeAllocTy && - Callee->hasFnAttribute(Attribute::AllocSize)) { - Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize); - std::pair<unsigned, Optional<unsigned>> Args = Attr.getAllocSizeArgs(); - - AllocFnsTy Result; - Result.AllocTy = AllocSizeAllocTy; - Result.NumParams = Callee->getNumOperands(); - Result.FstParam = Args.first; - Result.SndParam = Args.second.getValueOr(-1); - return Result; - } - // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; @@ -163,6 +144,32 @@ static Optional<AllocFnsTy> getAllocationData(const Value *V, AllocType AllocTy, return None; } +static Optional<AllocFnsTy> getAllocationSize(const Value *V, + const TargetLibraryInfo *TLI) { + // Prefer to use existing information over allocsize. This will give us an + // accurate AllocTy. + if (Optional<AllocFnsTy> Data = + getAllocationData(V, AnyAlloc, TLI, /*LookThroughBitCast=*/false)) + return Data; + + // FIXME: Not calling getCalledFunction twice would be nice. + const Function *Callee = getCalledFunction(V, /*LookThroughBitCast=*/false); + if (!Callee || !Callee->hasFnAttribute(Attribute::AllocSize)) + return None; + + Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize); + std::pair<unsigned, Optional<unsigned>> Args = Attr.getAllocSizeArgs(); + + AllocFnsTy Result; + // Because allocsize only tells us how many bytes are allocated, we're not + // really allowed to assume anything, so we use MallocLike. + Result.AllocTy = MallocLike; + Result.NumParams = Callee->getNumOperands(); + Result.FstParam = Args.first; + Result.SndParam = Args.second.getValueOr(-1); + return Result; +} + static bool hasNoAliasAttr(const Value *V, bool LookThroughBitCast) { ImmutableCallSite CS(LookThroughBitCast ? V->stripPointerCasts() : V); return CS && CS.paramHasAttr(AttributeSet::ReturnIndex, Attribute::NoAlias); @@ -505,8 +512,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitArgument(Argument &A) { } SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite CS) { - Optional<AllocFnsTy> FnData = - getAllocationData(CS.getInstruction(), AnyAlloc, TLI); + Optional<AllocFnsTy> FnData = getAllocationSize(CS.getInstruction(), TLI); if (!FnData) return unknown(); @@ -765,8 +771,7 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) { } SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitCallSite(CallSite CS) { - Optional<AllocFnsTy> FnData = - getAllocationData(CS.getInstruction(), AnyAlloc, TLI); + Optional<AllocFnsTy> FnData = getAllocationSize(CS.getInstruction(), TLI); if (!FnData) return unknown(); diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt index 33fc5c78ce5..65a2ac094cf 100644 --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -14,6 +14,7 @@ add_llvm_unittest(AnalysisTests CGSCCPassManagerTest.cpp LazyCallGraphTest.cpp LoopPassManagerTest.cpp + MemoryBuiltinsTest.cpp ScalarEvolutionTest.cpp TBAATest.cpp ValueTrackingTest.cpp diff --git a/llvm/unittests/Analysis/MemoryBuiltinsTest.cpp b/llvm/unittests/Analysis/MemoryBuiltinsTest.cpp new file mode 100644 index 00000000000..898ebeece4f --- /dev/null +++ b/llvm/unittests/Analysis/MemoryBuiltinsTest.cpp @@ -0,0 +1,50 @@ +//===- MemoryBuiltinsTest.cpp - Tests for utilities in MemoryBuiltins.h ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +// allocsize should not imply that a function is a traditional allocation +// function (e.g. that can be optimized out/...); it just tells us how many +// bytes exist at the pointer handed back by the function. +TEST(AllocSize, AllocationBuiltinsTest) { + LLVMContext Context; + Module M("", Context); + IntegerType *ArgTy = Type::getInt32Ty(Context); + + Function *AllocSizeFn = Function::Create( + FunctionType::get(Type::getInt8PtrTy(Context), {ArgTy}, false), + GlobalValue::ExternalLinkage, "F", &M); + + AllocSizeFn->addFnAttr(Attribute::getWithAllocSizeArgs(Context, 1, None)); + + // 100 is arbitrary. + std::unique_ptr<CallInst> Caller( + CallInst::Create(AllocSizeFn, {ConstantInt::get(ArgTy, 100)})); + + const TargetLibraryInfo *TLI = nullptr; + EXPECT_FALSE(isNoAliasFn(Caller.get(), TLI)); + EXPECT_FALSE(isMallocLikeFn(Caller.get(), TLI)); + EXPECT_FALSE(isCallocLikeFn(Caller.get(), TLI)); + EXPECT_FALSE(isAllocLikeFn(Caller.get(), TLI)); + + // FIXME: We might be able to treat allocsize functions as general allocation + // functions. For the moment, being conservative seems better (and we'd have + // to plumb stuff around `isNoAliasFn`). + EXPECT_FALSE(isAllocationFn(Caller.get(), TLI)); +} +} |