| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -S -passes=objc-arc < %s | FileCheck %s |
| ; rdar://9503416 |
| |
| ; Detect loop boundaries and don't move retains and releases |
| ; across them. |
| |
| declare void @use_pointer(ptr) |
| declare ptr @llvm.objc.retain(ptr) |
| declare void @llvm.objc.release(ptr) |
| declare void @callee() |
| declare void @block_callee(ptr) |
| |
| define void @test0(ptr %digits) { |
| ; CHECK-LABEL: @test0( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[DIGITS:%.*]]) #[[ATTR0:[0-9]+]] |
| ; CHECK-NEXT: call void @use_pointer(ptr [[DIGITS]]) |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[UPCDIGITINDEX_01:%.*]] = phi i64 [ 2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ] |
| ; CHECK-NEXT: call void @use_pointer(ptr [[DIGITS]]) |
| ; CHECK-NEXT: [[INC]] = add i64 [[UPCDIGITINDEX_01]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 12 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[DIGITS]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %tmp1 = call ptr @llvm.objc.retain(ptr %digits) nounwind |
| call void @use_pointer(ptr %digits) |
| br label %for.body |
| |
| for.body: ; preds = %for.body, %entry |
| %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ] |
| call void @use_pointer(ptr %digits) |
| %inc = add i64 %upcDigitIndex.01, 1 |
| %cmp = icmp ult i64 %inc, 12 |
| br i1 %cmp, label %for.body, label %for.end |
| |
| for.end: ; preds = %for.body |
| call void @llvm.objc.release(ptr %digits) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test1(ptr %digits) { |
| ; CHECK-LABEL: @test1( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[DIGITS:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[UPCDIGITINDEX_01:%.*]] = phi i64 [ 2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ] |
| ; CHECK-NEXT: call void @use_pointer(ptr [[DIGITS]]) |
| ; CHECK-NEXT: call void @use_pointer(ptr [[DIGITS]]) |
| ; CHECK-NEXT: [[INC]] = add i64 [[UPCDIGITINDEX_01]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 12 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[DIGITS]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %tmp1 = call ptr @llvm.objc.retain(ptr %digits) nounwind |
| br label %for.body |
| |
| for.body: ; preds = %for.body, %entry |
| %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ] |
| call void @use_pointer(ptr %digits) |
| call void @use_pointer(ptr %digits) |
| %inc = add i64 %upcDigitIndex.01, 1 |
| %cmp = icmp ult i64 %inc, 12 |
| br i1 %cmp, label %for.body, label %for.end |
| |
| for.end: ; preds = %for.body |
| call void @llvm.objc.release(ptr %digits) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test2(ptr %digits) { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[DIGITS:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[UPCDIGITINDEX_01:%.*]] = phi i64 [ 2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ] |
| ; CHECK-NEXT: call void @use_pointer(ptr [[DIGITS]]) |
| ; CHECK-NEXT: [[INC]] = add i64 [[UPCDIGITINDEX_01]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 12 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: call void @use_pointer(ptr [[DIGITS]]) |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[DIGITS]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %tmp1 = call ptr @llvm.objc.retain(ptr %digits) nounwind |
| br label %for.body |
| |
| for.body: ; preds = %for.body, %entry |
| %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ] |
| call void @use_pointer(ptr %digits) |
| %inc = add i64 %upcDigitIndex.01, 1 |
| %cmp = icmp ult i64 %inc, 12 |
| br i1 %cmp, label %for.body, label %for.end |
| |
| for.end: ; preds = %for.body |
| call void @use_pointer(ptr %digits) |
| call void @llvm.objc.release(ptr %digits) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| ; Delete nested retain+release pairs around loops. |
| define void @test3(ptr %a) nounwind { |
| ; CHECK-LABEL: @test3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: store i8 0, ptr [[A]], align 1 |
| ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| call void @callee() |
| store i8 0, ptr %a |
| br i1 undef, label %loop, label %exit |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test4(ptr %a) nounwind { |
| ; CHECK-LABEL: @test4( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br label [[MORE:%.*]] |
| ; CHECK: more: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: store i8 0, ptr [[A]], align 1 |
| ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br label %more |
| |
| more: |
| call void @callee() |
| call void @callee() |
| store i8 0, ptr %a |
| br i1 undef, label %loop, label %exit |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test5(ptr %a) nounwind { |
| ; CHECK-LABEL: @test5( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @use_pointer(ptr [[A]]) |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| call void @callee() |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @use_pointer(ptr %a) |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test6(ptr %a) nounwind { |
| ; CHECK-LABEL: @test6( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @use_pointer(ptr [[A]]) |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| call void @callee() |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @use_pointer(ptr %a) |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test7(ptr %a) nounwind { |
| ; CHECK-LABEL: @test7( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use_pointer(ptr [[A]]) |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| call void @callee() |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| call void @use_pointer(ptr %a) |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test8(ptr %a) nounwind { |
| ; CHECK-LABEL: @test8( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: call void @use_pointer(ptr [[A]]) |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| call void @callee() |
| call void @use_pointer(ptr %a) |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test9(ptr %a) nounwind { |
| ; CHECK-LABEL: @test9( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use_pointer(ptr [[A:%.*]]) |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| call void @use_pointer(ptr %a) |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test10(ptr %a) nounwind { |
| ; CHECK-LABEL: @test10( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| call void @callee() |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| define void @test11(ptr %a) nounwind { |
| ; CHECK-LABEL: @test11( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: br label [[MORE]] |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| br label %more |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| ; Don't delete anything if they're not balanced. |
| |
| define void @test12(ptr %a) nounwind { |
| ; CHECK-LABEL: @test12( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: [[INNER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: br i1 undef, label [[TRUE:%.*]], label [[MORE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: ret void |
| ; CHECK: more: |
| ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]] |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| br i1 undef, label %true, label %more |
| |
| true: |
| ret void |
| |
| more: |
| br i1 undef, label %exit, label %loop |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| ; Do not improperly pair retains in a for loop with releases outside of a for |
| ; loop when the proper pairing is disguised by a separate provenance represented |
| ; by an alloca. |
| ; rdar://12969722 |
| |
| define void @test13(ptr %a) nounwind { |
| ; CHECK-LABEL: @test13( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[BLOCK:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: [[A1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[A2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A]]) #[[ATTR0]] |
| ; CHECK-NEXT: store ptr [[A]], ptr [[BLOCK]], align 8 |
| ; CHECK-NEXT: call void @block_callee(ptr [[BLOCK]]) |
| ; CHECK-NEXT: [[RELOADED_A:%.*]] = load ptr, ptr [[BLOCK]], align 8 |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[RELOADED_A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %block = alloca ptr |
| %a1 = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| br label %loop |
| |
| loop: |
| %a2 = tail call ptr @llvm.objc.retain(ptr %a) nounwind |
| store ptr %a, ptr %block, align 8 |
| call void @block_callee(ptr %block) |
| %reloaded_a = load ptr, ptr %block, align 8 |
| call void @llvm.objc.release(ptr %reloaded_a) nounwind, !clang.imprecise_release !0 |
| br i1 undef, label %loop, label %exit |
| |
| exit: |
| call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| ; The retain call in the entry block shouldn't be moved to the loop body. |
| |
| define void @test14(ptr %val0, i8 %val1) { |
| ; CHECK-LABEL: @test14( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[V1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[VAL0:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[VAL0]], null |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_END27:%.*]], label [[IF_THEN:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8 [[VAL1:%.*]], 1 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP6:%.*]] = icmp eq i8 [[VAL1]], 2 |
| ; CHECK-NEXT: br i1 [[CMP6]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: [[TOBOOL9:%.*]] = icmp eq i8 [[VAL1]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL9]], label [[FOR_COND:%.*]], label [[IF_THEN10:%.*]] |
| ; CHECK: if.then10: |
| ; CHECK-NEXT: br label [[FOR_END:%.*]] |
| ; CHECK: for.end.loopexit: |
| ; CHECK-NEXT: br label [[FOR_END]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: call void @callee() |
| ; CHECK-NEXT: call void @use_pointer(ptr [[V1]]) |
| ; CHECK-NEXT: br label [[IF_END27]] |
| ; CHECK: if.end27: |
| ; CHECK-NEXT: call void @llvm.objc.release(ptr [[V1]]) #[[ATTR0]], !clang.imprecise_release !0 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %v1 = tail call ptr @llvm.objc.retain(ptr %val0) |
| %cmp = icmp eq ptr %val0, null |
| br i1 %cmp, label %if.end27, label %if.then |
| |
| if.then: |
| %tobool = icmp eq i8 %val1, 1 |
| br label %for.body |
| |
| for.cond: |
| %cmp6 = icmp eq i8 %val1, 2 |
| br i1 %cmp6, label %for.body, label %for.end.loopexit |
| |
| for.body: |
| call void @callee() |
| %tobool9 = icmp eq i8 %val1, 0 |
| br i1 %tobool9, label %for.cond, label %if.then10 |
| |
| if.then10: |
| br label %for.end |
| |
| for.end.loopexit: |
| br label %for.end |
| |
| for.end: |
| call void @callee() |
| call void @use_pointer(ptr %v1) |
| br label %if.end27 |
| |
| if.end27: |
| call void @llvm.objc.release(ptr %v1) #0, !clang.imprecise_release !0 |
| ret void |
| } |
| |
| |
| !0 = !{} |