From dc817b2dea9f28e22470d1d74956f404fcec4e01 Mon Sep 17 00:00:00 2001 From: Uday Bondhugula Date: Sat, 28 Mar 2020 12:05:36 +0530 Subject: [PATCH] [InstCombine] Deduce attributes for aligned_alloc in InstCombine Make InstCombine aware of the aligned_alloc library function. Signed-off-by: Uday Bondhugula Depends on D76970. Differential Revision: https://reviews.llvm.org/D76971 --- .../Transforms/InstCombine/InstCombineCalls.cpp | 15 +++++++++++- .../test/Transforms/InstCombine/deref-alloc-fns.ll | 27 +++++++++++++++++++++- .../Transforms/InstCombine/malloc-free-delete.ll | 11 +++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index abbc878..4ad0f8d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -4441,7 +4441,8 @@ static void annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) { ConstantInt *Op0C = dyn_cast(Call.getOperand(0)); ConstantInt *Op1C = (NumArgs == 1) ? nullptr : dyn_cast(Call.getOperand(1)); - // Bail out if the allocation size is zero. + // Bail out if the allocation size is zero (or an invalid alignment of zero + // with aligned_alloc). if ((Op0C && Op0C->isNullValue()) || (Op1C && Op1C->isNullValue())) return; @@ -4454,6 +4455,18 @@ static void annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) { Call.addAttribute(AttributeList::ReturnIndex, Attribute::getWithDereferenceableOrNullBytes( Call.getContext(), Op0C->getZExtValue())); + } else if (isAlignedAllocLikeFn(&Call, TLI) && Op1C) { + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithDereferenceableOrNullBytes( + Call.getContext(), Op1C->getZExtValue())); + // Add alignment attribute if alignment is a power of two constant. + if (Op0C) { + uint64_t AlignmentVal = Op0C->getZExtValue(); + if (llvm::isPowerOf2_64(AlignmentVal)) + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call.getContext(), + Align(AlignmentVal))); + } } else if (isReallocLikeFn(&Call, TLI) && Op1C) { Call.addAttribute(AttributeList::ReturnIndex, Attribute::getWithDereferenceableOrNullBytes( diff --git a/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll b/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll index efaf1cd..9d9964d 100644 --- a/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll +++ b/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll @@ -7,6 +7,7 @@ declare noalias i8* @realloc(i8* nocapture, i64) declare noalias nonnull i8* @_Znam(i64) ; throwing version of 'new' declare noalias nonnull i8* @_Znwm(i64) ; throwing version of 'new' declare noalias i8* @strdup(i8*) +declare noalias i8* @aligned_alloc(i64, i64) @.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @@ -28,6 +29,31 @@ define noalias i8* @malloc_constant_size() { ret i8* %call } +define noalias i8* @aligned_alloc_constant_size() { +; CHECK-LABEL: @aligned_alloc_constant_size( +; CHECK-NEXT: [[CALL:%.*]] = tail call noalias align 32 dereferenceable_or_null(512) i8* @aligned_alloc(i64 32, i64 512) +; CHECK-NEXT: ret i8* [[CALL]] +; + %call = tail call noalias i8* @aligned_alloc(i64 32, i64 512) + ret i8* %call +} + +declare noalias i8* @foo(i8*, i8*, i8*) + +define noalias i8* @aligned_alloc_dynamic_args(i64 %align, i64 %size) { +; CHECK-LABEL: @aligned_alloc_dynamic_args( +; CHECK-NEXT: tail call noalias dereferenceable_or_null(1024) i8* @aligned_alloc(i64 %{{.*}}, i64 1024) +; CHECK-NEXT: tail call noalias i8* @aligned_alloc(i64 0, i64 1024) +; CHECK-NEXT: tail call noalias i8* @aligned_alloc(i64 32, i64 %{{.*}}) +; + %call = tail call noalias i8* @aligned_alloc(i64 %align, i64 1024) + %call_1 = tail call noalias i8* @aligned_alloc(i64 0, i64 1024) + %call_2 = tail call noalias i8* @aligned_alloc(i64 32, i64 %size) + + call i8* @foo(i8* %call, i8* %call_1, i8* %call_2) + ret i8* %call +} + define noalias i8* @malloc_constant_size2() { ; CHECK-LABEL: @malloc_constant_size2( ; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(80) i8* @malloc(i64 40) @@ -46,7 +72,6 @@ define noalias i8* @malloc_constant_size3() { ret i8* %call } - define noalias i8* @malloc_constant_zero_size() { ; CHECK-LABEL: @malloc_constant_zero_size( ; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @malloc(i64 0) diff --git a/llvm/test/Transforms/InstCombine/malloc-free-delete.ll b/llvm/test/Transforms/InstCombine/malloc-free-delete.ll index 7f6d7b4..2f4447b 100644 --- a/llvm/test/Transforms/InstCombine/malloc-free-delete.ll +++ b/llvm/test/Transforms/InstCombine/malloc-free-delete.ll @@ -13,8 +13,19 @@ define i32 @main(i32 %argc, i8** %argv) { ret i32 0 } +define i32 @dead_aligned_alloc(i32 %size, i32 %alignment, i8 %value) { +; CHECK-LABEL: @dead_aligned_alloc( +; CHECK-NEXT: ret i32 0 +; + %aligned_allocation = tail call i8* @aligned_alloc(i32 %alignment, i32 %size) + store i8 %value, i8* %aligned_allocation + tail call void @free(i8* %aligned_allocation) + ret i32 0 +} + declare noalias i8* @calloc(i32, i32) nounwind declare noalias i8* @malloc(i32) +declare noalias i8* @aligned_alloc(i32, i32) declare void @free(i8*) define i1 @foo() { -- 2.7.4