| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,275 @@ | ||
| // 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[16]; | ||
| }; | ||
|
|
||
| struct S1 { | ||
| int x; | ||
| union U1 y; | ||
| }; | ||
|
|
||
| union U2 { | ||
| int x; | ||
| char y[16]; | ||
| } __attribute__((__aligned__(32))); | ||
|
|
||
| struct S2 { | ||
| int x; | ||
| long long y; | ||
| char z[8]; | ||
| } __attribute__((__aligned__(32))); | ||
|
|
||
| struct S3 { | ||
| char x; | ||
| unsigned char y : 4; | ||
| unsigned char z : 7; | ||
| } __attribute__((packed)); | ||
|
|
||
| union U1 global_u1 = {}; | ||
|
|
||
| union U1 global_u2 = {3}; | ||
|
|
||
| union U1 global_u2_from_cast = (union U1)3; | ||
|
|
||
| struct S1 global_s1 = {}; | ||
|
|
||
| struct S1 global_s2 = { | ||
| .x = 3, | ||
| }; | ||
|
|
||
| struct S1 global_s3 = {.x = 3, .y = {.x = 6}}; | ||
|
|
||
| const union U1 global_const_u1 = {4}; | ||
| struct S1 global_s3_from_const_u1 = {.y = global_const_u1}; | ||
|
|
||
| union U2 global_u3 = {}; | ||
|
|
||
| struct S2 global_s4 = {}; | ||
|
|
||
| struct S2 global_s5 = {.x = 1}; | ||
|
|
||
| struct S3 global_s6 = {101, 15, 123}; | ||
|
|
||
| // Test empty initializer for union. | ||
| //. | ||
| // CHECK: @global_u1 = global %union.U1 zeroinitializer, align 4 | ||
| // CHECK: @global_u2 = global %union.U1 { i32 3, [12 x i8] zeroinitializer }, align 4 | ||
| // CHECK: @global_u2_from_cast = global { i32, [12 x i8] } { i32 3, [12 x i8] zeroinitializer }, align 4 | ||
| // CHECK: @global_s1 = global %struct.S1 zeroinitializer, align 4 | ||
| // CHECK: @global_s2 = global %struct.S1 { i32 3, %union.U1 zeroinitializer }, align 4 | ||
| // CHECK: @global_s3 = global %struct.S1 { i32 3, %union.U1 { i32 6, [12 x i8] zeroinitializer } }, align 4 | ||
| // CHECK: @global_const_u1 = constant %union.U1 { i32 4, [12 x i8] zeroinitializer }, align 4 | ||
| // CHECK: @global_s3_from_const_u1 = global %struct.S1 { i32 0, %union.U1 { i32 4, [12 x i8] zeroinitializer } }, align 4 | ||
| // CHECK: @global_u3 = global %union.U2 zeroinitializer, align 32 | ||
| // CHECK: @global_s4 = global { i32, [4 x i8], i64, [8 x i8], [8 x i8] } zeroinitializer, align 32 | ||
| // CHECK: @global_s5 = global { i32, [4 x i8], i64, [8 x i8], [8 x i8] } { i32 1, [4 x i8] zeroinitializer, i64 0, [8 x i8] zeroinitializer, [8 x i8] zeroinitializer }, align 32 | ||
| // CHECK: @global_s6 = global { i8, i8, i8 } { i8 101, i8 -65, i8 7 }, align 1 | ||
| // CHECK: @test2.a = internal global %union.U1 zeroinitializer, align 4 | ||
| // CHECK: @__const.test3.a = private unnamed_addr constant %union.U1 { i32 3, [12 x i8] zeroinitializer }, align 4 | ||
| // CHECK: @test4.a = internal global %union.U1 { i32 3, [12 x i8] zeroinitializer }, align 4 | ||
| // CHECK: @test6.s = internal global %struct.S1 zeroinitializer, align 4 | ||
| // CHECK: @__const.test7.s = private unnamed_addr constant %struct.S1 { i32 3, %union.U1 zeroinitializer }, align 4 | ||
| // CHECK: @test8.s = internal global %struct.S1 { i32 3, %union.U1 zeroinitializer }, align 4 | ||
| // CHECK: @__const.test9.s = private unnamed_addr constant %struct.S1 { i32 3, %union.U1 { i32 6, [12 x i8] zeroinitializer } }, align 4 | ||
| // CHECK: @test10.s = internal global %struct.S1 { i32 3, %union.U1 { i32 6, [12 x i8] zeroinitializer } }, align 4 | ||
| // CHECK: @test12.a = internal global %union.U2 zeroinitializer, align 32 | ||
| // CHECK: @test14.s = internal global { i32, [4 x i8], i64, [8 x i8], [8 x i8] } zeroinitializer, align 32 | ||
| // CHECK: @__const.test15.s = private unnamed_addr constant { i32, [4 x i8], i64, [8 x i8], [8 x i8] } { i32 1, [4 x i8] zeroinitializer, i64 0, [8 x i8] zeroinitializer, [8 x i8] zeroinitializer }, align 32 | ||
| // CHECK: @test16.s = internal global { i32, [4 x i8], i64, [8 x i8], [8 x i8] } { i32 1, [4 x i8] zeroinitializer, i64 0, [8 x i8] zeroinitializer, [8 x i8] zeroinitializer }, align 32 | ||
| //. | ||
| // CHECK-LABEL: define dso_local void @test1( | ||
| // CHECK-SAME: ) #[[ATTR0:[0-9]+]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[A:%.*]] = alloca [[UNION_U1:%.*]], align 4 | ||
| // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[A]], i8 0, i64 16, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test1() { | ||
| union U1 a = {}; | ||
| } | ||
|
|
||
| // Test empty initializer for union. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test2( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test2() { | ||
| static union U1 a = {}; | ||
| } | ||
|
|
||
| // Test only initializing a small field for union. | ||
| // CHECK-LABEL: define dso_local void @test3( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[A:%.*]] = alloca [[UNION_U1:%.*]], align 4 | ||
| // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[A]], ptr align 4 @__const.test3.a, i64 16, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test3() { | ||
| union U1 a = {3}; | ||
| } | ||
|
|
||
| // Test only initializing a small field for union. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test4( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test4() { | ||
| static union U1 a = {3}; | ||
| } | ||
|
|
||
| // Test union in struct. Use empty initializer for the struct. | ||
| // CHECK-LABEL: define dso_local void @test5( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S1:%.*]], align 4 | ||
| // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[S]], i8 0, i64 20, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test5() { | ||
| struct S1 s = {}; | ||
| } | ||
|
|
||
| // Test union in struct. Use empty initializer for the struct. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test6( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test6() { | ||
| static struct S1 s = {}; | ||
| } | ||
|
|
||
| // Test union in struct. Initialize other fields of the struct. | ||
| // CHECK-LABEL: define dso_local void @test7( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S1:%.*]], align 4 | ||
| // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[S]], ptr align 4 @__const.test7.s, i64 20, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test7() { | ||
| struct S1 s = { | ||
| .x = 3, | ||
| }; | ||
| } | ||
|
|
||
| // Test union in struct. Initialize other fields of the struct. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test8( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test8() { | ||
| static struct S1 s = { | ||
| .x = 3, | ||
| }; | ||
| } | ||
|
|
||
| // Test union in struct. Initialize a small field for union. | ||
| // CHECK-LABEL: define dso_local void @test9( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S1:%.*]], align 4 | ||
| // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[S]], ptr align 4 @__const.test9.s, i64 20, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test9() { | ||
| struct S1 s = {.x = 3, | ||
| .y = { | ||
| .x = 6, | ||
| }}; | ||
| } | ||
|
|
||
| // Test union in struct. Initialize a small field for union. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test10( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test10() { | ||
| static struct S1 s = {.x = 3, | ||
| .y = { | ||
| .x = 6, | ||
| }}; | ||
| } | ||
|
|
||
| // Test empty initializer for union with padding. | ||
| // CHECK-LABEL: define dso_local void @test11( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[A:%.*]] = alloca [[UNION_U2:%.*]], align 32 | ||
| // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 32 [[A]], i8 0, i64 32, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test11() { | ||
| union U2 a = {}; | ||
| } | ||
|
|
||
| // Test empty initializer for union with padding. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test12( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test12() { | ||
| static union U2 a = {}; | ||
| } | ||
|
|
||
| // Test empty initializer for struct with padding. | ||
| // CHECK-LABEL: define dso_local void @test13( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S2:%.*]], align 32 | ||
| // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 32 [[S]], i8 0, i64 32, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test13() { | ||
| struct S2 s = {}; | ||
| } | ||
|
|
||
| // Test empty initializer for struct with padding. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test14( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test14() { | ||
| static struct S2 s = {}; | ||
| } | ||
|
|
||
| // Test partial initialization for struct with padding. | ||
| // CHECK-LABEL: define dso_local void @test15( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S2:%.*]], align 32 | ||
| // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 [[S]], ptr align 32 @__const.test15.s, i64 32, i1 false) | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test15() { | ||
| struct S2 s = {.x = 1}; | ||
| } | ||
|
|
||
| // Test partial initialization for struct with padding. Use static variable. | ||
| // CHECK-LABEL: define dso_local void @test16( | ||
| // CHECK-SAME: ) #[[ATTR0]] { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void test16() { | ||
| static struct S2 s = {.x = 1}; | ||
| } | ||
| //. | ||
| // 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: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } | ||
| //. | ||
| // CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} | ||
| // CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} | ||
| //. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| // 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 {{.*}}"} | ||
| //. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| expression -- | ||
| a | ||
| + | ||
| b | ||
|
|
||
| quit |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # RUN: echo quit | %lldb -o "expression a+b" \ | ||
| # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK1 | ||
| # (lldb) expression a+b | ||
| # CHECK1:{{^ \^ \^}} | ||
| # CHECK1: {{^ | error: use of undeclared identifier 'b'}} | ||
| # CHECK1: {{^ error: use of undeclared identifier 'a'}} | ||
|
|
||
| # RUN: echo quit | %lldb -o "expr a" \ | ||
| # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK2 | ||
| # (lldb) expr a | ||
| # CHECK2:{{^ \^}} | ||
|
|
||
| # RUN: echo quit | %lldb -o "expr -i 0 -o 0 -- a" \ | ||
| # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK3 | ||
| # (lldb) expr -i 0 -o 0 -- a | ||
| # CHECK3:{{^ \^}} | ||
| # CHECK3: {{^ error: use of undeclared identifier 'a'}} | ||
|
|
||
| # RUN: echo "int main(){return 0;}">%t.c | ||
| # RUN: %clang_host %t.c -o %t.exe | ||
| # RUN: echo quit | %lldb %t.exe -o "b main" -o r -o \ | ||
| # RUN: "expr --top-level -- template<typename T> T FOO(T x) { return x/2;}" -o \ | ||
| # RUN: "expression -- FOO(\"\")" 2>&1 | FileCheck %s --check-prefix=CHECK4 | ||
| # (lldb) expression -- FOO("") | ||
| # CHECK4:{{^ \^}} | ||
| # CHECK4: {{^ note: in instantiation of function template}} | ||
| # CHECK4: error: <user expression | ||
|
|
||
| # RUN: echo expression --\na\n+\nb | ||
| # RUN: cat %S/Inputs/multiline-expr.txt | %lldb 2>&1 | FileCheck %s --strict-whitespace --check-prefix=CHECK5 | ||
| # CHECK5: error: <user{{.*}}a | ||
| # CHECK5: error: <user{{.*}}b |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| ; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128" | ||
| target triple = "mips64--linux" | ||
|
|
||
| define i32 @foo(i32 %guard, ...) { | ||
| %vl = alloca ptr, align 8 | ||
| call void @llvm.lifetime.start.p0(i64 32, ptr %vl) | ||
| call void @llvm.va_start(ptr %vl) | ||
| call void @llvm.va_end(ptr %vl) | ||
| call void @llvm.lifetime.end.p0(i64 32, ptr %vl) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; First, check allocation of the save area. | ||
|
|
||
| ; CHECK-LABEL: @foo | ||
| ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls | ||
| ; CHECK: [[B:%.*]] = add i64 0, [[A]] | ||
| ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]] | ||
|
|
||
| ; CHECK: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 [[B]], i1 false) | ||
|
|
||
| ; CHECK: [[D:%.*]] = call i64 @llvm.umin.i64(i64 [[B]], i64 800) | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C]], ptr align 8 @__msan_va_arg_tls, i64 [[D]], i1 false) | ||
|
|
||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
| declare void @llvm.va_start(ptr) #2 | ||
| declare void @llvm.va_end(ptr) #2 | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| define i32 @bar() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls | ||
| ; array. The first argument is stored at position 4, since it's right | ||
| ; justified. | ||
| ; CHECK-LABEL: @bar | ||
| ; CHECK: store i32 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 4) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 16) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check multiple fixed arguments. | ||
| declare i32 @foo2(i32 %g1, i32 %g2, ...) | ||
| define i32 @bar2() { | ||
| %1 = call i32 (i32, i32, ...) @foo2(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar2 | ||
| ; CHECK: store i64 0, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) | ||
|
|
||
| ; CHECK: declare void @__msan_maybe_warning_1(i8 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_1(i8 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_2(i16 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_2(i16 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_4(i32 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_4(i32 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_8(i64 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_8(i64 signext, ptr, i32 signext) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| ; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128" | ||
| target triple = "mips64--linux" | ||
|
|
||
| define i32 @foo(i32 %guard, ...) { | ||
| %vl = alloca ptr, align 8 | ||
| call void @llvm.lifetime.start.p0(i64 32, ptr %vl) | ||
| call void @llvm.va_start(ptr %vl) | ||
| call void @llvm.va_end(ptr %vl) | ||
| call void @llvm.lifetime.end.p0(i64 32, ptr %vl) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; First, check allocation of the save area. | ||
|
|
||
| ; CHECK-LABEL: @foo | ||
| ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls | ||
| ; CHECK: [[B:%.*]] = add i64 0, [[A]] | ||
| ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]] | ||
|
|
||
| ; CHECK: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 [[B]], i1 false) | ||
|
|
||
| ; CHECK: [[D:%.*]] = call i64 @llvm.umin.i64(i64 [[B]], i64 800) | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C]], ptr align 8 @__msan_va_arg_tls, i64 [[D]], i1 false) | ||
|
|
||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
| declare void @llvm.va_start(ptr) #2 | ||
| declare void @llvm.va_end(ptr) #2 | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| define i32 @bar() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls | ||
| ; array. The first argument is stored at position 4, since it's right | ||
| ; justified. | ||
| ; CHECK-LABEL: @bar | ||
| ; CHECK: store i32 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 4) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 16) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check multiple fixed arguments. | ||
| declare i32 @foo2(i32 %g1, i32 %g2, ...) | ||
| define i32 @bar2() { | ||
| %1 = call i32 (i32, i32, ...) @foo2(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar2 | ||
| ; CHECK: store i64 0, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) | ||
|
|
||
| ; CHECK: declare void @__msan_maybe_warning_1(i8 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_1(i8 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_2(i16 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_2(i16 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_4(i32 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_4(i32 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_8(i64 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_8(i64 signext, ptr, i32 signext) |