324 lines · plain
1// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -o - %s | FileCheck -check-prefix CHECK %s2// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -O1 -o - %s | FileCheck -check-prefix CHECK-O1 %s3// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s4// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -fobjc-avoid-heapify-local-blocks -o - %s | FileCheck -check-prefix CHECK-NOHEAP %s5 6// CHECK: [[A:.*]] = type { i64, [10 x ptr] }7// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }8// CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 }9 10// CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"11 12// If a __block variable requires extended layout information *and*13// a copy/dispose helper, be sure to adjust the offsets used in copy/dispose.14namespace test0 {15 struct A {16 unsigned long count;17 id data[10];18 };19 20 void foo() {21 __block A v;22 ^{ (void)v; };23 }24 // CHECK-LABEL: define{{.*}} void @_ZN5test03fooEv() 25 // CHECK: [[V:%.*]] = alloca [[BYREF_A:%.*]], align 826 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr [[V]], i32 0, i32 427 // CHECK-NEXT: store ptr [[COPY_HELPER:@.*]], ptr [[T0]]28 // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr [[V]], i32 0, i32 529 // CHECK-NEXT: store ptr [[DISPOSE_HELPER:@.*]], ptr [[T0]]30 // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr [[V]], i32 0, i32 631 // CHECK-NEXT: store ptr [[LAYOUT0]], ptr [[T0]]32 // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr [[V]], i32 0, i32 733 // CHECK-NEXT: call void @_ZN5test01AC1Ev(ptr {{[^,]*}} [[T0]])34 // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr [[V]], i32 0, i32 735 // CHECK: call void @_Block_object_dispose(ptr [[V]], i32 8)36 // CHECK-NEXT: call void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[T0]])37 // CHECK-NEXT: ret void38 39 // CHECK: define internal void [[COPY_HELPER]](40 // CHECK: [[T1:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr {{.*}}, i32 0, i32 741 // CHECK-NEXT: load42 // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr {{.*}}, i32 0, i32 743 // CHECK-NEXT: call void @_ZN5test01AC1ERKS0_(ptr {{[^,]*}} [[T1]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[T3]])44 // CHECK-NEXT: ret void45 46 // CHECK: define internal void [[DISPOSE_HELPER]](47 // CHECK: [[T1:%.*]] = getelementptr inbounds nuw [[BYREF_A]], ptr {{.*}}, i32 0, i32 748 // CHECK-NEXT: call void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[T1]])49 // CHECK-NEXT: ret void50}51 52// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_53// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_54// CHECK-LABEL-O1: define linkonce_odr hidden void @__copy_helper_block_55// CHECK-LABEL-O1: define linkonce_odr hidden void @__destroy_helper_block_56 57namespace test1 {58 59// Check that copy/dispose helper functions are exception safe.60 61// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_32s40r48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(62 63// CHECK: %[[V9:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 564// CHECK: %[[V10:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 565// CHECK: %[[BLOCKCOPY_SRC2:.*]] = load ptr, ptr %[[V9]], align 866// CHECK: store ptr null, ptr %[[V10]], align 867// CHECK: call void @llvm.objc.storeStrong(ptr %[[V10]], ptr %[[BLOCKCOPY_SRC2]])68 69// CHECK: %[[V4:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 670// CHECK: %[[V5:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 671// CHECK: %[[BLOCKCOPY_SRC:.*]] = load ptr, ptr %[[V4]], align 872// CHECK: call void @_Block_object_assign(ptr %[[V5]], ptr %[[BLOCKCOPY_SRC]], i32 8)73 74// CHECK: %[[V7:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 775// CHECK: %[[V8:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 776// CHECK: call void @llvm.objc.copyWeak(ptr %[[V8]], ptr %[[V7]])77 78// CHECK: %[[V11:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 879// CHECK: %[[V12:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 880// CHECK: invoke void @_ZN5test12S0C1ERKS0_(ptr {{[^,]*}} %[[V12]], ptr noundef nonnull align 4 dereferenceable(4) %[[V11]])81// CHECK: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]82 83// CHECK: [[INVOKE_CONT]]:84// CHECK: %[[V13:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 985// CHECK: %[[V14:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 986// CHECK: invoke void @_ZN5test12S0C1ERKS0_(ptr {{[^,]*}} %[[V14]], ptr noundef nonnull align 4 dereferenceable(4) %[[V13]])87// CHECK: to label %[[INVOKE_CONT4:.*]] unwind label %[[LPAD3:.*]]88 89// CHECK: [[INVOKE_CONT4]]:90// CHECK: ret void91 92// CHECK: [[LPAD]]:93// CHECK: br label %[[EHCLEANUP:.*]]94 95// CHECK: [[LPAD3]]:96// CHECK: invoke void @_ZN5test12S0D1Ev(ptr {{[^,]*}} %[[V12]])97// CHECK: to label %[[INVOKE_CONT5:.*]] unwind label %[[TERMINATE_LPAD:.*]]98 99// CHECK: [[INVOKE_CONT5]]:100// CHECK: br label %[[EHCLEANUP]]101 102// CHECK: [[EHCLEANUP]]:103// CHECK: call void @llvm.objc.destroyWeak(ptr %[[V8]])104// CHECK: %[[V21:.*]] = load ptr, ptr %[[V5]], align 8105// CHECK: call void @_Block_object_dispose(ptr %[[V21]], i32 8)106// CHECK: call void @llvm.objc.storeStrong(ptr %[[V10]], ptr null)107// CHECK: br label %[[EH_RESUME:.*]]108 109// CHECK: [[EH_RESUME]]:110// CHECK: resume { ptr, i32 }111 112// CHECK: [[TERMINATE_LPAD]]:113// CHECK: call void @__clang_call_terminate(114 115// CHECK-O1-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_32s40r48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(116// CHECK-O1: call void @llvm.objc.release({{.*}}) {{.*}} !clang.imprecise_release117// CHECK-NOEXCP: define linkonce_odr hidden void @__copy_helper_block_8_32s40r48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(118 119// CHECK: define linkonce_odr hidden void @__destroy_helper_block_ea8_32s40r48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(120// CHECK: %[[V4:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 5121// CHECK: %[[V2:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 6122// CHECK: %[[V3:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 7123// CHECK: %[[V5:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 8124// CHECK: %[[V6:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr, ptr, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, ptr %{{.*}}, i32 0, i32 9125// CHECK: invoke void @_ZN5test12S0D1Ev(ptr {{[^,]*}} %[[V6]])126// CHECK: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]127 128// CHECK: [[INVOKE_CONT]]:129// CHECK: invoke void @_ZN5test12S0D1Ev(ptr {{[^,]*}} %[[V5]])130// CHECK: to label %[[INVOKE_CONT2:.*]] unwind label %[[LPAD1:.*]]131 132// CHECK: [[INVOKE_CONT2]]:133// CHECK: call void @llvm.objc.destroyWeak(ptr %[[V3]])134// CHECK: %[[V7:.*]] = load ptr, ptr %[[V2]], align 8135// CHECK: call void @_Block_object_dispose(ptr %[[V7]], i32 8)136// CHECK: call void @llvm.objc.storeStrong(ptr %[[V4]], ptr null)137// CHECK: ret void138 139// CHECK: [[LPAD]]:140// CHECK: invoke void @_ZN5test12S0D1Ev(ptr {{[^,]*}} %[[V5]])141// CHECK: to label %[[INVOKE_CONT3:.*]] unwind label %[[TERMINATE_LPAD:.*]]142 143// CHECK: [[LPAD1]]144// CHECK: br label %[[EHCLEANUP:.*]]145 146// CHECK: [[INVOKE_CONT3]]:147// CHECK: br label %[[EHCLEANUP]]148 149// CHECK: [[EHCLEANUP]]:150// CHECK: call void @llvm.objc.destroyWeak(ptr %[[V3]])151// CHECK: %[[V14:.*]] = load ptr, ptr %[[V2]], align 8152// CHECK: call void @_Block_object_dispose(ptr %[[V14]], i32 8)153// CHECK: call void @llvm.objc.storeStrong(ptr %[[V4]], ptr null)154// CHECK: br label %[[EH_RESUME:.*]]155 156// CHECK: [[EH_RESUME]]:157// CHECK: resume { ptr, i32 }158 159// CHECK: [[TERMINATE_LPAD]]:160// CHECK: call void @__clang_call_terminate(161 162// CHECK-O1-LABEL: define linkonce_odr hidden void @__destroy_helper_block_ea8_32s40r48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(163// CHECK-O1: call void @llvm.objc.release({{.*}}) {{.*}} !clang.imprecise_release164// CHECK-O1: call void @llvm.objc.release({{.*}}) {{.*}} !clang.imprecise_release165// CHECK-NOEXCP: define linkonce_odr hidden void @__destroy_helper_block_8_32s40r48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(166 167namespace {168struct TrivialInternal {169 int a;170};171}172 173struct S0 {174 S0();175 S0(const S0 &);176 ~S0();177 int f0;178};179 180id getObj();181 182void foo1() {183 __block id t0 = getObj();184 __weak id t1 = getObj();185 id t2 = getObj();186 S0 t3, t4;187 // Capturing a non-external type doesn't cause the copy/dispose helpers to be188 // internal unless the captured type has a non-trivial copy constructor or189 // destructor.190 TrivialInternal t5;191 ^{ (void)t0; (void)t1; (void)t2; (void)t3; (void)t4; (void)t5; };192}193}194 195// Test that calls to @llvm.objc.retainBlock aren't emitted in some cases.196 197typedef void (^BlockTy)();198void foo1(id);199 200namespace test_block_retain {201 202// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain14initializationEP11objc_object(203// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock(204 void initialization(id a) {205 BlockTy b0 = ^{ foo1(a); };206 BlockTy b1 = (^{ foo1(a); });207 b0();208 b1();209 }210 211// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain20initializationStaticEP11objc_object(212// CHECK-NOHEAP: @llvm.objc.retainBlock(213 void initializationStatic(id a) {214 static BlockTy b0 = ^{ foo1(a); };215 b0();216 }217 218// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain15initialization2EP11objc_object219// CHECK-NOHEAP: %b0 = alloca ptr, align 8220// CHECK-NOHEAP: %b1 = alloca ptr, align 8221// CHECK-NOHEAP: load ptr, ptr %b0, align 8222// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock223// CHECK-NOHEAP: %[[V9:.*]] = load ptr, ptr %b0, align 8224// CHECK-NOHEAP: %[[V11:.*]] = call ptr @llvm.objc.retainBlock(ptr %[[V9]])225// CHECK-NOHEAP: store ptr %[[V11]], ptr %b1, align 8226 void initialization2(id a) {227 BlockTy b0 = ^{ foo1(a); };228 b0();229 BlockTy b1 = b0; // can't optimize this yet.230 b1();231 }232 233// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain10assignmentEP11objc_object(234// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock(235 void assignment(id a) {236 BlockTy b0;237 (b0) = ^{ foo1(a); };238 b0();239 b0 = (^{ foo1(a); });240 b0();241 }242 243// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain16assignmentStaticEP11objc_object(244// CHECK-NOHEAP: @llvm.objc.retainBlock(245 void assignmentStatic(id a) {246 static BlockTy b0;247 b0 = ^{ foo1(a); };248 b0();249 }250 251// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain21assignmentConditionalEP11objc_objectb(252// CHECK-NOHEAP: @llvm.objc.retainBlock(253 void assignmentConditional(id a, bool c) {254 BlockTy b0;255 if (c)256 // can't optimize this since 'b0' is declared in the outer scope.257 b0 = ^{ foo1(a); };258 b0();259 }260 261// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain11assignment2EP11objc_object(262// CHECK-NOHEAP: %b0 = alloca ptr, align 8263// CHECK-NOHEAP: %b1 = alloca ptr, align 8264// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock265// CHECK-NOHEAP: store ptr null, ptr %b1, align 8266// CHECK-NOHEAP: %[[V9:.*]] = load ptr, ptr %b0, align 8267// CHECK-NOHEAP: %[[V11:.*]] = call ptr @llvm.objc.retainBlock(ptr %[[V9]]268// CHECK-NOHEAP: store ptr %[[V11]], ptr %b1, align 8269 void assignment2(id a) {270 BlockTy b0 = ^{ foo1(a); };271 b0();272 BlockTy b1;273 b1 = b0; // can't optimize this yet.274 b1();275 }276 277// We cannot remove the call to @llvm.objc.retainBlock if the variable is of type id.278 279// CHECK-NOHEAP: define{{.*}} void @_ZN17test_block_retain21initializationObjCPtrEP11objc_object(280// CHECK-NOHEAP: alloca ptr, align 8281// CHECK-NOHEAP: %[[B0:.*]] = alloca ptr, align 8282// CHECK-NOHEAP: %[[BLOCK:.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8283// CHECK-NOHEAP: %[[V5:.*]] = call ptr @llvm.objc.retainBlock(ptr %[[BLOCK]])284// CHECK-NOHEAP: store ptr %[[V5]], ptr %[[B0]], align 8285 void initializationObjCPtr(id a) {286 id b0 = ^{ foo1(a); };287 ((BlockTy)b0)();288 }289 290// CHECK-NOHEAP: define{{.*}} void @_ZN17test_block_retain17assignmentObjCPtrEP11objc_object(291// CHECK-NOHEAP: %b0 = alloca ptr, align 8292// CHECK-NOHEAP: %b1 = alloca ptr, align 8293// CHECK-NOHEAP: %[[V4:.*]] = load ptr, ptr %b0, align 8294// CHECK-NOHEAP: %[[V6:.*]] = call ptr @llvm.objc.retainBlock(ptr %[[V4]])295// CHECK-NOHEAP: store ptr %[[V6]], ptr %b1, align 8296 void assignmentObjCPtr(id a) {297 BlockTy b0 = ^{ foo1(a); };298 id b1;299 b1 = b0;300 ((BlockTy)b1)();301 }302}303 304// Check that the block capture is released after the full expression.305 306// CHECK-LABEL: define void @_ZN13test_rval_ref4testEP11objc_object(307// CHECK: %[[BLOCK:.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8308// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %[[BLOCK]], i32 0, i32 5309// CHECK: %[[V1:.*]] = call ptr @llvm.objc.retain(310// CHECK: store ptr %[[V1]], ptr %[[BLOCK_CAPTURED]], align 8311// CHECK: invoke void @_ZN13test_rval_ref17callTemplateBlockEOU15__autoreleasingU13block_pointerFvvE(312 313// CHECK: call void @llvm.objc.storeStrong(ptr %[[BLOCK_CAPTURED]], ptr null)314 315namespace test_rval_ref {316 void callTemplateBlock(BlockTy &&func);317 318 void test(id str) {319 return callTemplateBlock(^void() {320 foo1(str);321 });322 }323}324