ConstantInt *Op0C = dyn_cast<ConstantInt>(Call.getOperand(0));
ConstantInt *Op1C =
(NumArgs == 1) ? nullptr : dyn_cast<ConstantInt>(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;
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(
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
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)
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)
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() {