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 7 declare void @use_pointer(i8*) 8 declare i8* @objc_retain(i8*) 9 declare void @objc_release(i8*) 10 declare 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: } 19 define void @test0(i8* %digits) { 20 entry: 21 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind 22 call void @use_pointer(i8* %digits) 23 br label %for.body 24 25 for.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 32 for.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: } 44 define void @test1(i8* %digits) { 45 entry: 46 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind 47 br label %for.body 48 49 for.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 57 for.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: } 69 define void @test2(i8* %digits) { 70 entry: 71 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind 72 br label %for.body 73 74 for.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 81 for.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: } 98 define void @test3(i8* %a) nounwind { 99 entry: 100 %outer = call i8* @objc_retain(i8* %a) nounwind 101 %inner = call i8* @objc_retain(i8* %a) nounwind 102 br label %loop 103 104 loop: 105 call void @callee() 106 store i8 0, i8* %a 107 br i1 undef, label %loop, label %exit 108 109 exit: 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: } 124 define void @test4(i8* %a) nounwind { 125 entry: 126 %outer = call i8* @objc_retain(i8* %a) nounwind 127 %inner = call i8* @objc_retain(i8* %a) nounwind 128 br label %loop 129 130 loop: 131 br label %more 132 133 more: 134 call void @callee() 135 call void @callee() 136 store i8 0, i8* %a 137 br i1 undef, label %loop, label %exit 138 139 exit: 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: } 156 define void @test5(i8* %a) nounwind { 157 entry: 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 163 loop: 164 br i1 undef, label %true, label %more 165 166 true: 167 br label %more 168 169 more: 170 br i1 undef, label %exit, label %loop 171 172 exit: 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: } 189 define void @test6(i8* %a) nounwind { 190 entry: 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 195 loop: 196 br i1 undef, label %true, label %more 197 198 true: 199 call void @callee() 200 br label %more 201 202 more: 203 br i1 undef, label %exit, label %loop 204 205 exit: 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: } 222 define void @test7(i8* %a) nounwind { 223 entry: 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 229 loop: 230 br i1 undef, label %true, label %more 231 232 true: 233 call void @use_pointer(i8* %a) 234 br label %more 235 236 more: 237 br i1 undef, label %exit, label %loop 238 239 exit: 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: } 254 define void @test8(i8* %a) nounwind { 255 entry: 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 260 loop: 261 br i1 undef, label %true, label %more 262 263 true: 264 call void @callee() 265 call void @use_pointer(i8* %a) 266 br label %more 267 268 more: 269 br i1 undef, label %exit, label %loop 270 271 exit: 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: } 284 define void @test9(i8* %a) nounwind { 285 entry: 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 290 loop: 291 br i1 undef, label %true, label %more 292 293 true: 294 call void @use_pointer(i8* %a) 295 br label %more 296 297 more: 298 br i1 undef, label %exit, label %loop 299 300 exit: 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: } 313 define void @test10(i8* %a) nounwind { 314 entry: 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 319 loop: 320 br i1 undef, label %true, label %more 321 322 true: 323 call void @callee() 324 br label %more 325 326 more: 327 br i1 undef, label %exit, label %loop 328 329 exit: 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: } 342 define void @test11(i8* %a) nounwind { 343 entry: 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 348 loop: 349 br i1 undef, label %true, label %more 350 351 true: 352 br label %more 353 354 more: 355 br i1 undef, label %exit, label %loop 356 357 exit: 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: } 376 define void @test12(i8* %a) nounwind { 377 entry: 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 382 loop: 383 br i1 undef, label %true, label %more 384 385 true: 386 ret void 387 388 more: 389 br i1 undef, label %exit, label %loop 390 391 exit: 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