114 lines · c
1// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -fblocks -emit-llvm %s -o - | FileCheck %s2 3struct A {4 int value;5};6struct A *createA(void);7 8void use_block(int (^)(void));9 10// CHECK-LABEL: define void @test_block_nonaddress_capture(11void test_block_nonaddress_capture() {12 // CHECK: [[VAR:%.*]] = alloca ptr,13 // CHECK: [[BLOCK:%.*]] = alloca14 // flags - no copy/dispose required15 // CHECK: store i32 1073741824, ptr16 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds {{.*}} [[BLOCK]], i32 0, i32 517 // CHECK: [[LOAD:%.*]] = load ptr, ptr [[VAR]],18 // CHECK: store ptr [[LOAD]], ptr [[CAPTURE]]19 struct A * __ptrauth(1, 0, 15) ptr = createA();20 use_block(^{ return ptr->value; });21}22// CHECK-LABEL: define internal i32 @__test_block_nonaddress_capture_block_invoke23// CHECK: call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 1, i64 15)24 25// CHECK-LABEL: define void @test_block_address_capture(26void test_block_address_capture() {27 // CHECK: [[VAR:%.*]] = alloca ptr,28 // CHECK: [[BLOCK:%.*]] = alloca29 // flags - copy/dispose required30 // CHECK: store i32 1107296256, ptr31 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds {{.*}} [[BLOCK]], i32 0, i32 532 // CHECK: [[LOAD:%.*]] = load ptr, ptr [[VAR]],33 // CHECK: [[T0:%.*]] = ptrtoint ptr [[VAR]] to i6434 // CHECK: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 30)35 // CHECK: [[T0:%.*]] = ptrtoint ptr [[CAPTURE]] to i6436 // CHECK: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 30)37 // CHECK: [[T0:%.*]] = icmp ne ptr [[LOAD]], null38 // CHECK: br i1 [[T0]]39 // CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i6440 // CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]])41 // CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr42 // CHECK: [[T0:%.*]] = phi43 // CHECK: store ptr [[T0]], ptr [[CAPTURE]]44 struct A * __ptrauth(1, 1, 30) ptr = createA();45 use_block(^{ return ptr->value; });46}47// CHECK-LABEL: define internal i32 @__test_block_address_capture_block_invoke48// CHECK: call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 1, i64 {{%.*}})49 50// CHECK: linkonce_odr hidden void @__copy_helper_block_8_32p1d30(51// CHECK: [[OLDSLOT:%.*]] = getelementptr inbounds {{.*}} {{.*}}, i32 0, i32 552// CHECK: [[NEWSLOT:%.*]] = getelementptr inbounds {{.*}} {{.*}}, i32 0, i32 553// CHECK: [[LOAD:%.*]] = load ptr, ptr [[OLDSLOT]],54// CHECK: [[T0:%.*]] = ptrtoint ptr [[OLDSLOT]] to i6455// CHECK: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 30)56// CHECK: [[T0:%.*]] = ptrtoint ptr [[NEWSLOT]] to i6457// CHECK: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 30)58// CHECK: [[T0:%.*]] = icmp ne ptr [[LOAD]], null59// CHECK: br i1 [[T0]]60// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i6461// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]])62// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr63// CHECK: [[T0:%.*]] = phi64// CHECK: store ptr [[T0]], ptr [[NEWSLOT]]65 66// CHECK-LABEL: define void @test_block_nonaddress_byref_capture(67void test_block_nonaddress_byref_capture() {68 // flags - no copy/dispose required for byref69 // CHECK: store i32 0,70 // CHECK: call ptr @createA()71 // flags - copy/dispose required for block (because it captures byref)72 // CHECK: store i32 1107296256,73 __block struct A * __ptrauth(1, 0, 45) ptr = createA();74 use_block(^{ return ptr->value; });75}76 77// CHECK-LABEL: define void @test_block_address_byref_capture(78void test_block_address_byref_capture() {79 // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:.*]], align80 // CHECK: [[BLOCK:%.*]] = alloca81 // flags - byref requires copy/dispose82 // CHECK: store i32 33554432,83 // CHECK: store i32 48,84 // CHECK: [[COPY_HELPER_FIELD:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 485 // CHECK: [[T0:%.*]] = ptrtoint ptr [[COPY_HELPER_FIELD]] to i6486 // CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @__Block_byref_object_copy_ to i64), i32 0, i64 [[T0]])87 // CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr88 // CHECK: store ptr [[T2]], ptr [[COPY_HELPER_FIELD]], align89 // CHECK: [[DISPOSE_HELPER_FIELD:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 590 // CHECK: [[T0:%.*]] = ptrtoint ptr [[DISPOSE_HELPER_FIELD]] to i6491 // CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @__Block_byref_object_dispose_ to i64), i32 0, i64 [[T0]])92 // CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr93 // CHECK: store ptr [[T2]], ptr [[DISPOSE_HELPER_FIELD]], align94 // flags - copy/dispose required95 // CHECK: store i32 1107296256, ptr96 __block struct A * __ptrauth(1, 1, 60) ptr = createA();97 use_block(^{ return ptr->value; });98}99// CHECK-LABEL: define internal void @__Block_byref_object_copy_100// CHECK: [[NEWSLOT:%.*]] = getelementptr inbounds {{.*}} {{.*}}, i32 0, i32 6101// CHECK: [[OLDSLOT:%.*]] = getelementptr inbounds {{.*}} {{.*}}, i32 0, i32 6102// CHECK: [[LOAD:%.*]] = load ptr, ptr [[OLDSLOT]],103// CHECK: [[T0:%.*]] = ptrtoint ptr [[OLDSLOT]] to i64104// CHECK: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 60)105// CHECK: [[T0:%.*]] = ptrtoint ptr [[NEWSLOT]] to i64106// CHECK: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 60)107// CHECK: [[T0:%.*]] = icmp ne ptr [[LOAD]], null108// CHECK: br i1 [[T0]]109// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64110// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]])111// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr112// CHECK: [[T0:%.*]] = phi113// CHECK: store ptr [[T0]], ptr [[NEWSLOT]]114