
This reverts commit d50eaac12f0cdfe27e942290942b06889ab12a8c. Also fixes a bug calculating offsets for bit fields in the original patch.
182 lines
8.0 KiB
C
182 lines
8.0 KiB
C
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 5
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=gnu11 -verify -emit-llvm %s -o - | FileCheck %s
|
|
// expected-no-diagnostics
|
|
|
|
union U1 {
|
|
int x;
|
|
char y[5];
|
|
};
|
|
|
|
struct S1 {
|
|
int x;
|
|
long long y;
|
|
};
|
|
|
|
struct S2 {
|
|
unsigned char b1 : 3; // 1st 3 bits (in 1st byte) are b1
|
|
unsigned char : 2; // next 2 bits (in 1st byte) are blocked out as unused
|
|
unsigned char b2 : 6; // 6 bits for b2 - doesn't fit into the 1st byte => starts a 2nd
|
|
unsigned char b3 : 2; // 2 bits for b3 - next (and final) bits in the 2nd byte
|
|
int i;
|
|
};
|
|
|
|
struct S3 {
|
|
int x;
|
|
} __attribute__((__aligned__(8)));
|
|
|
|
struct S4 {
|
|
int a;
|
|
union U1 b;
|
|
};
|
|
|
|
struct S5 {
|
|
char x;
|
|
unsigned char y : 4;
|
|
unsigned char z : 7;
|
|
} __attribute__((packed));
|
|
|
|
// Test non-const initializer for union with padding.
|
|
// CHECK-LABEL: define dso_local void @test1(
|
|
// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[A:%.*]] = alloca [[UNION_U1:%.*]], align 4
|
|
// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
|
|
// CHECK-NEXT: store i32 [[TMP0]], ptr [[A]], align 4
|
|
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[A]], i64 4
|
|
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP1]], i8 0, i64 4, i1 false)
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test1(int x) {
|
|
union U1 a = {x};
|
|
}
|
|
|
|
// Test non-const initializer for struct with padding.
|
|
// CHECK-LABEL: define dso_local void @test2(
|
|
// CHECK-SAME: i64 noundef [[Y:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i64, align 8
|
|
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S1:%.*]], align 8
|
|
// CHECK-NEXT: store i64 [[Y]], ptr [[Y_ADDR]], align 8
|
|
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_S1]], ptr [[S]], i32 0, i32 0
|
|
// CHECK-NEXT: store i32 0, ptr [[X]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[S]], i64 4
|
|
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP0]], i8 0, i64 4, i1 false)
|
|
// CHECK-NEXT: [[Y1:%.*]] = getelementptr inbounds nuw [[STRUCT_S1]], ptr [[S]], i32 0, i32 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[Y_ADDR]], align 8
|
|
// CHECK-NEXT: store i64 [[TMP1]], ptr [[Y1]], align 8
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test2(long long y) {
|
|
struct S1 s = {.y = y};
|
|
}
|
|
|
|
// Test non-const initializer for struct with padding and bit fields.
|
|
// CHECK-LABEL: define dso_local void @test3(
|
|
// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S2:%.*]], align 4
|
|
// CHECK-NEXT: store i8 [[B]], ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: store i16 0, ptr [[S]], align 4
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[TMP0]] to i16
|
|
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[S]], align 4
|
|
// CHECK-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 7
|
|
// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD]], -8
|
|
// CHECK-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]]
|
|
// CHECK-NEXT: store i16 [[BF_SET]], ptr [[S]], align 4
|
|
// CHECK-NEXT: [[BF_LOAD1:%.*]] = load i16, ptr [[S]], align 4
|
|
// CHECK-NEXT: [[BF_CLEAR2:%.*]] = and i16 [[BF_LOAD1]], -16129
|
|
// CHECK-NEXT: [[BF_SET3:%.*]] = or i16 [[BF_CLEAR2]], 0
|
|
// CHECK-NEXT: store i16 [[BF_SET3]], ptr [[S]], align 4
|
|
// CHECK-NEXT: [[BF_LOAD4:%.*]] = load i16, ptr [[S]], align 4
|
|
// CHECK-NEXT: [[BF_CLEAR5:%.*]] = and i16 [[BF_LOAD4]], 16383
|
|
// CHECK-NEXT: [[BF_SET6:%.*]] = or i16 [[BF_CLEAR5]], 0
|
|
// CHECK-NEXT: store i16 [[BF_SET6]], ptr [[S]], align 4
|
|
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[S]], i64 2
|
|
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 2 [[TMP2]], i8 0, i64 2, i1 false)
|
|
// CHECK-NEXT: [[I:%.*]] = getelementptr inbounds nuw [[STRUCT_S2]], ptr [[S]], i32 0, i32 1
|
|
// CHECK-NEXT: store i32 0, ptr [[I]], align 4
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test3(unsigned char b) {
|
|
struct S2 s = {.b1 = b};
|
|
}
|
|
|
|
// Test non-const initializer for struct with padding at the end of the struct.
|
|
// CHECK-LABEL: define dso_local void @test4(
|
|
// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S3:%.*]], align 8
|
|
// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
|
|
// CHECK-NEXT: [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_S3]], ptr [[S]], i32 0, i32 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
|
|
// CHECK-NEXT: store i32 [[TMP0]], ptr [[X1]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[S]], i64 4
|
|
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP1]], i8 0, i64 4, i1 false)
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test4(int x) {
|
|
struct S3 s = {x};
|
|
}
|
|
|
|
// Test non-const initializer for union in struct.
|
|
// CHECK-LABEL: define dso_local void @test5(
|
|
// CHECK-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S4:%.*]], align 4
|
|
// CHECK-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
|
|
// CHECK-NEXT: store i32 [[B]], ptr [[B_ADDR]], align 4
|
|
// CHECK-NEXT: [[A1:%.*]] = getelementptr inbounds nuw [[STRUCT_S4]], ptr [[S]], i32 0, i32 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
|
// CHECK-NEXT: store i32 [[TMP0]], ptr [[A1]], align 4
|
|
// CHECK-NEXT: [[B2:%.*]] = getelementptr inbounds nuw [[STRUCT_S4]], ptr [[S]], i32 0, i32 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
|
|
// CHECK-NEXT: store i32 [[TMP1]], ptr [[B2]], align 4
|
|
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[B2]], i64 4
|
|
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP2]], i8 0, i64 4, i1 false)
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test5(int a, int b) {
|
|
struct S4 s = {a, {b}};
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test6(
|
|
// CHECK-SAME: i8 noundef signext [[X:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S5:%.*]], align 1
|
|
// CHECK-NEXT: store i8 [[X]], ptr [[X_ADDR]], align 1
|
|
// CHECK-NEXT: [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_S5]], ptr [[S]], i32 0, i32 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1
|
|
// CHECK-NEXT: store i8 [[TMP0]], ptr [[X1]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[S]], i64 1
|
|
// CHECK-NEXT: store i16 0, ptr [[TMP1]], align 1
|
|
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_S5]], ptr [[S]], i32 0, i32 1
|
|
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[Y]], align 1
|
|
// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD]], -16
|
|
// CHECK-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], 0
|
|
// CHECK-NEXT: store i16 [[BF_SET]], ptr [[Y]], align 1
|
|
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_S5]], ptr [[S]], i32 0, i32 1
|
|
// CHECK-NEXT: [[BF_LOAD2:%.*]] = load i16, ptr [[Z]], align 1
|
|
// CHECK-NEXT: [[BF_CLEAR3:%.*]] = and i16 [[BF_LOAD2]], -2033
|
|
// CHECK-NEXT: [[BF_SET4:%.*]] = or i16 [[BF_CLEAR3]], 0
|
|
// CHECK-NEXT: store i16 [[BF_SET4]], ptr [[Z]], align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test6(char x) {
|
|
struct S5 s = {.x = x};
|
|
}
|
|
//.
|
|
// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
|
|
// CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
|
|
//.
|
|
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
|
|
// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
|
|
//.
|