1 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s 2 3 #define PRECISE_LIFETIME __attribute__((objc_precise_lifetime)) 4 5 id test0_helper(void) __attribute__((ns_returns_retained)); 6 void test0() { 7 PRECISE_LIFETIME id x = test0_helper(); 8 x = 0; 9 // CHECK: [[X:%.*]] = alloca i8* 10 // CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8* 11 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]]) 12 // CHECK-NEXT: [[CALL:%.*]] = call i8* @test0_helper() 13 // CHECK-NEXT: store i8* [[CALL]], i8** [[X]] 14 15 // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]] 16 // CHECK-NEXT: store i8* null, i8** [[X]] 17 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]] 18 // CHECK-NOT: clang.imprecise_release 19 20 // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]] 21 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]] 22 // CHECK-NOT: clang.imprecise_release 23 24 // CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8* 25 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]]) 26 // CHECK-NEXT: ret void 27 } 28 29 // rdar://problem/9821110 - precise lifetime should suppress extension 30 // rdar://problem/22172983 - should work for calls via property syntax, too 31 @interface Test1 32 - (char*) interior __attribute__((objc_returns_inner_pointer)); 33 // Should we allow this on properties? Yes! see // rdar://14990439 34 @property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer)); 35 @end 36 extern Test1 *test1_helper(void); 37 38 // CHECK-LABEL: define void @test1a_message() 39 void test1a_message(void) { 40 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 41 // CHECK: [[C:%.*]] = alloca i8*, align 8 42 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 43 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 44 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 45 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 46 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 47 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 48 // CHECK-NEXT: store [[TEST1]]* [[T3]] 49 // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8* 50 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]]) 51 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 52 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 53 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]]) 54 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 55 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 56 // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8* 57 // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast 58 // CHECK-NEXT: store i8* [[T6]], i8** 59 // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8* 60 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]]) 61 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 62 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 63 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release 64 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 65 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 66 // CHECK-NEXT: ret void 67 Test1 *ptr = test1_helper(); 68 char *c = [(ptr) interior]; 69 } 70 71 72 // CHECK-LABEL: define void @test1a_property() 73 void test1a_property(void) { 74 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 75 // CHECK: [[C:%.*]] = alloca i8*, align 8 76 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 77 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 78 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 79 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 80 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 81 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 82 // CHECK-NEXT: store [[TEST1]]* [[T3]] 83 // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8* 84 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]]) 85 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 86 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 87 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]]) 88 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 89 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 90 // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8* 91 // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast 92 // CHECK-NEXT: store i8* [[T6]], i8** 93 // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8* 94 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]]) 95 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 96 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 97 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release 98 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 99 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 100 // CHECK-NEXT: ret void 101 Test1 *ptr = test1_helper(); 102 char *c = ptr.interior; 103 } 104 105 106 // CHECK-LABEL: define void @test1b_message() 107 void test1b_message(void) { 108 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 109 // CHECK: [[C:%.*]] = alloca i8*, align 8 110 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 111 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 112 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 113 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 114 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 115 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 116 // CHECK-NEXT: store [[TEST1]]* [[T3]] 117 // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8* 118 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]]) 119 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 120 // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 121 // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 122 // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast 123 // CHECK-NEXT: store i8* [[T3]], i8** 124 // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8* 125 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]]) 126 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 127 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 128 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]] 129 // CHECK-NOT: clang.imprecise_release 130 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 131 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 132 // CHECK-NEXT: ret void 133 PRECISE_LIFETIME Test1 *ptr = test1_helper(); 134 char *c = [ptr interior]; 135 } 136 137 // CHECK-LABEL: define void @test1b_property() 138 void test1b_property(void) { 139 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 140 // CHECK: [[C:%.*]] = alloca i8*, align 8 141 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 142 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 143 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 144 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 145 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 146 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 147 // CHECK-NEXT: store [[TEST1]]* [[T3]] 148 // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8* 149 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]]) 150 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 151 // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 152 // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 153 // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast 154 // CHECK-NEXT: store i8* [[T3]], i8** 155 // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8* 156 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]]) 157 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 158 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 159 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]] 160 // CHECK-NOT: clang.imprecise_release 161 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 162 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 163 // CHECK-NEXT: ret void 164 PRECISE_LIFETIME Test1 *ptr = test1_helper(); 165 char *c = ptr.interior; 166 } 167 168 // CHECK-LABEL: define void @test1c_message() 169 void test1c_message(void) { 170 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 171 // CHECK: [[PC:%.*]] = alloca i8*, align 8 172 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 173 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 174 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 175 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 176 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 177 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 178 // CHECK-NEXT: store [[TEST1]]* [[T3]] 179 // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8* 180 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]]) 181 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 182 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 183 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]]) 184 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 185 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 186 // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8* 187 // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast 188 // CHECK-NEXT: store i8* [[T6]], i8** 189 // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8* 190 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]]) 191 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 192 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 193 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release 194 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 195 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 196 // CHECK-NEXT: ret void 197 Test1 *ptr = test1_helper(); 198 char *pc = [ptr PropertyReturnsInnerPointer]; 199 } 200 201 // CHECK-LABEL: define void @test1c_property() 202 void test1c_property(void) { 203 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 204 // CHECK: [[PC:%.*]] = alloca i8*, align 8 205 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 206 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 207 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 208 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 209 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 210 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 211 // CHECK-NEXT: store [[TEST1]]* [[T3]] 212 // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8* 213 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]]) 214 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 215 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 216 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]]) 217 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 218 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 219 // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8* 220 // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast 221 // CHECK-NEXT: store i8* [[T6]], i8** 222 // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8* 223 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]]) 224 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 225 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 226 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release 227 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 228 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 229 // CHECK-NEXT: ret void 230 Test1 *ptr = test1_helper(); 231 char *pc = ptr.PropertyReturnsInnerPointer; 232 } 233 234 // CHECK-LABEL: define void @test1d_message() 235 void test1d_message(void) { 236 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 237 // CHECK: [[PC:%.*]] = alloca i8*, align 8 238 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 239 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 240 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 241 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 242 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 243 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 244 // CHECK-NEXT: store [[TEST1]]* [[T3]] 245 // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8* 246 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]]) 247 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 248 // CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 249 // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 250 // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]]) 251 // CHECK-NEXT: store i8* [[CALL1]], i8** 252 // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8* 253 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]]) 254 // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]** 255 // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8* 256 // CHECK-NEXT: call void @objc_release(i8* [[TEN]]) 257 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 258 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 259 // CHECK-NEXT: ret void 260 PRECISE_LIFETIME Test1 *ptr = test1_helper(); 261 char *pc = [ptr PropertyReturnsInnerPointer]; 262 } 263 264 // CHECK-LABEL: define void @test1d_property() 265 void test1d_property(void) { 266 // CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8 267 // CHECK: [[PC:%.*]] = alloca i8*, align 8 268 // CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 269 // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]]) 270 // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() 271 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 272 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 273 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* 274 // CHECK-NEXT: store [[TEST1]]* [[T3]] 275 // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8* 276 // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]]) 277 // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]** 278 // CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ 279 // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* 280 // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]]) 281 // CHECK-NEXT: store i8* [[CALL1]], i8** 282 // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8* 283 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]]) 284 // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]** 285 // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8* 286 // CHECK-NEXT: call void @objc_release(i8* [[TEN]]) 287 // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8* 288 // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]]) 289 // CHECK-NEXT: ret void 290 PRECISE_LIFETIME Test1 *ptr = test1_helper(); 291 char *pc = ptr.PropertyReturnsInnerPointer; 292 } 293 294 @interface Test2 { 295 @public 296 id ivar; 297 } 298 @end 299 // CHECK-LABEL: define void @test2( 300 void test2(Test2 *x) { 301 x->ivar = 0; 302 // CHECK: [[X:%.*]] = alloca [[TEST2:%.*]]* 303 // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST2]]* {{%.*}} to i8* 304 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]] 305 // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST2]]* 306 // CHECK-NEXT: store [[TEST2]]* [[T2]], [[TEST2]]** [[X]], 307 308 // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]*, [[TEST2]]** [[X]], 309 // CHECK-NEXT: [[OFFSET:%.*]] = load i64, i64* @"OBJC_IVAR_$_Test2.ivar" 310 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8* 311 // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8, i8* [[T1]], i64 [[OFFSET]] 312 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8** 313 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], 314 // CHECK-NEXT: store i8* null, i8** [[T3]], 315 // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]] 316 // CHECK-NOT: imprecise 317 318 // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]*, [[TEST2]]** [[X]] 319 // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8* 320 // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release 321 322 // CHECK-NEXT: ret void 323 } 324 325 // CHECK-LABEL: define void @test3(i8* 326 void test3(PRECISE_LIFETIME id x) { 327 // CHECK: [[X:%.*]] = alloca i8*, 328 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) [[NUW]] 329 // CHECK-NEXT: store i8* [[T0]], i8** [[X]], 330 331 // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]] 332 // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]] 333 // CHECK-NOT: imprecise_release 334 335 // CHECK-NEXT: ret void 336 } 337 338 // CHECK: attributes [[NUW]] = { nounwind } 339