blob: f22f76a315e00f22cd9b52f79819590a948ab4af [file] [edit]
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
// RUN: -ffreestanding -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
// RUN: -ffreestanding -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \
// RUN: --check-prefix=CHECK-FP80
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
// RUN: -ffreestanding -mlong-double-80 -fdump-record-layouts -fsyntax-only %s \
// RUN: | FileCheck %s --check-prefix=CHECK-LAYOUT
// Test that #pragma pack does not reduce natural type alignment for vector
// and x86_fp80 types when used as array elements (matching MSVC behavior).
#include <xmmintrin.h>
// Simple array-like struct with vector type under pragma pack.
#pragma pack(push, 8)
template<typename T, unsigned N>
struct array {
T _Elems[N];
};
#pragma pack(pop)
// CHECK-LABEL: define {{.*}} @"?test_vector_array
void test_vector_array() {
// CHECK: %matrix = alloca %struct.array, align 16
array<__m128, 16> matrix;
matrix._Elems[0] = _mm_setzero_ps();
}
// Struct containing vector under pragma pack.
#pragma pack(push, 8)
struct VectorStruct {
__m128 vec;
};
struct ArrayOfVectorStruct {
VectorStruct elems[4];
};
#pragma pack(pop)
// CHECK-LABEL: define {{.*}} @"?test_vector_struct
void test_vector_struct() {
// CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16
ArrayOfVectorStruct s;
s.elems[0].vec = _mm_setzero_ps();
}
// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack.
struct Klass { long double a; };
#pragma pack(push, 8)
template<typename T, unsigned N>
struct fp80_array {
T _Elems[N];
void fill(const T& val) {
for (unsigned i = 0; i < N; i++)
_Elems[i] = val;
}
};
#pragma pack(pop)
// CHECK-FP80-LABEL: define {{.*}} @"?test_fp80_array
void test_fp80_array() {
// CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16
fp80_array<Klass, 16> matrix;
matrix.fill({});
}
// Struct containing x86_fp80 under pragma pack.
#pragma pack(push, 8)
struct Fp80Struct {
long double val;
};
struct ArrayOfFp80Struct {
Fp80Struct elems[4];
};
#pragma pack(pop)
// CHECK-FP80-LABEL: define {{.*}} @"?test_fp80_struct
void test_fp80_struct() {
// CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16
ArrayOfFp80Struct s;
s.elems[0].val = 1.0L;
}
// An alignment attribute on a typedef of x86_fp80 makes the alignment
// requirement come from the typedef rather than from the pragma-pack-resistant
// natural alignment of the underlying type.
// The typedef raises the alignment above the natural alignment.
struct TypedefOverAligned {
typedef long double foo __attribute__((aligned(32)));
foo bar;
};
// CHECK-LAYOUT-LABEL: 0 | struct TypedefOverAligned{{$}}
// CHECK-LAYOUT-NEXT: 0 | foo bar
// CHECK-LAYOUT-NEXT: | [sizeof=32, align=32,
// CHECK-LAYOUT-NEXT: | nvsize=32, nvalign=32]
// The typedef's alignment attribute is not reduced by #pragma pack.
#pragma pack(push, 8)
struct TypedefOverAlignedPacked {
char c;
typedef long double foo __attribute__((aligned(32)));
foo bar;
};
#pragma pack(pop)
// CHECK-LAYOUT-LABEL: 0 | struct TypedefOverAlignedPacked{{$}}
// CHECK-LAYOUT-NEXT: 0 | char c
// CHECK-LAYOUT-NEXT: 32 | foo bar
// CHECK-LAYOUT-NEXT: | [sizeof=64, align=32,
// CHECK-LAYOUT-NEXT: | nvsize=48, nvalign=32]
// The typedef lowers the alignment below the natural alignment, so the field
// no longer resists #pragma pack.
#pragma pack(push, 8)
typedef long double fp80_align4 __attribute__((aligned(4)));
struct TypedefUnderAlignedPacked {
char c;
fp80_align4 x;
};
#pragma pack(pop)
// CHECK-LAYOUT-LABEL: 0 | struct TypedefUnderAlignedPacked{{$}}
// CHECK-LAYOUT-NEXT: 0 | char c
// CHECK-LAYOUT-NEXT: 8 | fp80_align4 x
// CHECK-LAYOUT-NEXT: | [sizeof=24, align=8,
// CHECK-LAYOUT-NEXT: | nvsize=24, nvalign=8]
// A plain x86_fp80 field resists #pragma pack.
#pragma pack(push, 8)
struct PlainFp80Packed {
char c;
long double x;
};
#pragma pack(pop)
// CHECK-LAYOUT-LABEL: 0 | struct PlainFp80Packed{{$}}
// CHECK-LAYOUT-NEXT: 0 | char c
// CHECK-LAYOUT-NEXT: 16 | long double x
// CHECK-LAYOUT-NEXT: | [sizeof=32, align=16,
// CHECK-LAYOUT-NEXT: | nvsize=32, nvalign=16]
// A typedef without an alignment attribute keeps the pragma-pack resistance.
#pragma pack(push, 8)
typedef long double fp80_t;
struct TypedefNoAttrPacked {
char c;
fp80_t x;
};
#pragma pack(pop)
// CHECK-LAYOUT-LABEL: 0 | struct TypedefNoAttrPacked{{$}}
// CHECK-LAYOUT-NEXT: 0 | char c
// CHECK-LAYOUT-NEXT: 16 | fp80_t x
// CHECK-LAYOUT-NEXT: | [sizeof=32, align=16,
// CHECK-LAYOUT-NEXT: | nvsize=32, nvalign=16]
int typedef_sizes[] = {
sizeof(TypedefOverAligned), sizeof(TypedefOverAlignedPacked),
sizeof(TypedefUnderAlignedPacked), sizeof(PlainFp80Packed),
sizeof(TypedefNoAttrPacked)};