diff --git a/clang/test/CodeGen/aarch64-ABI-align-packed.c b/clang/test/CodeGen/aarch64-ABI-align-packed.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/aarch64-ABI-align-packed.c @@ -0,0 +1,240 @@ +// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-eabi \ +// RUN: -target-feature +neon \ +// RUN: -emit-llvm -o - %s | FileCheck %s +#include +#include + +// natural alignment 16, adjusted alignment 16 +// expected alignment of copy on callee stack: 16 +struct non_packed_struct { + uint16x8_t M0; // member alignment 16 +}; + +// natural alignment 1, adjusted alignment 1 +// expected alignment of copy on callee stack: 8 +struct __attribute((packed)) packed_struct { + uint16x8_t M0; // member alignment 1, because the field is packed when the struct is packed +}; + +// natural alignment 1, adjusted alignment 1 +// expected alignment of copy on callee stack: 8 +struct packed_member { + uint16x8_t M0 __attribute((packed)); // member alignment 1 +}; + +// natural alignment 16, adjusted alignment 16 since __attribute((aligned (n))) sets the minimum alignment +// expected alignment of copy on callee stack: 16 +struct __attribute((aligned (8))) aligned_struct_8 { + uint16x8_t M0; // member alignment 16 +}; + +// natural alignment 16, adjusted alignment 16 +// expected alignment of copy on callee stack: 16 +struct aligned_member_8 { + uint16x8_t M0 __attribute((aligned (8))); // member alignment 16 since __attribute((aligned (n))) sets the minimum alignment +}; + +// natural alignment 8, adjusted alignment 8 +// expected alignment of copy on callee stack: 8 +#pragma pack(8) +struct pragma_packed_struct_8 { + uint16x8_t M0; // member alignment 8 because the struct is subject to packed(8) +}; + +// natural alignment 4, adjusted alignment 4 +// expected alignment of copy on callee stack: 8 +#pragma pack(4) +struct pragma_packed_struct_4 { + uint16x8_t M0; // member alignment 4 because the struct is subject to packed(4) +}; + +// Struct passed as a named argument +// CHECK-LABEL: define dso_local void @named_arg_non_packed_struct +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0:[0-9]+]] { +void named_arg_non_packed_struct(struct non_packed_struct arg) {} + +// CHECK-LABEL: define dso_local void @named_arg_packed_struct +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0]] { +void named_arg_packed_struct(struct packed_struct arg) {} + +// CHECK-LABEL: define dso_local void @named_arg_packed_member +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0]] { +void named_arg_packed_member(struct packed_member arg) {} + +// CHECK-LABEL: define dso_local void @named_arg_aligned_struct_8 +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0]] { +void named_arg_aligned_struct_8(struct aligned_struct_8 arg) {} + +// CHECK-LABEL: define dso_local void @named_arg_aligned_member_8 +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0]] { +void named_arg_aligned_member_8(struct aligned_member_8 arg) {} + +// CHECK-LABEL: define dso_local void @named_arg_pragma_packed_struct_8 +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0]] { +void named_arg_pragma_packed_struct_8(struct pragma_packed_struct_8 arg) {} + +// CHECK-LABEL: define dso_local void @named_arg_pragma_packed_struct_4 +// CHECK-SAME: ([1 x <8 x i16>] [[ARG_COERCE:%.*]]) #[[ATTR0]] { +void named_arg_pragma_packed_struct_4(struct pragma_packed_struct_4 arg) {} + +// Struct passed as a variadic argument +// CHECK-LABEL: define dso_local void @variadic_non_packed_struct +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[ON_CALLEE_STACK:.*]], ptr align 16 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_non_packed_struct(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct non_packed_struct on_callee_stack; + on_callee_stack = va_arg(vl, struct non_packed_struct); +} + +// CHECK-LABEL: define dso_local void @variadic_packed_struct +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[ON_CALLEE_STACK:.*]], ptr align 8 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_packed_struct(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct packed_struct on_callee_stack; + on_callee_stack = va_arg(vl, struct packed_struct); +} + +// CHECK-LABEL: define dso_local void @variadic_packed_member +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[ON_CALLEE_STACK:.*]], ptr align 8 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_packed_member(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct packed_member on_callee_stack; + on_callee_stack = va_arg(vl, struct packed_member); +} + +// CHECK-LABEL: define dso_local void @variadic_aligned_struct_8 +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[ON_CALLEE_STACK:.*]], ptr align 16 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_aligned_struct_8(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct aligned_struct_8 on_callee_stack; + on_callee_stack = va_arg(vl, struct aligned_struct_8); +} + +// CHECK-LABEL: define dso_local void @variadic_aligned_member_8 +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[ON_CALLEE_STACK:.*]], ptr align 16 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_aligned_member_8(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct aligned_member_8 on_callee_stack; + on_callee_stack = va_arg(vl, struct aligned_member_8); +} + +// CHECK-LABEL: define dso_local void @variadic_pragma_packed_struct_8 +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ON_CALLEE_STACK:.*]], ptr align 8 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_pragma_packed_struct_8(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct pragma_packed_struct_8 on_callee_stack; + on_callee_stack = va_arg(vl, struct pragma_packed_struct_8); +} + +// CHECK-LABEL: define dso_local void @variadic_pragma_packed_struct_4 +// CHECK: vaarg.end: +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ON_CALLEE_STACK:.*]], ptr align 8 [[VAARGS_ADDR:.*]], i64 16, i1 false) +// CHECK-NEXT: ret void +void variadic_pragma_packed_struct_4(int named_arg, ...) { + va_list vl; + va_start(vl, named_arg); + struct pragma_packed_struct_4 on_callee_stack; + on_callee_stack = va_arg(vl, struct pragma_packed_struct_4); +} + +// CHECK-LABEL: define dso_local void @test_non_packed_struct +// CHECK: call void @named_arg_non_packed_struct([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_NON_PACKED_STRUCT:.*]], ptr [[P_NON_PACKED_STRUCT:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7:.*]], align 16 +// CHECK-NEXT: call void (i32, ...) @variadic_non_packed_struct(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_non_packed_struct() { + struct non_packed_struct P_non_packed_struct = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_non_packed_struct(P_non_packed_struct); + variadic_non_packed_struct(0, P_non_packed_struct); +} + +// CHECK-LABEL: define dso_local void @test_packed_struct +// CHECK: call void @named_arg_packed_struct([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_PACKED_STRUCT:.*]], ptr [[P_PACKED_STRUCT:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7:.*]], align 1 +// CHECK-NEXT: call void (i32, ...) @variadic_packed_struct(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_packed_struct() { + struct packed_struct P_packed_struct = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_packed_struct(P_packed_struct); + variadic_packed_struct(0, P_packed_struct); +} + +// CHECK-LABEL: define dso_local void @test_packed_member +// CHECK: call void @named_arg_packed_member([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_PACKED_MEMBER:.*]], ptr [[P_PACKED_MEMBER:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7:.*]], align 1 +// CHECK-NEXT: call void (i32, ...) @variadic_packed_member(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_packed_member() { + struct packed_member P_packed_member = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_packed_member(P_packed_member); + variadic_packed_member(0, P_packed_member); +} + +// CHECK-LABEL: define dso_local void @test_aligned_struct_8 +// CHECK: call void @named_arg_aligned_struct_8([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_ALIGNED_STRUCT_8:.*]], ptr [[P_ALIGNED_STRUCT_8:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7:.*]], align 16 +// CHECK-NEXT: call void (i32, ...) @variadic_aligned_struct_8(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_aligned_struct_8() { + struct aligned_struct_8 P_aligned_struct_8 = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_aligned_struct_8(P_aligned_struct_8); + variadic_aligned_struct_8(0, P_aligned_struct_8); +} + +// CHECK-LABEL: define dso_local void @test_aligned_member_8 +// CHECK: call void @named_arg_aligned_member_8([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_ALIGNED_MEMBER_8:.*]], ptr [[P_ALIGNED_MEMBER_8:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7]], align 16 +// CHECK-NEXT: call void (i32, ...) @variadic_aligned_member_8(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_aligned_member_8() { + struct aligned_member_8 P_aligned_member_8 = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_aligned_member_8(P_aligned_member_8); + variadic_aligned_member_8(0, P_aligned_member_8); +} + +// CHECK-LABEL: define dso_local void @test_pragma_packed_struct_8 +// CHECK: call void @named_arg_pragma_packed_struct_8([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_PRAGMA_PACKED_STRUCT_8:.*]], ptr [[P_PRAGMA_PACKED_STRUCT_8:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7:.*]], align 8 +// CHECK-NEXT: call void (i32, ...) @variadic_pragma_packed_struct_8(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_pragma_packed_struct_8() { + struct pragma_packed_struct_8 P_pragma_packed_struct_8 = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_pragma_packed_struct_8(P_pragma_packed_struct_8); + variadic_pragma_packed_struct_8(0, P_pragma_packed_struct_8); +} + +// CHECK-LABEL: define dso_local void @test_pragma_packed_struct_4 +// CHECK: call void @named_arg_pragma_packed_struct_4([1 x <8 x i16>] [[TMP3:.*]]) +// CHECK-NEXT: [[COERCE_DIVE7:%.*]] = getelementptr inbounds [[STRUCT_PRAGMA_PACKED_STRUCT_4:.*]], ptr [[P_PRAGMA_PACKED_STRUCT_4:.*]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = load [1 x <8 x i16>], ptr [[COERCE_DIVE7:.*]], align 4 +// CHECK-NEXT: call void (i32, ...) @variadic_pragma_packed_struct_4(i32 noundef 0, [1 x <8 x i16>] [[TMP4:.*]]) +// CHECK-NEXT: ret void +void test_pragma_packed_struct_4() { + struct pragma_packed_struct_4 P_pragma_packed_struct_4 = {vld1q_u16(((const uint16_t[8]){1234, 0, 0, 0, 0, 0, 0, 0}))}; + named_arg_pragma_packed_struct_4(P_pragma_packed_struct_4); + variadic_pragma_packed_struct_4(0, P_pragma_packed_struct_4); +}