From: Uday Bondhugula Date: Sat, 28 Mar 2020 05:59:52 +0000 (+0530) Subject: Introduce support for lib function aligned_alloc in TLI / memory builtins X-Git-Tag: llvmorg-12-init~10801 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c0955edfd6ec51e9a3720f9bfc90bac2e511c06d;p=platform%2Fupstream%2Fllvm.git Introduce support for lib function aligned_alloc in TLI / memory builtins Aligned_alloc is a standard lib function and has been in glibc since 2.16 and in the C11 standard. It has semantics similar to malloc/calloc for several analyses/transforms. This patch introduces aligned_alloc in target library info and memory builtins. Subsequent ones will make other passes aware and fix https://bugs.llvm.org/show_bug.cgi?id=44062 This change will also be useful to LLVM generators that need to allocate buffers of vector elements larger than 16 bytes (for eg. 256-bit ones), element boundary alignment for which is not typically provided by glibc malloc. Signed-off-by: Uday Bondhugula Differential Revision: https://reviews.llvm.org/D76970 --- diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h index a89d76b..a674a3a 100644 --- a/llvm/include/llvm/Analysis/MemoryBuiltins.h +++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -76,6 +76,14 @@ bool isMallocLikeFn(const Value *V, bool LookThroughBitCast = false); /// Tests if a value is a call or invoke to a library function that +/// allocates uninitialized memory with alignment (such as aligned_alloc). +bool isAlignedAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI, + bool LookThroughBitCast = false); +bool isAlignedAllocLikeFn( + const Value *V, function_ref GetTLI, + bool LookThroughBitCast = false); + +/// Tests if a value is a call or invoke to a library function that /// allocates zero-filled memory (such as calloc). bool isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI, bool LookThroughBitCast = false); diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def index ed0e125..b5688ce 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -481,6 +481,9 @@ TLI_DEFINE_STRING_INTERNAL("acoshl") /// long double acosl(long double x); TLI_DEFINE_ENUM_INTERNAL(acosl) TLI_DEFINE_STRING_INTERNAL("acosl") +/// void *aligned_alloc(size_t alignment, size_t size); +TLI_DEFINE_ENUM_INTERNAL(aligned_alloc) +TLI_DEFINE_STRING_INTERNAL("aligned_alloc") /// double asin(double x); TLI_DEFINE_ENUM_INTERNAL(asin) TLI_DEFINE_STRING_INTERNAL("asin") diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 0cc28ef..9ab056f 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -960,7 +960,7 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call, } } - // If the call is to malloc or calloc, we can assume that it doesn't + // If the call is malloc/calloc like, we can assume that it doesn't // modify any IR visible value. This is only valid because we assume these // routines do not read values visible in the IR. TODO: Consider special // casing realloc and strdup routines which access only their arguments as diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index be0feeb..ac72bda 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -52,11 +52,12 @@ using namespace llvm; enum AllocType : uint8_t { OpNewLike = 1<<0, // allocates; never returns null MallocLike = 1<<1 | OpNewLike, // allocates; may return null - CallocLike = 1<<2, // allocates + bzero - ReallocLike = 1<<3, // reallocates - StrDupLike = 1<<4, - MallocOrCallocLike = MallocLike | CallocLike, - AllocLike = MallocLike | CallocLike | StrDupLike, + AlignedAllocLike = 1<<2, // allocates with alignment; may return null + CallocLike = 1<<3, // allocates + bzero + ReallocLike = 1<<4, // reallocates + StrDupLike = 1<<5, + MallocOrCallocLike = MallocLike | CallocLike | AlignedAllocLike, + AllocLike = MallocOrCallocLike | StrDupLike, AnyAlloc = AllocLike | ReallocLike }; @@ -100,6 +101,7 @@ static const std::pair AllocationFnData[] = { {LibFunc_msvc_new_array_int_nothrow, {MallocLike, 2, 0, -1}}, // new[](unsigned int, nothrow) {LibFunc_msvc_new_array_longlong, {OpNewLike, 1, 0, -1}}, // new[](unsigned long long) {LibFunc_msvc_new_array_longlong_nothrow, {MallocLike, 2, 0, -1}}, // new[](unsigned long long, nothrow) + {LibFunc_aligned_alloc, {AlignedAllocLike, 2, 1, -1}}, {LibFunc_calloc, {CallocLike, 2, 0, 1}}, {LibFunc_realloc, {ReallocLike, 2, 1, -1}}, {LibFunc_reallocf, {ReallocLike, 2, 1, -1}}, @@ -266,6 +268,20 @@ bool llvm::isMallocLikeFn( } /// Tests if a value is a call or invoke to a library function that +/// allocates uninitialized memory with alignment (such as aligned_alloc). +bool llvm::isAlignedAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI, + bool LookThroughBitCast) { + return getAllocationData(V, AlignedAllocLike, TLI, LookThroughBitCast) + .hasValue(); +} +bool llvm::isAlignedAllocLikeFn( + const Value *V, function_ref GetTLI, + bool LookThroughBitCast) { + return getAllocationData(V, AlignedAllocLike, GetTLI, LookThroughBitCast) + .hasValue(); +} + +/// Tests if a value is a call or invoke to a library function that /// allocates zero-filled memory (such as calloc). bool llvm::isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI, bool LookThroughBitCast) { diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index fa4deea..ffa6921 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -901,6 +901,8 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, FTy.getParamType(1)->isPointerTy()); case LibFunc_write: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); + case LibFunc_aligned_alloc: + return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); case LibFunc_bcopy: case LibFunc_bcmp: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index a385b08..c64ad14 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -378,6 +378,10 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; + case LibFunc_aligned_alloc: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + return Changed; case LibFunc_bcopy: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); diff --git a/llvm/test/Transforms/DeadStoreElimination/simple.ll b/llvm/test/Transforms/DeadStoreElimination/simple.ll index 84034ca..7efd395 100644 --- a/llvm/test/Transforms/DeadStoreElimination/simple.ll +++ b/llvm/test/Transforms/DeadStoreElimination/simple.ll @@ -259,6 +259,8 @@ define i32 addrspace(1)* @test13_addrspacecast() { declare noalias i8* @malloc(i32) declare noalias i8* @calloc(i32, i32) +declare noalias i8* @aligned_alloc(i32, i32) +declare void @free(i8*) define void @test14(i32* %Q) { @@ -272,6 +274,17 @@ define void @test14(i32* %Q) { } +; Dead store on an aligned_alloc: should know that %M doesn't alias with %A. +define i32 @test14a(i8* %M, i8 %value) { +; CHECK-LABEL: @test14a( +; CHECK-NOT: store +; CHECK: ret i32 0 +; + %A = tail call i8* @aligned_alloc(i32 32, i32 1024) + store i8 %value, i8* %A + tail call void @free(i8* %A) + ret i32 0 +} ; PR8701 diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp index af0ee63..f210814 100644 --- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp +++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -96,6 +96,7 @@ TEST_F(TargetLibraryInfoTest, ValidProto) { "declare float @acoshf(float)\n" "declare x86_fp80 @acoshl(x86_fp80)\n" "declare x86_fp80 @acosl(x86_fp80)\n" + "declare i8* @aligned_alloc(i64, i64)\n" "declare double @asin(double)\n" "declare float @asinf(float)\n" "declare double @asinh(double)\n"