260 lines · plain
1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s2 3#define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))4 5id test0_helper(void) __attribute__((ns_returns_retained));6void test0(void) {7 PRECISE_LIFETIME id x = test0_helper();8 x = 0;9 // CHECK: [[X:%.*]] = alloca ptr10 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[X]])11 // CHECK-NEXT: [[CALL:%.*]] = call ptr @test0_helper()12 // CHECK-NEXT: store ptr [[CALL]], ptr [[X]]13 14 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]15 // CHECK-NEXT: store ptr null, ptr [[X]]16 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]]) [[NUW:#[0-9]+]]17 // CHECK-NOT: clang.imprecise_release18 19 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]20 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]]) [[NUW:#[0-9]+]]21 // CHECK-NOT: clang.imprecise_release22 23 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[X]])24 // CHECK-NEXT: ret void25}26 27// precise lifetime should suppress extension28// should work for calls via property syntax, too29@interface Test130- (char*) interior __attribute__((objc_returns_inner_pointer));31// Should we allow this on properties? Yes!32@property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));33@end34extern Test1 *test1_helper(void);35 36// CHECK-LABEL: define{{.*}} void @test1a_message()37void test1a_message(void) {38 // CHECK: [[PTR:%.*]] = alloca ptr, align 839 // CHECK: [[C:%.*]] = alloca ptr, align 840 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])41 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]42 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])43 // CHECK-NEXT: store ptr [[T0]]44 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[C]])45 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr46 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])47 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_48 // CHECK-NEXT: [[T6:%.*]] = call ptr49 // CHECK-NEXT: store ptr [[T6]], ptr50 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[C]])51 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr52 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release53 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])54 // CHECK-NEXT: ret void55 Test1 *ptr = test1_helper();56 char *c = [(ptr) interior];57}58 59 60// CHECK-LABEL: define{{.*}} void @test1a_property()61void test1a_property(void) {62 // CHECK: [[PTR:%.*]] = alloca ptr, align 863 // CHECK: [[C:%.*]] = alloca ptr, align 864 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])65 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]66 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])67 // CHECK-NEXT: store ptr [[T0]]68 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[C]])69 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr70 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])71 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_72 // CHECK-NEXT: [[T6:%.*]] = call ptr73 // CHECK-NEXT: store ptr [[T6]], ptr74 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[C]])75 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr76 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release77 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])78 // CHECK-NEXT: ret void79 Test1 *ptr = test1_helper();80 char *c = ptr.interior;81}82 83 84// CHECK-LABEL: define{{.*}} void @test1b_message()85void test1b_message(void) {86 // CHECK: [[PTR:%.*]] = alloca ptr, align 887 // CHECK: [[C:%.*]] = alloca ptr, align 888 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])89 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]90 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])91 // CHECK-NEXT: store ptr [[T0]]92 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[C]])93 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr94 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_95 // CHECK-NEXT: [[T3:%.*]] = call ptr96 // CHECK-NEXT: store ptr [[T3]], ptr97 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[C]])98 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr99 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]100 // CHECK-NOT: clang.imprecise_release101 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])102 // CHECK-NEXT: ret void103 PRECISE_LIFETIME Test1 *ptr = test1_helper();104 char *c = [ptr interior];105}106 107// CHECK-LABEL: define{{.*}} void @test1b_property()108void test1b_property(void) {109 // CHECK: [[PTR:%.*]] = alloca ptr, align 8110 // CHECK: [[C:%.*]] = alloca ptr, align 8111 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])112 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]113 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])114 // CHECK-NEXT: store ptr [[T0]]115 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[C]])116 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr117 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_118 // CHECK-NEXT: [[T3:%.*]] = call ptr119 // CHECK-NEXT: store ptr [[T3]], ptr120 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[C]])121 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr122 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]123 // CHECK-NOT: clang.imprecise_release124 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])125 // CHECK-NEXT: ret void126 PRECISE_LIFETIME Test1 *ptr = test1_helper();127 char *c = ptr.interior;128}129 130// CHECK-LABEL: define{{.*}} void @test1c_message()131void test1c_message(void) {132 // CHECK: [[PTR:%.*]] = alloca ptr, align 8133 // CHECK: [[PC:%.*]] = alloca ptr, align 8134 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])135 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]136 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])137 // CHECK-NEXT: store ptr [[T0]]138 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PC]])139 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr140 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])141 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_142 // CHECK-NEXT: [[T6:%.*]] = call ptr143 // CHECK-NEXT: store ptr [[T6]], ptr144 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PC]])145 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr146 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release147 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])148 // CHECK-NEXT: ret void149 Test1 *ptr = test1_helper();150 char *pc = [ptr PropertyReturnsInnerPointer];151}152 153// CHECK-LABEL: define{{.*}} void @test1c_property()154void test1c_property(void) {155 // CHECK: [[PTR:%.*]] = alloca ptr, align 8156 // CHECK: [[PC:%.*]] = alloca ptr, align 8157 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])158 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]159 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])160 // CHECK-NEXT: store ptr [[T0]]161 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PC]])162 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr163 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])164 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_165 // CHECK-NEXT: [[T6:%.*]] = call ptr166 // CHECK-NEXT: store ptr [[T6]], ptr167 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PC]])168 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr169 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release170 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])171 // CHECK-NEXT: ret void172 Test1 *ptr = test1_helper();173 char *pc = ptr.PropertyReturnsInnerPointer;174}175 176// CHECK-LABEL: define{{.*}} void @test1d_message()177void test1d_message(void) {178 // CHECK: [[PTR:%.*]] = alloca ptr, align 8179 // CHECK: [[PC:%.*]] = alloca ptr, align 8180 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])181 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]182 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])183 // CHECK-NEXT: store ptr [[T0]]184 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PC]])185 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr186 // CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_187 // CHECK-NEXT: [[CALL1:%.*]] = call ptr @objc_msgSend(ptr noundef [[T0]], ptr noundef [[SEL]])188 // CHECK-NEXT: store ptr [[CALL1]], ptr189 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PC]])190 // CHECK-NEXT: [[NINE:%.*]] = load ptr, ptr191 // CHECK-NEXT: call void @llvm.objc.release(ptr [[NINE]])192 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])193 // CHECK-NEXT: ret void194 PRECISE_LIFETIME Test1 *ptr = test1_helper();195 char *pc = [ptr PropertyReturnsInnerPointer];196}197 198// CHECK-LABEL: define{{.*}} void @test1d_property()199void test1d_property(void) {200 // CHECK: [[PTR:%.*]] = alloca ptr, align 8201 // CHECK: [[PC:%.*]] = alloca ptr, align 8202 // CHECK: call void @llvm.lifetime.start.p0(ptr [[PTR]])203 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]204 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])205 // CHECK-NEXT: store ptr [[T0]]206 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PC]])207 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr208 // CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_209 // CHECK-NEXT: [[CALL1:%.*]] = call ptr @objc_msgSend(ptr noundef [[T0]], ptr noundef [[SEL]])210 // CHECK-NEXT: store ptr [[CALL1]], ptr211 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PC]])212 // CHECK-NEXT: [[NINE:%.*]] = load ptr, ptr213 // CHECK-NEXT: call void @llvm.objc.release(ptr [[NINE]])214 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PTR]])215 // CHECK-NEXT: ret void216 PRECISE_LIFETIME Test1 *ptr = test1_helper();217 char *pc = ptr.PropertyReturnsInnerPointer;218}219 220@interface Test2 {221@public222 id ivar;223}224@end225// CHECK-LABEL: define{{.*}} void @test2(226void test2(Test2 *x) {227 x->ivar = 0;228 // CHECK: [[X:%.*]] = alloca ptr229 // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}}) [[NUW]]230 // CHECK-NEXT: store ptr [[T1]], ptr [[X]],231 232 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],233 // CHECK-NEXT: [[OFFSET:%.*]] = load i64, ptr @"OBJC_IVAR_$_Test2.ivar"234 // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8, ptr [[T0]], i64 [[OFFSET]]235 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T2]],236 // CHECK-NEXT: store ptr null, ptr [[T2]],237 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T4]]) [[NUW]]238 // CHECK-NOT: imprecise239 240 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]241 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release242 243 // CHECK-NEXT: ret void244}245 246// CHECK-LABEL: define{{.*}} void @test3(ptr247void test3(PRECISE_LIFETIME id x) {248 // CHECK: [[X:%.*]] = alloca ptr,249 // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}}) [[NUW]]250 // CHECK-NEXT: store ptr [[T0]], ptr [[X]],251 252 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]253 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]254 // CHECK-NOT: imprecise_release255 256 // CHECK-NEXT: ret void 257}258 259// CHECK: attributes [[NUW]] = { nounwind }260