diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -2049,7 +2049,27 @@ return nullptr; } -void InstCombinerImpl::annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) { +static unsigned GuaranteedAlignmentForAllocFns(CallBase &Call) { + Triple T(Call.getModule()->getTargetTriple()); + // From the glibc documentation, on GNU systems, malloc guarantees 16-byte + // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See + // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html. + // This alignment guarantee also applies to Windows and Android. On Darwin, + // the alignment is 16 bytes on both 64-bit and 32-bit systems. + if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid()) { + if (T.isArch64Bit()) + return 16; + if (T.isArch32Bit()) + return 8; + } + + if (T.isOSDarwin()) + return 16; + return 0; // Unknown. Can we assume 8 ??? +} + +void InstCombinerImpl::annotateAnyAllocSite(CallBase &Call, + const TargetLibraryInfo *TLI) { unsigned NumArgs = Call.getNumArgOperands(); ConstantInt *Op0C = dyn_cast(Call.getOperand(0)); ConstantInt *Op1C = @@ -2059,6 +2079,7 @@ if ((Op0C && Op0C->isNullValue()) || (Op1C && Op1C->isNullValue())) return; + unsigned AlignmentForAlloc = GuaranteedAlignmentForAllocFns(Call); if (isMallocLikeFn(&Call, TLI) && Op0C) { if (isOpNewLikeFn(&Call, TLI)) Call.addAttribute(AttributeList::ReturnIndex, @@ -2068,6 +2089,11 @@ Call.addAttribute(AttributeList::ReturnIndex, Attribute::getWithDereferenceableOrNullBytes( Call.getContext(), Op0C->getZExtValue())); + + if (AlignmentForAlloc) + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call.getContext(), + Align(AlignmentForAlloc))); } else if (isAlignedAllocLikeFn(&Call, TLI)) { if (Op1C) Call.addAttribute(AttributeList::ReturnIndex, @@ -2081,11 +2107,19 @@ Call.addAttribute(AttributeList::ReturnIndex, Attribute::getWithAlignment(Call.getContext(), Align(AlignmentVal))); + } else if (AlignmentForAlloc) { + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call.getContext(), + Align(AlignmentForAlloc))); } } else if (isReallocLikeFn(&Call, TLI) && Op1C) { Call.addAttribute(AttributeList::ReturnIndex, Attribute::getWithDereferenceableOrNullBytes( Call.getContext(), Op1C->getZExtValue())); + if (AlignmentForAlloc) + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call.getContext(), + Align(AlignmentForAlloc))); } else if (isCallocLikeFn(&Call, TLI) && Op0C && Op1C) { bool Overflow; const APInt &N = Op0C->getValue(); @@ -2094,6 +2128,11 @@ Call.addAttribute(AttributeList::ReturnIndex, Attribute::getWithDereferenceableOrNullBytes( Call.getContext(), Size.getZExtValue())); + + if (AlignmentForAlloc) + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call.getContext(), + Align(AlignmentForAlloc))); } else if (isStrdupLikeFn(&Call, TLI)) { uint64_t Len = GetStringLength(Call.getOperand(0)); if (Len) { @@ -2109,6 +2148,11 @@ Attribute::getWithDereferenceableOrNullBytes( Call.getContext(), std::min(Len, Op1C->getZExtValue() + 1))); } + + if (AlignmentForAlloc) + Call.addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call.getContext(), + Align(AlignmentForAlloc))); } } diff --git a/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll b/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll --- a/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll +++ b/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll @@ -1,6 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -instcombine -S < %s | FileCheck %s -; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -instcombine -S | FileCheck %s --check-prefixes=CHECK,GNU +; RUN: opt -instcombine -S < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefixes=CHECK,GNU64 +; RUN: opt -instcombine -S < %s -mtriple=i386-unknown-linux-gnu | FileCheck %s --check-prefixes=CHECK,GNU32 +; RUN: opt -instcombine -S < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s --check-prefixes=CHECK,MSVC declare noalias i8* @malloc(i64) @@ -24,9 +26,17 @@ } define noalias i8* @malloc_constant_size() { -; CHECK-LABEL: @malloc_constant_size( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(40) i8* @malloc(i64 40) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @malloc_constant_size( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(40) i8* @malloc(i64 40) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @malloc_constant_size( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(40) i8* @malloc(i64 40) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @malloc_constant_size( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(40) i8* @malloc(i64 40) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @malloc(i64 40) ret i8* %call @@ -53,10 +63,20 @@ } define noalias i8* @aligned_alloc_unknown_size_possibly_zero(i1 %c) { -; CHECK-LABEL: @aligned_alloc_unknown_size_possibly_zero( -; CHECK-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @aligned_alloc(i64 32, i64 [[SIZE]]) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @aligned_alloc_unknown_size_possibly_zero( +; GNU64-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @aligned_alloc(i64 32, i64 [[SIZE]]) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @aligned_alloc_unknown_size_possibly_zero( +; GNU32-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 i8* @aligned_alloc(i64 32, i64 [[SIZE]]) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @aligned_alloc_unknown_size_possibly_zero( +; MSVC-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @aligned_alloc(i64 32, i64 [[SIZE]]) +; MSVC-NEXT: ret i8* [[CALL]] ; %size = select i1 %c, i64 64, i64 0 %call = tail call noalias i8* @aligned_alloc(i64 32, i64 %size) @@ -64,9 +84,17 @@ } define noalias i8* @aligned_alloc_unknown_align(i64 %align) { -; CHECK-LABEL: @aligned_alloc_unknown_align( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(128) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 128) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @aligned_alloc_unknown_align( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(128) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 128) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @aligned_alloc_unknown_align( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(128) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 128) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @aligned_alloc_unknown_align( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(128) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 128) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @aligned_alloc(i64 %align, i64 128) ret i8* %call @@ -75,12 +103,26 @@ 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: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(1024) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 1024) -; CHECK-NEXT: [[CALL_1:%.*]] = tail call noalias i8* @aligned_alloc(i64 0, i64 1024) -; CHECK-NEXT: [[CALL_2:%.*]] = tail call noalias i8* @aligned_alloc(i64 32, i64 [[SIZE:%.*]]) -; CHECK-NEXT: [[TMP1:%.*]] = call i8* @foo(i8* [[CALL]], i8* [[CALL_1]], i8* [[CALL_2]]) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @aligned_alloc_dynamic_args( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(1024) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 1024) +; GNU64-NEXT: [[CALL_1:%.*]] = tail call noalias i8* @aligned_alloc(i64 0, i64 1024) +; GNU64-NEXT: [[CALL_2:%.*]] = tail call noalias align 16 i8* @aligned_alloc(i64 32, i64 [[SIZE:%.*]]) +; GNU64-NEXT: [[TMP1:%.*]] = call i8* @foo(i8* [[CALL]], i8* [[CALL_1]], i8* [[CALL_2]]) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @aligned_alloc_dynamic_args( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(1024) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 1024) +; GNU32-NEXT: [[CALL_1:%.*]] = tail call noalias i8* @aligned_alloc(i64 0, i64 1024) +; GNU32-NEXT: [[CALL_2:%.*]] = tail call noalias align 8 i8* @aligned_alloc(i64 32, i64 [[SIZE:%.*]]) +; GNU32-NEXT: [[TMP1:%.*]] = call i8* @foo(i8* [[CALL]], i8* [[CALL_1]], i8* [[CALL_2]]) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @aligned_alloc_dynamic_args( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(1024) i8* @aligned_alloc(i64 [[ALIGN:%.*]], i64 1024) +; MSVC-NEXT: [[CALL_1:%.*]] = tail call noalias i8* @aligned_alloc(i64 0, i64 1024) +; MSVC-NEXT: [[CALL_2:%.*]] = tail call noalias align 16 i8* @aligned_alloc(i64 32, i64 [[SIZE:%.*]]) +; MSVC-NEXT: [[TMP1:%.*]] = call i8* @foo(i8* [[CALL]], i8* [[CALL_1]], i8* [[CALL_2]]) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @aligned_alloc(i64 %align, i64 1024) %call_1 = tail call noalias i8* @aligned_alloc(i64 0, i64 1024) @@ -91,19 +133,37 @@ } define noalias i8* @memalign_constant_size() { -; GNU-LABEL: @memalign_constant_size( -; GNU-NEXT: [[CALL:%.*]] = tail call noalias align 32 dereferenceable_or_null(512) i8* @memalign(i64 32, i64 512) -; GNU-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @memalign_constant_size( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 32 dereferenceable_or_null(512) i8* @memalign(i64 32, i64 512) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @memalign_constant_size( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 32 dereferenceable_or_null(512) i8* @memalign(i64 32, i64 512) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @memalign_constant_size( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias i8* @memalign(i64 32, i64 512) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @memalign(i64 32, i64 512) ret i8* %call } define noalias i8* @memalign_unknown_size_nonzero(i1 %c) { -; GNU-LABEL: @memalign_unknown_size_nonzero( -; GNU-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 128 -; GNU-NEXT: [[CALL:%.*]] = tail call noalias align 32 i8* @memalign(i64 32, i64 [[SIZE]]) -; GNU-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @memalign_unknown_size_nonzero( +; GNU64-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 128 +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 32 i8* @memalign(i64 32, i64 [[SIZE]]) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @memalign_unknown_size_nonzero( +; GNU32-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 128 +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 32 i8* @memalign(i64 32, i64 [[SIZE]]) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @memalign_unknown_size_nonzero( +; MSVC-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 128 +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias i8* @memalign(i64 32, i64 [[SIZE]]) +; MSVC-NEXT: ret i8* [[CALL]] ; %size = select i1 %c, i64 64, i64 128 %call = tail call noalias i8* @memalign(i64 32, i64 %size) @@ -111,10 +171,20 @@ } define noalias i8* @memalign_unknown_size_possibly_zero(i1 %c) { -; CHECK-LABEL: @memalign_unknown_size_possibly_zero( -; CHECK-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @memalign(i64 32, i64 [[SIZE]]) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @memalign_unknown_size_possibly_zero( +; GNU64-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @memalign(i64 32, i64 [[SIZE]]) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @memalign_unknown_size_possibly_zero( +; GNU32-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 i8* @memalign(i64 32, i64 [[SIZE]]) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @memalign_unknown_size_possibly_zero( +; MSVC-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 64, i64 0 +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias i8* @memalign(i64 32, i64 [[SIZE]]) +; MSVC-NEXT: ret i8* [[CALL]] ; %size = select i1 %c, i64 64, i64 0 %call = tail call noalias i8* @memalign(i64 32, i64 %size) @@ -122,27 +192,51 @@ } define noalias i8* @memalign_unknown_align(i64 %align) { -; GNU-LABEL: @memalign_unknown_align( -; GNU-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(128) i8* @memalign(i64 [[ALIGN:%.*]], i64 128) -; GNU-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @memalign_unknown_align( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(128) i8* @memalign(i64 [[ALIGN:%.*]], i64 128) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @memalign_unknown_align( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(128) i8* @memalign(i64 [[ALIGN:%.*]], i64 128) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @memalign_unknown_align( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias i8* @memalign(i64 [[ALIGN:%.*]], i64 128) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @memalign(i64 %align, i64 128) 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) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @malloc_constant_size2( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(80) i8* @malloc(i64 40) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @malloc_constant_size2( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(80) i8* @malloc(i64 40) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @malloc_constant_size2( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(80) i8* @malloc(i64 40) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias dereferenceable_or_null(80) i8* @malloc(i64 40) ret i8* %call } define noalias i8* @malloc_constant_size3() { -; CHECK-LABEL: @malloc_constant_size3( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable(80) dereferenceable_or_null(40) i8* @malloc(i64 40) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @malloc_constant_size3( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable(80) dereferenceable_or_null(40) i8* @malloc(i64 40) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @malloc_constant_size3( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable(80) dereferenceable_or_null(40) i8* @malloc(i64 40) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @malloc_constant_size3( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable(80) dereferenceable_or_null(40) i8* @malloc(i64 40) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias dereferenceable(80) i8* @malloc(i64 40) ret i8* %call @@ -176,9 +270,17 @@ } define noalias i8* @realloc_constant_size(i8* %p) { -; CHECK-LABEL: @realloc_constant_size( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(40) i8* @realloc(i8* [[P:%.*]], i64 40) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @realloc_constant_size( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(40) i8* @realloc(i8* [[P:%.*]], i64 40) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @realloc_constant_size( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(40) i8* @realloc(i8* [[P:%.*]], i64 40) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @realloc_constant_size( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(40) i8* @realloc(i8* [[P:%.*]], i64 40) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @realloc(i8* %p, i64 40) ret i8* %call @@ -258,18 +360,34 @@ } define noalias i8* @calloc_constant_size() { -; CHECK-LABEL: @calloc_constant_size( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(128) i8* @calloc(i64 16, i64 8) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @calloc_constant_size( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(128) i8* @calloc(i64 16, i64 8) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @calloc_constant_size( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(128) i8* @calloc(i64 16, i64 8) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @calloc_constant_size( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(128) i8* @calloc(i64 16, i64 8) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @calloc(i64 16, i64 8) ret i8* %call } define noalias i8* @calloc_constant_size_overflow() { -; CHECK-LABEL: @calloc_constant_size_overflow( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @calloc(i64 2000000000000, i64 80000000000) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @calloc_constant_size_overflow( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @calloc(i64 2000000000000, i64 80000000000) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @calloc_constant_size_overflow( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 i8* @calloc(i64 2000000000000, i64 80000000000) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @calloc_constant_size_overflow( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @calloc(i64 2000000000000, i64 80000000000) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @calloc(i64 2000000000000, i64 80000000000) ret i8* %call @@ -285,18 +403,34 @@ } define noalias i8* @op_new_constant_size() { -; CHECK-LABEL: @op_new_constant_size( -; CHECK-NEXT: [[CALL:%.*]] = tail call dereferenceable(40) i8* @_Znam(i64 40) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @op_new_constant_size( +; GNU64-NEXT: [[CALL:%.*]] = tail call align 16 dereferenceable(40) i8* @_Znam(i64 40) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @op_new_constant_size( +; GNU32-NEXT: [[CALL:%.*]] = tail call align 8 dereferenceable(40) i8* @_Znam(i64 40) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @op_new_constant_size( +; MSVC-NEXT: [[CALL:%.*]] = tail call align 16 dereferenceable(40) i8* @_Znam(i64 40) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call i8* @_Znam(i64 40) ret i8* %call } define noalias i8* @op_new_constant_size2() { -; CHECK-LABEL: @op_new_constant_size2( -; CHECK-NEXT: [[CALL:%.*]] = tail call dereferenceable(40) i8* @_Znwm(i64 40) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @op_new_constant_size2( +; GNU64-NEXT: [[CALL:%.*]] = tail call align 16 dereferenceable(40) i8* @_Znwm(i64 40) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @op_new_constant_size2( +; GNU32-NEXT: [[CALL:%.*]] = tail call align 8 dereferenceable(40) i8* @_Znwm(i64 40) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @op_new_constant_size2( +; MSVC-NEXT: [[CALL:%.*]] = tail call align 16 dereferenceable(40) i8* @_Znwm(i64 40) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call i8* @_Znwm(i64 40) ret i8* %call @@ -312,18 +446,34 @@ } define noalias i8* @strdup_constant_str() { -; CHECK-LABEL: @strdup_constant_str( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0)) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @strdup_constant_str( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0)) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @strdup_constant_str( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0)) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @strdup_constant_str( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0)) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0)) ret i8* %call } define noalias i8* @strdup_notconstant_str(i8 * %str) { -; CHECK-LABEL: @strdup_notconstant_str( -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @strdup(i8* [[STR:%.*]]) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @strdup_notconstant_str( +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @strdup(i8* [[STR:%.*]]) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @strdup_notconstant_str( +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 i8* @strdup(i8* [[STR:%.*]]) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @strdup_notconstant_str( +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 i8* @strdup(i8* [[STR:%.*]]) +; MSVC-NEXT: ret i8* [[CALL]] ; %call = tail call noalias i8* @strdup(i8* %str) ret i8* %call @@ -332,10 +482,20 @@ ; OSS-Fuzz #23214 ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23214 define noalias i8* @ossfuzz_23214() { -; CHECK-LABEL: @ossfuzz_23214( -; CHECK-NEXT: bb: -; CHECK-NEXT: [[CALL:%.*]] = tail call noalias dereferenceable_or_null(512) i8* @aligned_alloc(i64 -9223372036854775808, i64 512) -; CHECK-NEXT: ret i8* [[CALL]] +; GNU64-LABEL: @ossfuzz_23214( +; GNU64-NEXT: bb: +; GNU64-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(512) i8* @aligned_alloc(i64 -9223372036854775808, i64 512) +; GNU64-NEXT: ret i8* [[CALL]] +; +; GNU32-LABEL: @ossfuzz_23214( +; GNU32-NEXT: bb: +; GNU32-NEXT: [[CALL:%.*]] = tail call noalias align 8 dereferenceable_or_null(512) i8* @aligned_alloc(i64 -9223372036854775808, i64 512) +; GNU32-NEXT: ret i8* [[CALL]] +; +; MSVC-LABEL: @ossfuzz_23214( +; MSVC-NEXT: bb: +; MSVC-NEXT: [[CALL:%.*]] = tail call noalias align 16 dereferenceable_or_null(512) i8* @aligned_alloc(i64 -9223372036854775808, i64 512) +; MSVC-NEXT: ret i8* [[CALL]] ; bb: %and = and i64 -1, -9223372036854775808