1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s 2 3%struct.__objcFastEnumerationState = type { i64, ptr, ptr, [5 x i64] } 4 5@"\01L_OBJC_METH_VAR_NAME_" = internal global [43 x i8] c"countByEnumeratingWithState:objects:count:\00", section "__TEXT,__objc_methname,cstring_literals", align 1 6@"\01L_OBJC_SELECTOR_REFERENCES_" = internal global ptr @"\01L_OBJC_METH_VAR_NAME_", section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 7@g = common global ptr null, align 8 8@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip" 9 10declare void @callee() 11declare ptr @returner() 12declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr) 13declare ptr @llvm.objc.retain(ptr) 14declare void @llvm.objc.enumerationMutation(ptr) 15declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind 16declare ptr @objc_msgSend(ptr, ptr, ...) nonlazybind 17declare void @use(ptr) 18declare void @llvm.objc.release(ptr) 19declare ptr @def() 20declare void @__crasher_block_invoke(ptr nocapture) 21declare ptr @llvm.objc.retainBlock(ptr) 22declare void @__crasher_block_invoke1(ptr nocapture) 23 24!0 = !{} 25 26; Delete a nested retain+release pair. 27 28; CHECK-LABEL: define void @test0( 29; CHECK: call ptr @llvm.objc.retain 30; CHECK-NOT: @llvm.objc.retain 31; CHECK: } 32define void @test0(ptr %a) nounwind { 33entry: 34 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 35 %items.ptr = alloca [16 x ptr], align 8 36 %0 = call ptr @llvm.objc.retain(ptr %a) nounwind 37 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 38 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 39 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 40 %call = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16) 41 %iszero = icmp eq i64 %call, 0 42 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 43 44forcoll.loopinit: 45 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 46 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 47 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 48 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 49 br label %forcoll.loopbody.outer 50 51forcoll.loopbody.outer: 52 %forcoll.count.ph = phi i64 [ %call, %forcoll.loopinit ], [ %call6, %forcoll.refetch ] 53 %tmp7 = icmp ugt i64 %forcoll.count.ph, 1 54 %umax = select i1 %tmp7, i64 %forcoll.count.ph, i64 1 55 br label %forcoll.loopbody 56 57forcoll.loopbody: 58 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ] 59 %mutationsptr3 = load ptr, ptr %mutationsptr.ptr, align 8 60 %statemutations = load i64, ptr %mutationsptr3, align 8 61 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 62 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 63 64forcoll.mutated: 65 call void @llvm.objc.enumerationMutation(ptr %1) 66 br label %forcoll.notmutated 67 68forcoll.notmutated: 69 %stateitems = load ptr, ptr %stateitems.ptr, align 8 70 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 71 %3 = load ptr, ptr %currentitem.ptr, align 8 72 call void @use(ptr %3) 73 %4 = add i64 %forcoll.index, 1 74 %exitcond = icmp eq i64 %4, %umax 75 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 76 77forcoll.refetch: 78 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 79 %call6 = call i64 @objc_msgSend(ptr %1, ptr %tmp5, ptr %state.ptr, ptr %items.ptr, i64 16) 80 %5 = icmp eq i64 %call6, 0 81 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 82 83forcoll.empty: 84 call void @llvm.objc.release(ptr %1) nounwind 85 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 86 ret void 87} 88 89; Delete a nested retain+release pair. 90 91; CHECK-LABEL: define void @test2( 92; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 93; CHECK-NOT: @llvm.objc.retain 94; CHECK: } 95define void @test2() nounwind { 96entry: 97 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 98 %items.ptr = alloca [16 x ptr], align 8 99 %call = call ptr @returner() 100 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 101 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 102 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 103 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 104 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16) 105 %iszero = icmp eq i64 %call3, 0 106 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 107 108forcoll.loopinit: 109 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 110 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 111 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 112 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 113 br label %forcoll.loopbody.outer 114 115forcoll.loopbody.outer: 116 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 117 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1 118 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1 119 br label %forcoll.loopbody 120 121forcoll.loopbody: 122 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ] 123 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8 124 %statemutations = load i64, ptr %mutationsptr4, align 8 125 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 126 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 127 128forcoll.mutated: 129 call void @llvm.objc.enumerationMutation(ptr %1) 130 br label %forcoll.notmutated 131 132forcoll.notmutated: 133 %stateitems = load ptr, ptr %stateitems.ptr, align 8 134 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 135 %3 = load ptr, ptr %currentitem.ptr, align 8 136 call void @use(ptr %3) 137 %4 = add i64 %forcoll.index, 1 138 %exitcond = icmp eq i64 %4, %umax 139 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 140 141forcoll.refetch: 142 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 143 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 144 %5 = icmp eq i64 %call7, 0 145 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 146 147forcoll.empty: 148 call void @llvm.objc.release(ptr %1) nounwind 149 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 150 ret void 151} 152 153; Delete a nested retain+release pair. 154 155; CHECK-LABEL: define void @test4( 156; CHECK: call ptr @llvm.objc.retain 157; CHECK-NOT: @llvm.objc.retain 158; CHECK: } 159define void @test4() nounwind { 160entry: 161 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 162 %items.ptr = alloca [16 x ptr], align 8 163 %tmp = load ptr, ptr @g, align 8 164 %0 = call ptr @llvm.objc.retain(ptr %tmp) nounwind 165 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 166 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 167 %tmp4 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 168 %call = call i64 @objc_msgSend(ptr %1, ptr %tmp4, ptr %state.ptr, ptr %items.ptr, i64 16) 169 %iszero = icmp eq i64 %call, 0 170 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 171 172forcoll.loopinit: 173 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 174 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 175 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 176 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 177 br label %forcoll.loopbody.outer 178 179forcoll.loopbody.outer: 180 %forcoll.count.ph = phi i64 [ %call, %forcoll.loopinit ], [ %call8, %forcoll.refetch ] 181 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1 182 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1 183 br label %forcoll.loopbody 184 185forcoll.loopbody: 186 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ] 187 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8 188 %statemutations = load i64, ptr %mutationsptr5, align 8 189 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 190 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 191 192forcoll.mutated: 193 call void @llvm.objc.enumerationMutation(ptr %1) 194 br label %forcoll.notmutated 195 196forcoll.notmutated: 197 %stateitems = load ptr, ptr %stateitems.ptr, align 8 198 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 199 %3 = load ptr, ptr %currentitem.ptr, align 8 200 call void @use(ptr %3) 201 %4 = add i64 %forcoll.index, 1 202 %exitcond = icmp eq i64 %4, %umax 203 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 204 205forcoll.refetch: 206 %tmp7 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 207 %call8 = call i64 @objc_msgSend(ptr %1, ptr %tmp7, ptr %state.ptr, ptr %items.ptr, i64 16) 208 %5 = icmp eq i64 %call8, 0 209 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 210 211forcoll.empty: 212 call void @llvm.objc.release(ptr %1) nounwind 213 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 214 ret void 215} 216 217; Delete a nested retain+release pair. 218 219; CHECK-LABEL: define void @test5( 220; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 221; CHECK-NOT: @llvm.objc.retain 222; CHECK: } 223define void @test5() nounwind { 224entry: 225 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 226 %items.ptr = alloca [16 x ptr], align 8 227 %call = call ptr @returner() 228 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 229 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 230 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 231 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 232 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16) 233 %iszero = icmp eq i64 %call3, 0 234 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 235 236forcoll.loopinit: 237 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 238 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 239 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 240 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 241 br label %forcoll.loopbody.outer 242 243forcoll.loopbody.outer: 244 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 245 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1 246 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1 247 br label %forcoll.loopbody 248 249forcoll.loopbody: 250 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ] 251 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8 252 %statemutations = load i64, ptr %mutationsptr4, align 8 253 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 254 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 255 256forcoll.mutated: 257 call void @llvm.objc.enumerationMutation(ptr %1) 258 br label %forcoll.notmutated 259 260forcoll.notmutated: 261 %stateitems = load ptr, ptr %stateitems.ptr, align 8 262 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 263 %3 = load ptr, ptr %currentitem.ptr, align 8 264 call void @use(ptr %3) 265 %4 = add i64 %forcoll.index, 1 266 %exitcond = icmp eq i64 %4, %umax 267 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 268 269forcoll.refetch: 270 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 271 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 272 %5 = icmp eq i64 %call7, 0 273 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 274 275forcoll.empty: 276 call void @llvm.objc.release(ptr %1) nounwind 277 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 278 ret void 279} 280 281; We handle this now due to the fact that a release just needs a post dominating 282; use. 283; 284; CHECK-LABEL: define void @test6( 285; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 286; CHECK-NOT: @llvm.objc.retain 287; CHECK: } 288define void @test6() nounwind { 289entry: 290 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 291 %items.ptr = alloca [16 x ptr], align 8 292 %call = call ptr @returner() 293 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 294 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 295 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 296 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 297 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16) 298 %iszero = icmp eq i64 %call3, 0 299 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 300 301forcoll.loopinit: 302 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 303 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 304 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 305 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 306 br label %forcoll.loopbody.outer 307 308forcoll.loopbody.outer: 309 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 310 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1 311 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1 312 br label %forcoll.loopbody 313 314forcoll.loopbody: 315 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ] 316 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8 317 %statemutations = load i64, ptr %mutationsptr4, align 8 318 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 319 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 320 321forcoll.mutated: 322 call void @llvm.objc.enumerationMutation(ptr %1) 323 br label %forcoll.notmutated 324 325forcoll.notmutated: 326 %stateitems = load ptr, ptr %stateitems.ptr, align 8 327 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 328 %3 = load ptr, ptr %currentitem.ptr, align 8 329 call void @use(ptr %3) 330 %4 = add i64 %forcoll.index, 1 331 %exitcond = icmp eq i64 %4, %umax 332 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 333 334forcoll.refetch: 335 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 336 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 337 %5 = icmp eq i64 %call7, 0 338 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 339 340forcoll.empty: 341 call void @llvm.objc.release(ptr %1) nounwind 342 call void @callee() 343 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 344 ret void 345} 346 347; TODO: Delete a nested retain+release pair. 348; The optimizer currently can't do this, because isn't isn't sophisticated enough in 349; reasnoning about nesting. 350 351; CHECK-LABEL: define void @test7( 352; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 353; CHECK: @llvm.objc.retain 354; CHECK: } 355define void @test7() nounwind { 356entry: 357 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 358 %items.ptr = alloca [16 x ptr], align 8 359 %call = call ptr @returner() 360 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 361 call void @callee() 362 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 363 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 364 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 365 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16) 366 %iszero = icmp eq i64 %call3, 0 367 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 368 369forcoll.loopinit: 370 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 371 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 372 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 373 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 374 br label %forcoll.loopbody.outer 375 376forcoll.loopbody.outer: 377 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 378 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1 379 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1 380 br label %forcoll.loopbody 381 382forcoll.loopbody: 383 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ] 384 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8 385 %statemutations = load i64, ptr %mutationsptr4, align 8 386 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 387 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 388 389forcoll.mutated: 390 call void @llvm.objc.enumerationMutation(ptr %1) 391 br label %forcoll.notmutated 392 393forcoll.notmutated: 394 %stateitems = load ptr, ptr %stateitems.ptr, align 8 395 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 396 %3 = load ptr, ptr %currentitem.ptr, align 8 397 call void @use(ptr %3) 398 %4 = add i64 %forcoll.index, 1 399 %exitcond = icmp eq i64 %4, %umax 400 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 401 402forcoll.refetch: 403 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 404 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 405 %5 = icmp eq i64 %call7, 0 406 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 407 408forcoll.empty: 409 call void @llvm.objc.release(ptr %1) nounwind 410 call void @callee() 411 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 412 ret void 413} 414 415; Delete a nested retain+release pair. 416 417; CHECK-LABEL: define void @test8( 418; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 419; CHECK-NOT: @llvm.objc.retain 420; CHECK: } 421define void @test8() nounwind { 422entry: 423 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 424 %items.ptr = alloca [16 x ptr], align 8 425 %call = call ptr @returner() 426 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 427 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 428 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind 429 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 430 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16) 431 %iszero = icmp eq i64 %call3, 0 432 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 433 434forcoll.loopinit: 435 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 436 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 437 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 438 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1 439 br label %forcoll.loopbody.outer 440 441forcoll.loopbody.outer: 442 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 443 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1 444 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1 445 br label %forcoll.loopbody 446 447forcoll.loopbody: 448 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.next ] 449 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8 450 %statemutations = load i64, ptr %mutationsptr4, align 8 451 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations 452 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated 453 454forcoll.mutated: 455 call void @llvm.objc.enumerationMutation(ptr %1) 456 br label %forcoll.notmutated 457 458forcoll.notmutated: 459 %stateitems = load ptr, ptr %stateitems.ptr, align 8 460 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index 461 %3 = load ptr, ptr %currentitem.ptr, align 8 462 %tobool = icmp eq ptr %3, null 463 br i1 %tobool, label %forcoll.next, label %if.then 464 465if.then: 466 call void @callee() 467 br label %forcoll.next 468 469forcoll.next: 470 %4 = add i64 %forcoll.index, 1 471 %exitcond = icmp eq i64 %4, %umax 472 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 473 474forcoll.refetch: 475 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 476 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 477 %5 = icmp eq i64 %call7, 0 478 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer 479 480forcoll.empty: 481 call void @llvm.objc.release(ptr %1) nounwind 482 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 483 ret void 484} 485 486; TODO: Delete a nested retain+release pair. 487; The optimizer currently can't do this, because of a split loop backedge. 488; See test9b for the same testcase without a split backedge. 489 490; CHECK-LABEL: define void @test9( 491; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 492; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 493; CHECK: call ptr @llvm.objc.retain 494; CHECK: } 495define void @test9() nounwind { 496entry: 497 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 498 %items.ptr = alloca [16 x ptr], align 8 499 %call = call ptr @returner() 500 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 501 %call1 = call ptr @returner() 502 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind 503 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 504 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind 505 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 506 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16) 507 %iszero = icmp eq i64 %call4, 0 508 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 509 510forcoll.loopinit: 511 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 512 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 513 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 514 br label %forcoll.loopbody.outer 515 516forcoll.loopbody.outer: 517 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 518 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1 519 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1 520 br label %forcoll.loopbody 521 522forcoll.loopbody: 523 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated.forcoll.loopbody_crit_edge ], [ 1, %forcoll.loopbody.outer ] 524 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8 525 %statemutations = load i64, ptr %mutationsptr5, align 8 526 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations 527 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated 528 529forcoll.mutated: 530 call void @llvm.objc.enumerationMutation(ptr %2) 531 br label %forcoll.notmutated 532 533forcoll.notmutated: 534 %exitcond = icmp eq i64 %forcoll.index, %umax 535 br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge 536 537forcoll.notmutated.forcoll.loopbody_crit_edge: 538 %phitmp = add i64 %forcoll.index, 1 539 br label %forcoll.loopbody 540 541forcoll.refetch: 542 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 543 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 544 %4 = icmp eq i64 %call7, 0 545 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer 546 547forcoll.empty: 548 call void @llvm.objc.release(ptr %2) nounwind 549 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0 550 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 551 ret void 552} 553 554; Like test9, but without a split backedge. TODO: optimize this. 555 556; CHECK-LABEL: define void @test9b( 557; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 558; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 559; CHECK: @llvm.objc.retain 560; CHECK: } 561define void @test9b() nounwind { 562entry: 563 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 564 %items.ptr = alloca [16 x ptr], align 8 565 %call = call ptr @returner() 566 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 567 %call1 = call ptr @returner() 568 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind 569 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 570 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind 571 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 572 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16) 573 %iszero = icmp eq i64 %call4, 0 574 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 575 576forcoll.loopinit: 577 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 578 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 579 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 580 br label %forcoll.loopbody.outer 581 582forcoll.loopbody.outer: 583 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 584 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1 585 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1 586 br label %forcoll.loopbody 587 588forcoll.loopbody: 589 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated ], [ 0, %forcoll.loopbody.outer ] 590 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8 591 %statemutations = load i64, ptr %mutationsptr5, align 8 592 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations 593 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated 594 595forcoll.mutated: 596 call void @llvm.objc.enumerationMutation(ptr %2) 597 br label %forcoll.notmutated 598 599forcoll.notmutated: 600 %phitmp = add i64 %forcoll.index, 1 601 %exitcond = icmp eq i64 %phitmp, %umax 602 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 603 604forcoll.refetch: 605 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 606 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 607 %4 = icmp eq i64 %call7, 0 608 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer 609 610forcoll.empty: 611 call void @llvm.objc.release(ptr %2) nounwind 612 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0 613 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 614 ret void 615} 616 617; TODO: Delete a nested retain+release pair. 618; The optimizer currently can't do this, because of a split loop backedge. 619; See test10b for the same testcase without a split backedge. 620 621; CHECK-LABEL: define void @test10( 622; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 623; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 624; CHECK: call ptr @llvm.objc.retain 625; CHECK: } 626define void @test10() nounwind { 627entry: 628 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 629 %items.ptr = alloca [16 x ptr], align 8 630 %call = call ptr @returner() 631 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 632 %call1 = call ptr @returner() 633 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind 634 call void @callee() 635 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 636 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind 637 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 638 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16) 639 %iszero = icmp eq i64 %call4, 0 640 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 641 642forcoll.loopinit: 643 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 644 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 645 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 646 br label %forcoll.loopbody.outer 647 648forcoll.loopbody.outer: 649 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 650 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1 651 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1 652 br label %forcoll.loopbody 653 654forcoll.loopbody: 655 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated.forcoll.loopbody_crit_edge ], [ 1, %forcoll.loopbody.outer ] 656 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8 657 %statemutations = load i64, ptr %mutationsptr5, align 8 658 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations 659 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated 660 661forcoll.mutated: 662 call void @llvm.objc.enumerationMutation(ptr %2) 663 br label %forcoll.notmutated 664 665forcoll.notmutated: 666 %exitcond = icmp eq i64 %forcoll.index, %umax 667 br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge 668 669forcoll.notmutated.forcoll.loopbody_crit_edge: 670 %phitmp = add i64 %forcoll.index, 1 671 br label %forcoll.loopbody 672 673forcoll.refetch: 674 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 675 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 676 %4 = icmp eq i64 %call7, 0 677 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer 678 679forcoll.empty: 680 call void @llvm.objc.release(ptr %2) nounwind 681 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0 682 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 683 ret void 684} 685 686; Like test10, but without a split backedge. TODO: optimize this. 687 688; CHECK-LABEL: define void @test10b( 689; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 690; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue 691; CHECK: @llvm.objc.retain 692; CHECK: } 693define void @test10b() nounwind { 694entry: 695 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8 696 %items.ptr = alloca [16 x ptr], align 8 697 %call = call ptr @returner() 698 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 699 %call1 = call ptr @returner() 700 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind 701 call void @callee() 702 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false) 703 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind 704 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 705 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16) 706 %iszero = icmp eq i64 %call4, 0 707 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit 708 709forcoll.loopinit: 710 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2 711 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8 712 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8 713 br label %forcoll.loopbody.outer 714 715forcoll.loopbody.outer: 716 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ] 717 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1 718 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1 719 br label %forcoll.loopbody 720 721forcoll.loopbody: 722 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated ], [ 0, %forcoll.loopbody.outer ] 723 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8 724 %statemutations = load i64, ptr %mutationsptr5, align 8 725 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations 726 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated 727 728forcoll.mutated: 729 call void @llvm.objc.enumerationMutation(ptr %2) 730 br label %forcoll.notmutated 731 732forcoll.notmutated: 733 %phitmp = add i64 %forcoll.index, 1 734 %exitcond = icmp eq i64 %phitmp, %umax 735 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody 736 737forcoll.refetch: 738 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 739 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16) 740 %4 = icmp eq i64 %call7, 0 741 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer 742 743forcoll.empty: 744 call void @llvm.objc.release(ptr %2) nounwind 745 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0 746 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 747 ret void 748} 749 750; Pointers to strong pointers can obscure provenance relationships. Be conservative 751; in the face of escaping pointers. rdar://12150909. 752 753%struct.__block_d = type { i64, i64 } 754 755@_NSConcreteStackBlock = external global ptr 756@__block_d_tmp = external hidden constant { i64, i64, ptr, ptr, ptr, ptr } 757@__block_d_tmp5 = external hidden constant { i64, i64, ptr, ptr, ptr, ptr } 758 759; CHECK-LABEL: define void @test11( 760; CHECK: tail call ptr @llvm.objc.retain(ptr %call) [[NUW:#[0-9]+]] 761; CHECK: tail call ptr @llvm.objc.retain(ptr %call) [[NUW]] 762; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]], !clang.imprecise_release !0 763; CHECK: } 764define void @test11() { 765entry: 766 %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8 767 %block9 = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8 768 %call = call ptr @def(), !clang.arc.no_objc_arc_exceptions !0 769 %foo = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 5 770 %block.isa = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 0 771 store ptr @_NSConcreteStackBlock, ptr %block.isa, align 8 772 %block.flags = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 1 773 store i32 1107296256, ptr %block.flags, align 8 774 %block.reserved = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 2 775 store i32 0, ptr %block.reserved, align 4 776 %block.invoke = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 3 777 store ptr @__crasher_block_invoke, ptr %block.invoke, align 8 778 %block.d = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 4 779 store ptr @__block_d_tmp, ptr %block.d, align 8 780 %foo2 = tail call ptr @llvm.objc.retain(ptr %call) nounwind 781 store ptr %foo2, ptr %foo, align 8 782 %foo5 = call ptr @llvm.objc.retainBlock(ptr %block) nounwind 783 call void @use(ptr %foo5), !clang.arc.no_objc_arc_exceptions !0 784 call void @llvm.objc.release(ptr %foo5) nounwind 785 %strongdestroy = load ptr, ptr %foo, align 8 786 call void @llvm.objc.release(ptr %strongdestroy) nounwind, !clang.imprecise_release !0 787 %foo10 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 5 788 %block.isa11 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 0 789 store ptr @_NSConcreteStackBlock, ptr %block.isa11, align 8 790 %block.flags12 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 1 791 store i32 1107296256, ptr %block.flags12, align 8 792 %block.reserved13 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 2 793 store i32 0, ptr %block.reserved13, align 4 794 %block.invoke14 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 3 795 store ptr @__crasher_block_invoke1, ptr %block.invoke14, align 8 796 %block.d15 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 4 797 store ptr @__block_d_tmp5, ptr %block.d15, align 8 798 %foo18 = call ptr @llvm.objc.retain(ptr %call) nounwind 799 store ptr %call, ptr %foo10, align 8 800 %foo21 = call ptr @llvm.objc.retainBlock(ptr %block9) nounwind 801 call void @use(ptr %foo21), !clang.arc.no_objc_arc_exceptions !0 802 call void @llvm.objc.release(ptr %foo21) nounwind 803 %strongdestroy25 = load ptr, ptr %foo10, align 8 804 call void @llvm.objc.release(ptr %strongdestroy25) nounwind, !clang.imprecise_release !0 805 call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0 806 ret void 807} 808 809 810; CHECK: attributes [[NUW]] = { nounwind } 811; CHECK: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) } 812; CHECK: attributes #2 = { nonlazybind } 813