813 lines · plain
1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s2 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 16@"\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 88@"\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) nounwind16declare ptr @objc_msgSend(ptr, ptr, ...) nonlazybind17declare 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.retain30; CHECK-NOT: @llvm.objc.retain31; CHECK: }32define void @test0(ptr %a) nounwind {33entry:34 %state.ptr = alloca %struct.__objcFastEnumerationState, align 835 %items.ptr = alloca [16 x ptr], align 836 %0 = call ptr @llvm.objc.retain(ptr %a) nounwind37 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) nounwind39 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 840 %call = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)41 %iszero = icmp eq i64 %call, 042 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit43 44forcoll.loopinit:45 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 246 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 847 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 848 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 149 br label %forcoll.loopbody.outer50 51forcoll.loopbody.outer:52 %forcoll.count.ph = phi i64 [ %call, %forcoll.loopinit ], [ %call6, %forcoll.refetch ]53 %tmp7 = icmp ugt i64 %forcoll.count.ph, 154 %umax = select i1 %tmp7, i64 %forcoll.count.ph, i64 155 br label %forcoll.loopbody56 57forcoll.loopbody:58 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]59 %mutationsptr3 = load ptr, ptr %mutationsptr.ptr, align 860 %statemutations = load i64, ptr %mutationsptr3, align 861 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations62 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated63 64forcoll.mutated:65 call void @llvm.objc.enumerationMutation(ptr %1)66 br label %forcoll.notmutated67 68forcoll.notmutated:69 %stateitems = load ptr, ptr %stateitems.ptr, align 870 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index71 %3 = load ptr, ptr %currentitem.ptr, align 872 call void @use(ptr %3)73 %4 = add i64 %forcoll.index, 174 %exitcond = icmp eq i64 %4, %umax75 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody76 77forcoll.refetch:78 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 879 %call6 = call i64 @objc_msgSend(ptr %1, ptr %tmp5, ptr %state.ptr, ptr %items.ptr, i64 16)80 %5 = icmp eq i64 %call6, 081 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer82 83forcoll.empty:84 call void @llvm.objc.release(ptr %1) nounwind85 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !086 ret void87}88 89; Delete a nested retain+release pair.90 91; CHECK-LABEL: define void @test2(92; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue93; CHECK-NOT: @llvm.objc.retain94; CHECK: }95define void @test2() nounwind {96entry:97 %state.ptr = alloca %struct.__objcFastEnumerationState, align 898 %items.ptr = alloca [16 x ptr], align 899 %call = call ptr @returner()100 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind101 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) nounwind103 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8104 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)105 %iszero = icmp eq i64 %call3, 0106 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit107 108forcoll.loopinit:109 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2110 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8111 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8112 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1113 br label %forcoll.loopbody.outer114 115forcoll.loopbody.outer:116 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]117 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1118 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1119 br label %forcoll.loopbody120 121forcoll.loopbody:122 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]123 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8124 %statemutations = load i64, ptr %mutationsptr4, align 8125 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations126 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated127 128forcoll.mutated:129 call void @llvm.objc.enumerationMutation(ptr %1)130 br label %forcoll.notmutated131 132forcoll.notmutated:133 %stateitems = load ptr, ptr %stateitems.ptr, align 8134 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index135 %3 = load ptr, ptr %currentitem.ptr, align 8136 call void @use(ptr %3)137 %4 = add i64 %forcoll.index, 1138 %exitcond = icmp eq i64 %4, %umax139 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody140 141forcoll.refetch:142 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8143 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)144 %5 = icmp eq i64 %call7, 0145 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer146 147forcoll.empty:148 call void @llvm.objc.release(ptr %1) nounwind149 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0150 ret void151}152 153; Delete a nested retain+release pair.154 155; CHECK-LABEL: define void @test4(156; CHECK: call ptr @llvm.objc.retain157; CHECK-NOT: @llvm.objc.retain158; CHECK: }159define void @test4() nounwind {160entry:161 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8162 %items.ptr = alloca [16 x ptr], align 8163 %tmp = load ptr, ptr @g, align 8164 %0 = call ptr @llvm.objc.retain(ptr %tmp) nounwind165 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) nounwind167 %tmp4 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8168 %call = call i64 @objc_msgSend(ptr %1, ptr %tmp4, ptr %state.ptr, ptr %items.ptr, i64 16)169 %iszero = icmp eq i64 %call, 0170 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit171 172forcoll.loopinit:173 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2174 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8175 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8176 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1177 br label %forcoll.loopbody.outer178 179forcoll.loopbody.outer:180 %forcoll.count.ph = phi i64 [ %call, %forcoll.loopinit ], [ %call8, %forcoll.refetch ]181 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1182 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1183 br label %forcoll.loopbody184 185forcoll.loopbody:186 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]187 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8188 %statemutations = load i64, ptr %mutationsptr5, align 8189 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations190 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated191 192forcoll.mutated:193 call void @llvm.objc.enumerationMutation(ptr %1)194 br label %forcoll.notmutated195 196forcoll.notmutated:197 %stateitems = load ptr, ptr %stateitems.ptr, align 8198 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index199 %3 = load ptr, ptr %currentitem.ptr, align 8200 call void @use(ptr %3)201 %4 = add i64 %forcoll.index, 1202 %exitcond = icmp eq i64 %4, %umax203 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody204 205forcoll.refetch:206 %tmp7 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8207 %call8 = call i64 @objc_msgSend(ptr %1, ptr %tmp7, ptr %state.ptr, ptr %items.ptr, i64 16)208 %5 = icmp eq i64 %call8, 0209 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer210 211forcoll.empty:212 call void @llvm.objc.release(ptr %1) nounwind213 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0214 ret void215}216 217; Delete a nested retain+release pair.218 219; CHECK-LABEL: define void @test5(220; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue221; CHECK-NOT: @llvm.objc.retain222; CHECK: }223define void @test5() nounwind {224entry:225 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8226 %items.ptr = alloca [16 x ptr], align 8227 %call = call ptr @returner()228 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind229 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) nounwind231 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8232 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)233 %iszero = icmp eq i64 %call3, 0234 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit235 236forcoll.loopinit:237 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2238 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8239 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8240 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1241 br label %forcoll.loopbody.outer242 243forcoll.loopbody.outer:244 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]245 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1246 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1247 br label %forcoll.loopbody248 249forcoll.loopbody:250 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]251 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8252 %statemutations = load i64, ptr %mutationsptr4, align 8253 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations254 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated255 256forcoll.mutated:257 call void @llvm.objc.enumerationMutation(ptr %1)258 br label %forcoll.notmutated259 260forcoll.notmutated:261 %stateitems = load ptr, ptr %stateitems.ptr, align 8262 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index263 %3 = load ptr, ptr %currentitem.ptr, align 8264 call void @use(ptr %3)265 %4 = add i64 %forcoll.index, 1266 %exitcond = icmp eq i64 %4, %umax267 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody268 269forcoll.refetch:270 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8271 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)272 %5 = icmp eq i64 %call7, 0273 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer274 275forcoll.empty:276 call void @llvm.objc.release(ptr %1) nounwind277 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0278 ret void279}280 281; We handle this now due to the fact that a release just needs a post dominating282; use.283;284; CHECK-LABEL: define void @test6(285; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue286; CHECK-NOT: @llvm.objc.retain287; CHECK: }288define void @test6() nounwind {289entry:290 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8291 %items.ptr = alloca [16 x ptr], align 8292 %call = call ptr @returner()293 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind294 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) nounwind296 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8297 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)298 %iszero = icmp eq i64 %call3, 0299 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit300 301forcoll.loopinit:302 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2303 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8304 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8305 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1306 br label %forcoll.loopbody.outer307 308forcoll.loopbody.outer:309 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]310 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1311 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1312 br label %forcoll.loopbody313 314forcoll.loopbody:315 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]316 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8317 %statemutations = load i64, ptr %mutationsptr4, align 8318 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations319 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated320 321forcoll.mutated:322 call void @llvm.objc.enumerationMutation(ptr %1)323 br label %forcoll.notmutated324 325forcoll.notmutated:326 %stateitems = load ptr, ptr %stateitems.ptr, align 8327 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index328 %3 = load ptr, ptr %currentitem.ptr, align 8329 call void @use(ptr %3)330 %4 = add i64 %forcoll.index, 1331 %exitcond = icmp eq i64 %4, %umax332 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody333 334forcoll.refetch:335 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8336 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)337 %5 = icmp eq i64 %call7, 0338 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer339 340forcoll.empty:341 call void @llvm.objc.release(ptr %1) nounwind342 call void @callee()343 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0344 ret void345}346 347; TODO: Delete a nested retain+release pair.348; The optimizer currently can't do this, because isn't isn't sophisticated enough in349; reasnoning about nesting.350 351; CHECK-LABEL: define void @test7(352; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue353; CHECK: @llvm.objc.retain354; CHECK: }355define void @test7() nounwind {356entry:357 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8358 %items.ptr = alloca [16 x ptr], align 8359 %call = call ptr @returner()360 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind361 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) nounwind364 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8365 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)366 %iszero = icmp eq i64 %call3, 0367 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit368 369forcoll.loopinit:370 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2371 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8372 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8373 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1374 br label %forcoll.loopbody.outer375 376forcoll.loopbody.outer:377 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]378 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1379 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1380 br label %forcoll.loopbody381 382forcoll.loopbody:383 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]384 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8385 %statemutations = load i64, ptr %mutationsptr4, align 8386 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations387 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated388 389forcoll.mutated:390 call void @llvm.objc.enumerationMutation(ptr %1)391 br label %forcoll.notmutated392 393forcoll.notmutated:394 %stateitems = load ptr, ptr %stateitems.ptr, align 8395 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index396 %3 = load ptr, ptr %currentitem.ptr, align 8397 call void @use(ptr %3)398 %4 = add i64 %forcoll.index, 1399 %exitcond = icmp eq i64 %4, %umax400 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody401 402forcoll.refetch:403 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8404 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)405 %5 = icmp eq i64 %call7, 0406 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer407 408forcoll.empty:409 call void @llvm.objc.release(ptr %1) nounwind410 call void @callee()411 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0412 ret void413}414 415; Delete a nested retain+release pair.416 417; CHECK-LABEL: define void @test8(418; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue419; CHECK-NOT: @llvm.objc.retain420; CHECK: }421define void @test8() nounwind {422entry:423 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8424 %items.ptr = alloca [16 x ptr], align 8425 %call = call ptr @returner()426 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind427 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) nounwind429 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8430 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)431 %iszero = icmp eq i64 %call3, 0432 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit433 434forcoll.loopinit:435 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2436 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8437 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8438 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1439 br label %forcoll.loopbody.outer440 441forcoll.loopbody.outer:442 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]443 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1444 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1445 br label %forcoll.loopbody446 447forcoll.loopbody:448 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.next ]449 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8450 %statemutations = load i64, ptr %mutationsptr4, align 8451 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations452 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated453 454forcoll.mutated:455 call void @llvm.objc.enumerationMutation(ptr %1)456 br label %forcoll.notmutated457 458forcoll.notmutated:459 %stateitems = load ptr, ptr %stateitems.ptr, align 8460 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index461 %3 = load ptr, ptr %currentitem.ptr, align 8462 %tobool = icmp eq ptr %3, null463 br i1 %tobool, label %forcoll.next, label %if.then464 465if.then:466 call void @callee()467 br label %forcoll.next468 469forcoll.next:470 %4 = add i64 %forcoll.index, 1471 %exitcond = icmp eq i64 %4, %umax472 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody473 474forcoll.refetch:475 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8476 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)477 %5 = icmp eq i64 %call7, 0478 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer479 480forcoll.empty:481 call void @llvm.objc.release(ptr %1) nounwind482 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0483 ret void484}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.retainAutoreleasedReturnValue492; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue493; CHECK: call ptr @llvm.objc.retain494; CHECK: }495define void @test9() nounwind {496entry:497 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8498 %items.ptr = alloca [16 x ptr], align 8499 %call = call ptr @returner()500 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind501 %call1 = call ptr @returner()502 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind503 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) nounwind505 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8506 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)507 %iszero = icmp eq i64 %call4, 0508 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit509 510forcoll.loopinit:511 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2512 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8513 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8514 br label %forcoll.loopbody.outer515 516forcoll.loopbody.outer:517 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]518 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1519 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1520 br label %forcoll.loopbody521 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 8525 %statemutations = load i64, ptr %mutationsptr5, align 8526 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations527 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated528 529forcoll.mutated:530 call void @llvm.objc.enumerationMutation(ptr %2)531 br label %forcoll.notmutated532 533forcoll.notmutated:534 %exitcond = icmp eq i64 %forcoll.index, %umax535 br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge536 537forcoll.notmutated.forcoll.loopbody_crit_edge:538 %phitmp = add i64 %forcoll.index, 1539 br label %forcoll.loopbody540 541forcoll.refetch:542 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8543 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)544 %4 = icmp eq i64 %call7, 0545 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer546 547forcoll.empty:548 call void @llvm.objc.release(ptr %2) nounwind549 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0550 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0551 ret void552}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.retainAutoreleasedReturnValue558; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue559; CHECK: @llvm.objc.retain560; CHECK: }561define void @test9b() nounwind {562entry:563 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8564 %items.ptr = alloca [16 x ptr], align 8565 %call = call ptr @returner()566 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind567 %call1 = call ptr @returner()568 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind569 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) nounwind571 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8572 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)573 %iszero = icmp eq i64 %call4, 0574 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit575 576forcoll.loopinit:577 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2578 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8579 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8580 br label %forcoll.loopbody.outer581 582forcoll.loopbody.outer:583 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]584 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1585 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1586 br label %forcoll.loopbody587 588forcoll.loopbody:589 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated ], [ 0, %forcoll.loopbody.outer ]590 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8591 %statemutations = load i64, ptr %mutationsptr5, align 8592 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations593 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated594 595forcoll.mutated:596 call void @llvm.objc.enumerationMutation(ptr %2)597 br label %forcoll.notmutated598 599forcoll.notmutated:600 %phitmp = add i64 %forcoll.index, 1601 %exitcond = icmp eq i64 %phitmp, %umax602 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody603 604forcoll.refetch:605 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8606 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)607 %4 = icmp eq i64 %call7, 0608 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer609 610forcoll.empty:611 call void @llvm.objc.release(ptr %2) nounwind612 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0613 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0614 ret void615}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.retainAutoreleasedReturnValue623; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue624; CHECK: call ptr @llvm.objc.retain625; CHECK: }626define void @test10() nounwind {627entry:628 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8629 %items.ptr = alloca [16 x ptr], align 8630 %call = call ptr @returner()631 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind632 %call1 = call ptr @returner()633 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind634 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) nounwind637 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8638 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)639 %iszero = icmp eq i64 %call4, 0640 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit641 642forcoll.loopinit:643 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2644 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8645 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8646 br label %forcoll.loopbody.outer647 648forcoll.loopbody.outer:649 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]650 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1651 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1652 br label %forcoll.loopbody653 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 8657 %statemutations = load i64, ptr %mutationsptr5, align 8658 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations659 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated660 661forcoll.mutated:662 call void @llvm.objc.enumerationMutation(ptr %2)663 br label %forcoll.notmutated664 665forcoll.notmutated:666 %exitcond = icmp eq i64 %forcoll.index, %umax667 br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge668 669forcoll.notmutated.forcoll.loopbody_crit_edge:670 %phitmp = add i64 %forcoll.index, 1671 br label %forcoll.loopbody672 673forcoll.refetch:674 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8675 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)676 %4 = icmp eq i64 %call7, 0677 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer678 679forcoll.empty:680 call void @llvm.objc.release(ptr %2) nounwind681 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0682 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0683 ret void684}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.retainAutoreleasedReturnValue690; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue691; CHECK: @llvm.objc.retain692; CHECK: }693define void @test10b() nounwind {694entry:695 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8696 %items.ptr = alloca [16 x ptr], align 8697 %call = call ptr @returner()698 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind699 %call1 = call ptr @returner()700 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind701 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) nounwind704 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8705 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)706 %iszero = icmp eq i64 %call4, 0707 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit708 709forcoll.loopinit:710 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2711 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8712 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8713 br label %forcoll.loopbody.outer714 715forcoll.loopbody.outer:716 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]717 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1718 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1719 br label %forcoll.loopbody720 721forcoll.loopbody:722 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated ], [ 0, %forcoll.loopbody.outer ]723 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8724 %statemutations = load i64, ptr %mutationsptr5, align 8725 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations726 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated727 728forcoll.mutated:729 call void @llvm.objc.enumerationMutation(ptr %2)730 br label %forcoll.notmutated731 732forcoll.notmutated:733 %phitmp = add i64 %forcoll.index, 1734 %exitcond = icmp eq i64 %phitmp, %umax735 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody736 737forcoll.refetch:738 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8739 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)740 %4 = icmp eq i64 %call7, 0741 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer742 743forcoll.empty:744 call void @llvm.objc.release(ptr %2) nounwind745 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0746 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0747 ret void748}749 750; Pointers to strong pointers can obscure provenance relationships. Be conservative751; in the face of escaping pointers. rdar://12150909.752 753%struct.__block_d = type { i64, i64 }754 755@_NSConcreteStackBlock = external global ptr756@__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 !0763; CHECK: }764define void @test11() {765entry:766 %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8767 %block9 = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8768 %call = call ptr @def(), !clang.arc.no_objc_arc_exceptions !0769 %foo = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 5770 %block.isa = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 0771 store ptr @_NSConcreteStackBlock, ptr %block.isa, align 8772 %block.flags = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 1773 store i32 1107296256, ptr %block.flags, align 8774 %block.reserved = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 2775 store i32 0, ptr %block.reserved, align 4776 %block.invoke = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 3777 store ptr @__crasher_block_invoke, ptr %block.invoke, align 8778 %block.d = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 4779 store ptr @__block_d_tmp, ptr %block.d, align 8780 %foo2 = tail call ptr @llvm.objc.retain(ptr %call) nounwind781 store ptr %foo2, ptr %foo, align 8782 %foo5 = call ptr @llvm.objc.retainBlock(ptr %block) nounwind783 call void @use(ptr %foo5), !clang.arc.no_objc_arc_exceptions !0784 call void @llvm.objc.release(ptr %foo5) nounwind785 %strongdestroy = load ptr, ptr %foo, align 8786 call void @llvm.objc.release(ptr %strongdestroy) nounwind, !clang.imprecise_release !0787 %foo10 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 5788 %block.isa11 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 0789 store ptr @_NSConcreteStackBlock, ptr %block.isa11, align 8790 %block.flags12 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 1791 store i32 1107296256, ptr %block.flags12, align 8792 %block.reserved13 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 2793 store i32 0, ptr %block.reserved13, align 4794 %block.invoke14 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 3795 store ptr @__crasher_block_invoke1, ptr %block.invoke14, align 8796 %block.d15 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 4797 store ptr @__block_d_tmp5, ptr %block.d15, align 8798 %foo18 = call ptr @llvm.objc.retain(ptr %call) nounwind799 store ptr %call, ptr %foo10, align 8800 %foo21 = call ptr @llvm.objc.retainBlock(ptr %block9) nounwind801 call void @use(ptr %foo21), !clang.arc.no_objc_arc_exceptions !0802 call void @llvm.objc.release(ptr %foo21) nounwind803 %strongdestroy25 = load ptr, ptr %foo10, align 8804 call void @llvm.objc.release(ptr %strongdestroy25) nounwind, !clang.imprecise_release !0805 call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0806 ret void807}808 809 810; CHECK: attributes [[NUW]] = { nounwind }811; CHECK: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) }812; CHECK: attributes #2 = { nonlazybind }813