1 ; RUN: opt -S -objc-arc < %s | FileCheck %s 2 ; rdar://10209613 3 4 %0 = type opaque 5 %struct.__block_descriptor = type { i64, i64 } 6 7 @_NSConcreteStackBlock = external global i8* 8 @__block_descriptor_tmp = external hidden constant { i64, i64, i8*, i8*, i8*, i8* } 9 @"\01L_OBJC_SELECTOR_REFERENCES_" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 10 11 ; CHECK: define void @test( 12 ; CHECK: %3 = call i8* @objc_retainBlock(i8* %2) [[NUW:#[0-9]+]] 13 ; CHECK: @objc_msgSend 14 ; CHECK-NEXT: @objc_release(i8* %3) 15 define void @test(%0* %array) uwtable { 16 entry: 17 %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>, align 8 18 %0 = bitcast %0* %array to i8* 19 %1 = tail call i8* @objc_retain(i8* %0) nounwind 20 %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 0 21 store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8 22 %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 1 23 store i32 1107296256, i32* %block.flags, align 8 24 %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 2 25 store i32 0, i32* %block.reserved, align 4 26 %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 3 27 store i8* bitcast (void (i8*)* @__test_block_invoke_0 to i8*), i8** %block.invoke, align 8 28 %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 4 29 store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8 30 %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 5 31 store %0* %array, %0** %block.captured, align 8 32 %2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block to i8* 33 %3 = call i8* @objc_retainBlock(i8* %2) nounwind 34 %tmp2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 35 call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* %0, i8* %tmp2, i8* %3) 36 call void @objc_release(i8* %3) nounwind 37 %strongdestroy = load %0** %block.captured, align 8 38 %4 = bitcast %0* %strongdestroy to i8* 39 call void @objc_release(i8* %4) nounwind, !clang.imprecise_release !0 40 ret void 41 } 42 43 ; Same as test, but the objc_retainBlock has a clang.arc.copy_on_escape 44 ; tag so it's safe to delete. 45 46 ; CHECK: define void @test_with_COE( 47 ; CHECK-NOT: @objc_retainBlock 48 ; CHECK: @objc_msgSend 49 ; CHECK: @objc_release 50 ; CHECK-NOT: @objc_release 51 ; CHECK: } 52 define void @test_with_COE(%0* %array) uwtable { 53 entry: 54 %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>, align 8 55 %0 = bitcast %0* %array to i8* 56 %1 = tail call i8* @objc_retain(i8* %0) nounwind 57 %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 0 58 store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8 59 %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 1 60 store i32 1107296256, i32* %block.flags, align 8 61 %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 2 62 store i32 0, i32* %block.reserved, align 4 63 %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 3 64 store i8* bitcast (void (i8*)* @__test_block_invoke_0 to i8*), i8** %block.invoke, align 8 65 %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 4 66 store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8 67 %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 5 68 store %0* %array, %0** %block.captured, align 8 69 %2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block to i8* 70 %3 = call i8* @objc_retainBlock(i8* %2) nounwind, !clang.arc.copy_on_escape !0 71 %tmp2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 72 call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* %0, i8* %tmp2, i8* %3) 73 call void @objc_release(i8* %3) nounwind 74 %strongdestroy = load %0** %block.captured, align 8 75 %4 = bitcast %0* %strongdestroy to i8* 76 call void @objc_release(i8* %4) nounwind, !clang.imprecise_release !0 77 ret void 78 } 79 80 declare i8* @objc_retain(i8*) 81 82 declare void @__test_block_invoke_0(i8* nocapture) uwtable 83 84 declare i8* @objc_retainBlock(i8*) 85 86 declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind 87 88 declare void @objc_release(i8*) 89 90 ; CHECK: attributes #0 = { uwtable } 91 ; CHECK: attributes #1 = { nonlazybind } 92 ; CHECK: attributes [[NUW]] = { nounwind } 93 94 !0 = metadata !{} 95