1// RUN: %clang_cc1 -triple x86_64 -emit-llvm -o - %s | opt -S -strip -o %t 2// RUN: FileCheck --check-prefix=CHECK-GLOBAL < %t %s 3// RUN: FileCheck --check-prefix=CHECK-FUNCTIONS < %t %s 4 5struct s0 { 6 int x; 7 int y __attribute__((packed)); 8}; 9 10// CHECK-GLOBAL: @s0_align_x = global i32 4 11 12// CHECK-GLOBAL: @s0_align_y = global i32 1 13 14// CHECK-GLOBAL: @s0_align = global i32 4 15int s0_align_x = __alignof(((struct s0*)0)->x); 16int s0_align_y = __alignof(((struct s0*)0)->y); 17int s0_align = __alignof(struct s0); 18 19// CHECK-FUNCTIONS-LABEL: define i32 @s0_load_x 20// CHECK-FUNCTIONS: [[s0_load_x:%.*]] = load i32* {{.*}}, align 4 21// CHECK-FUNCTIONS: ret i32 [[s0_load_x]] 22int s0_load_x(struct s0 *a) { return a->x; } 23// FIXME: This seems like it should be align 1. This is actually something which 24// has changed in llvm-gcc recently, previously both x and y would be loaded 25// with align 1 (in 2363.1 at least). 26// 27// CHECK-FUNCTIONS-LABEL: define i32 @s0_load_y 28// CHECK-FUNCTIONS: [[s0_load_y:%.*]] = load i32* {{.*}}, align 1 29// CHECK-FUNCTIONS: ret i32 [[s0_load_y]] 30int s0_load_y(struct s0 *a) { return a->y; } 31// CHECK-FUNCTIONS-LABEL: define void @s0_copy 32// CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 4, i1 false) 33void s0_copy(struct s0 *a, struct s0 *b) { *b = *a; } 34 35// 36 37struct s1 { 38 int x; 39 int y; 40} __attribute__((packed)); 41 42// CHECK-GLOBAL: @s1_align_x = global i32 1 43// CHECK-GLOBAL: @s1_align_y = global i32 1 44// CHECK-GLOBAL: @s1_align = global i32 1 45int s1_align_x = __alignof(((struct s1*)0)->x); 46int s1_align_y = __alignof(((struct s1*)0)->y); 47int s1_align = __alignof(struct s1); 48 49// CHECK-FUNCTIONS-LABEL: define i32 @s1_load_x 50// CHECK-FUNCTIONS: [[s1_load_x:%.*]] = load i32* {{.*}}, align 1 51// CHECK-FUNCTIONS: ret i32 [[s1_load_x]] 52int s1_load_x(struct s1 *a) { return a->x; } 53// CHECK-FUNCTIONS-LABEL: define i32 @s1_load_y 54// CHECK-FUNCTIONS: [[s1_load_y:%.*]] = load i32* {{.*}}, align 1 55// CHECK-FUNCTIONS: ret i32 [[s1_load_y]] 56int s1_load_y(struct s1 *a) { return a->y; } 57// CHECK-FUNCTIONS-LABEL: define void @s1_copy 58// CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 1, i1 false) 59void s1_copy(struct s1 *a, struct s1 *b) { *b = *a; } 60 61// 62 63#pragma pack(push,2) 64struct s2 { 65 int x; 66 int y; 67}; 68#pragma pack(pop) 69 70// CHECK-GLOBAL: @s2_align_x = global i32 2 71// CHECK-GLOBAL: @s2_align_y = global i32 2 72// CHECK-GLOBAL: @s2_align = global i32 2 73int s2_align_x = __alignof(((struct s2*)0)->x); 74int s2_align_y = __alignof(((struct s2*)0)->y); 75int s2_align = __alignof(struct s2); 76 77// CHECK-FUNCTIONS-LABEL: define i32 @s2_load_x 78// CHECK-FUNCTIONS: [[s2_load_y:%.*]] = load i32* {{.*}}, align 2 79// CHECK-FUNCTIONS: ret i32 [[s2_load_y]] 80int s2_load_x(struct s2 *a) { return a->x; } 81// CHECK-FUNCTIONS-LABEL: define i32 @s2_load_y 82// CHECK-FUNCTIONS: [[s2_load_y:%.*]] = load i32* {{.*}}, align 2 83// CHECK-FUNCTIONS: ret i32 [[s2_load_y]] 84int s2_load_y(struct s2 *a) { return a->y; } 85// CHECK-FUNCTIONS-LABEL: define void @s2_copy 86// CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 2, i1 false) 87void s2_copy(struct s2 *a, struct s2 *b) { *b = *a; } 88 89struct __attribute__((packed, aligned)) s3 { 90 short aShort; 91 int anInt; 92}; 93// CHECK-GLOBAL: @s3_1 = global i32 1 94int s3_1 = __alignof(((struct s3*) 0)->anInt); 95// CHECK-FUNCTIONS-LABEL: define i32 @test3( 96int test3(struct s3 *ptr) { 97 // CHECK-FUNCTIONS: [[PTR:%.*]] = getelementptr inbounds {{%.*}}* {{%.*}}, i32 0, i32 1 98 // CHECK-FUNCTIONS-NEXT: load i32* [[PTR]], align 1 99 return ptr->anInt; 100} 101