1; RUN: opt -S -objc-arc < %s | FileCheck %s 2; rdar://9503416 3 4; Detect loop boundaries and don't move retains and releases 5; across them. 6 7declare void @use_pointer(i8*) 8declare i8* @objc_retain(i8*) 9declare void @objc_release(i8*) 10declare void @callee() 11 12; CHECK: define void @test0( 13; CHECK: call i8* @objc_retain( 14; CHECK: for.body: 15; CHECK-NOT: @objc 16; CHECK: for.end: 17; CHECK: call void @objc_release( 18; CHECK: } 19define void @test0(i8* %digits) { 20entry: 21 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind 22 call void @use_pointer(i8* %digits) 23 br label %for.body 24 25for.body: ; preds = %for.body, %entry 26 %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ] 27 call void @use_pointer(i8* %digits) 28 %inc = add i64 %upcDigitIndex.01, 1 29 %cmp = icmp ult i64 %inc, 12 30 br i1 %cmp, label %for.body, label %for.end 31 32for.end: ; preds = %for.body 33 call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0 34 ret void 35} 36 37; CHECK: define void @test1( 38; CHECK: call i8* @objc_retain( 39; CHECK: for.body: 40; CHECK-NOT: @objc 41; CHECK: for.end: 42; CHECK: void @objc_release( 43; CHECK: } 44define void @test1(i8* %digits) { 45entry: 46 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind 47 br label %for.body 48 49for.body: ; preds = %for.body, %entry 50 %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ] 51 call void @use_pointer(i8* %digits) 52 call void @use_pointer(i8* %digits) 53 %inc = add i64 %upcDigitIndex.01, 1 54 %cmp = icmp ult i64 %inc, 12 55 br i1 %cmp, label %for.body, label %for.end 56 57for.end: ; preds = %for.body 58 call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0 59 ret void 60} 61 62; CHECK: define void @test2( 63; CHECK: call i8* @objc_retain( 64; CHECK: for.body: 65; CHECK-NOT: @objc 66; CHECK: for.end: 67; CHECK: void @objc_release( 68; CHECK: } 69define void @test2(i8* %digits) { 70entry: 71 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind 72 br label %for.body 73 74for.body: ; preds = %for.body, %entry 75 %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ] 76 call void @use_pointer(i8* %digits) 77 %inc = add i64 %upcDigitIndex.01, 1 78 %cmp = icmp ult i64 %inc, 12 79 br i1 %cmp, label %for.body, label %for.end 80 81for.end: ; preds = %for.body 82 call void @use_pointer(i8* %digits) 83 call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0 84 ret void 85} 86 87; Delete nested retain+release pairs around loops. 88 89; CHECK: define void @test3(i8* %a) nounwind { 90; CHECK-NEXT: entry: 91; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind 92; CHECK-NEXT: br label %loop 93; CHECK-NOT: @objc_ 94; CHECK: exit: 95; CHECK-NEXT: call void @objc_release(i8* %a) 96; CHECK-NEXT: ret void 97; CHECK-NEXT: } 98define void @test3(i8* %a) nounwind { 99entry: 100 %outer = call i8* @objc_retain(i8* %a) nounwind 101 %inner = call i8* @objc_retain(i8* %a) nounwind 102 br label %loop 103 104loop: 105 call void @callee() 106 store i8 0, i8* %a 107 br i1 undef, label %loop, label %exit 108 109exit: 110 call void @objc_release(i8* %a) nounwind 111 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 112 ret void 113} 114 115; CHECK: define void @test4(i8* %a) nounwind { 116; CHECK-NEXT: entry: 117; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind 118; CHECK-NEXT: br label %loop 119; CHECK-NOT: @objc_ 120; CHECK: exit: 121; CHECK-NEXT: call void @objc_release(i8* %a) 122; CHECK-NEXT: ret void 123; CHECK-NEXT: } 124define void @test4(i8* %a) nounwind { 125entry: 126 %outer = call i8* @objc_retain(i8* %a) nounwind 127 %inner = call i8* @objc_retain(i8* %a) nounwind 128 br label %loop 129 130loop: 131 br label %more 132 133more: 134 call void @callee() 135 call void @callee() 136 store i8 0, i8* %a 137 br i1 undef, label %loop, label %exit 138 139exit: 140 call void @objc_release(i8* %a) nounwind 141 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 142 ret void 143} 144 145; CHECK: define void @test5(i8* %a) nounwind { 146; CHECK-NEXT: entry: 147; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind 148; CHECK-NEXT: call void @callee() 149; CHECK-NEXT: br label %loop 150; CHECK-NOT: @objc_ 151; CHECK: exit: 152; CHECK-NEXT: call void @use_pointer(i8* %a) 153; CHECK-NEXT: call void @objc_release(i8* %a) 154; CHECK-NEXT: ret void 155; CHECK-NEXT: } 156define void @test5(i8* %a) nounwind { 157entry: 158 %outer = tail call i8* @objc_retain(i8* %a) nounwind 159 %inner = tail call i8* @objc_retain(i8* %a) nounwind 160 call void @callee() 161 br label %loop 162 163loop: 164 br i1 undef, label %true, label %more 165 166true: 167 br label %more 168 169more: 170 br i1 undef, label %exit, label %loop 171 172exit: 173 call void @use_pointer(i8* %a) 174 call void @objc_release(i8* %a) nounwind 175 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 176 ret void 177} 178 179; CHECK: define void @test6(i8* %a) nounwind { 180; CHECK-NEXT: entry: 181; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind 182; CHECK-NEXT: br label %loop 183; CHECK-NOT: @objc_ 184; CHECK: exit: 185; CHECK-NEXT: call void @use_pointer(i8* %a) 186; CHECK-NEXT: call void @objc_release(i8* %a) 187; CHECK-NEXT: ret void 188; CHECK-NEXT: } 189define void @test6(i8* %a) nounwind { 190entry: 191 %outer = tail call i8* @objc_retain(i8* %a) nounwind 192 %inner = tail call i8* @objc_retain(i8* %a) nounwind 193 br label %loop 194 195loop: 196 br i1 undef, label %true, label %more 197 198true: 199 call void @callee() 200 br label %more 201 202more: 203 br i1 undef, label %exit, label %loop 204 205exit: 206 call void @use_pointer(i8* %a) 207 call void @objc_release(i8* %a) nounwind 208 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 209 ret void 210} 211 212; CHECK: define void @test7(i8* %a) nounwind { 213; CHECK-NEXT: entry: 214; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind 215; CHECK-NEXT: call void @callee() 216; CHECK-NEXT: br label %loop 217; CHECK-NOT: @objc_ 218; CHECK: exit: 219; CHECK-NEXT: call void @objc_release(i8* %a) 220; CHECK-NEXT: ret void 221; CHECK-NEXT: } 222define void @test7(i8* %a) nounwind { 223entry: 224 %outer = tail call i8* @objc_retain(i8* %a) nounwind 225 %inner = tail call i8* @objc_retain(i8* %a) nounwind 226 call void @callee() 227 br label %loop 228 229loop: 230 br i1 undef, label %true, label %more 231 232true: 233 call void @use_pointer(i8* %a) 234 br label %more 235 236more: 237 br i1 undef, label %exit, label %loop 238 239exit: 240 call void @objc_release(i8* %a) nounwind 241 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 242 ret void 243} 244 245; CHECK: define void @test8(i8* %a) nounwind { 246; CHECK-NEXT: entry: 247; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind 248; CHECK-NEXT: br label %loop 249; CHECK-NOT: @objc_ 250; CHECK: exit: 251; CHECK-NEXT: call void @objc_release(i8* %a) 252; CHECK-NEXT: ret void 253; CHECK-NEXT: } 254define void @test8(i8* %a) nounwind { 255entry: 256 %outer = tail call i8* @objc_retain(i8* %a) nounwind 257 %inner = tail call i8* @objc_retain(i8* %a) nounwind 258 br label %loop 259 260loop: 261 br i1 undef, label %true, label %more 262 263true: 264 call void @callee() 265 call void @use_pointer(i8* %a) 266 br label %more 267 268more: 269 br i1 undef, label %exit, label %loop 270 271exit: 272 call void @objc_release(i8* %a) nounwind 273 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 274 ret void 275} 276 277; CHECK: define void @test9(i8* %a) nounwind { 278; CHECK-NEXT: entry: 279; CHECK-NEXT: br label %loop 280; CHECK-NOT: @objc_ 281; CHECK: exit: 282; CHECK-NEXT: ret void 283; CHECK-NEXT: } 284define void @test9(i8* %a) nounwind { 285entry: 286 %outer = tail call i8* @objc_retain(i8* %a) nounwind 287 %inner = tail call i8* @objc_retain(i8* %a) nounwind 288 br label %loop 289 290loop: 291 br i1 undef, label %true, label %more 292 293true: 294 call void @use_pointer(i8* %a) 295 br label %more 296 297more: 298 br i1 undef, label %exit, label %loop 299 300exit: 301 call void @objc_release(i8* %a) nounwind 302 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 303 ret void 304} 305 306; CHECK: define void @test10(i8* %a) nounwind { 307; CHECK-NEXT: entry: 308; CHECK-NEXT: br label %loop 309; CHECK-NOT: @objc_ 310; CHECK: exit: 311; CHECK-NEXT: ret void 312; CHECK-NEXT: } 313define void @test10(i8* %a) nounwind { 314entry: 315 %outer = tail call i8* @objc_retain(i8* %a) nounwind 316 %inner = tail call i8* @objc_retain(i8* %a) nounwind 317 br label %loop 318 319loop: 320 br i1 undef, label %true, label %more 321 322true: 323 call void @callee() 324 br label %more 325 326more: 327 br i1 undef, label %exit, label %loop 328 329exit: 330 call void @objc_release(i8* %a) nounwind 331 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 332 ret void 333} 334 335; CHECK: define void @test11(i8* %a) nounwind { 336; CHECK-NEXT: entry: 337; CHECK-NEXT: br label %loop 338; CHECK-NOT: @objc_ 339; CHECK: exit: 340; CHECK-NEXT: ret void 341; CHECK-NEXT: } 342define void @test11(i8* %a) nounwind { 343entry: 344 %outer = tail call i8* @objc_retain(i8* %a) nounwind 345 %inner = tail call i8* @objc_retain(i8* %a) nounwind 346 br label %loop 347 348loop: 349 br i1 undef, label %true, label %more 350 351true: 352 br label %more 353 354more: 355 br i1 undef, label %exit, label %loop 356 357exit: 358 call void @objc_release(i8* %a) nounwind 359 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 360 ret void 361} 362 363; Don't delete anything if they're not balanced. 364 365; CHECK: define void @test12(i8* %a) nounwind { 366; CHECK-NEXT: entry: 367; CHECK-NEXT: %outer = tail call i8* @objc_retain(i8* %a) nounwind 368; CHECK-NEXT: %inner = tail call i8* @objc_retain(i8* %a) nounwind 369; CHECK-NEXT: br label %loop 370; CHECK-NOT: @objc_ 371; CHECK: exit: 372; CHECK-NEXT: call void @objc_release(i8* %a) nounwind 373; CHECK-NEXT: call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 374; CHECK-NEXT: ret void 375; CHECK-NEXT: } 376define void @test12(i8* %a) nounwind { 377entry: 378 %outer = tail call i8* @objc_retain(i8* %a) nounwind 379 %inner = tail call i8* @objc_retain(i8* %a) nounwind 380 br label %loop 381 382loop: 383 br i1 undef, label %true, label %more 384 385true: 386 ret void 387 388more: 389 br i1 undef, label %exit, label %loop 390 391exit: 392 call void @objc_release(i8* %a) nounwind 393 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0 394 ret void 395} 396 397!0 = metadata !{} 398