| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt < %s -passes='unify-loop-exits' -S | FileCheck %s |
| |
| define void @loop_1_callbr(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) { |
| ; CHECK-LABEL: define void @loop_1_callbr( |
| ; CHECK-SAME: i1 [[PREDENTRY:%.*]], i1 [[PREDB:%.*]], i1 [[PREDC:%.*]], i1 [[PREDD:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br i1 [[PREDENTRY]], label %[[A:.*]], label %[[G:.*]] |
| ; CHECK: [[A]]: |
| ; CHECK-NEXT: br label %[[B:.*]] |
| ; CHECK: [[B]]: |
| ; CHECK-NEXT: callbr void asm "", "r,!i,!i"(i1 [[PREDB]]) |
| ; CHECK-NEXT: to label %[[C:.*]] [label %[[B_TARGET_E:.*]], label %[[B_TARGET_E]]] |
| ; CHECK: [[C]]: |
| ; CHECK-NEXT: callbr void asm "", "r,!i"(i1 [[PREDC]]) |
| ; CHECK-NEXT: to label %[[D:.*]] [label %[[C_TARGET_F:.*]]] |
| ; CHECK: [[D]]: |
| ; CHECK-NEXT: callbr void asm "", "r,!i"(i1 [[PREDD]]) |
| ; CHECK-NEXT: to label %[[A]] [label %[[D_TARGET_F:.*]]] |
| ; CHECK: [[E:.*]]: |
| ; CHECK-NEXT: br label %[[EXIT:.*]] |
| ; CHECK: [[F:.*]]: |
| ; CHECK-NEXT: br label %[[EXIT]] |
| ; CHECK: [[G]]: |
| ; CHECK-NEXT: br label %[[F]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; CHECK: [[B_TARGET_E]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD:.*]] |
| ; CHECK: [[C_TARGET_F]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD]] |
| ; CHECK: [[D_TARGET_F]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD]] |
| ; CHECK: [[LOOP_EXIT_GUARD]]: |
| ; CHECK-NEXT: [[GUARD_E:%.*]] = phi i1 [ true, %[[B_TARGET_E]] ], [ false, %[[C_TARGET_F]] ], [ false, %[[D_TARGET_F]] ] |
| ; CHECK-NEXT: br i1 [[GUARD_E]], label %[[E]], label %[[F]] |
| ; |
| entry: |
| br i1 %PredEntry, label %A, label %G |
| |
| A: |
| br label %B |
| |
| B: |
| callbr void asm "", "r,!i,!i"(i1 %PredB) to label %C [label %E, label %E] |
| |
| C: |
| callbr void asm "", "r,!i"(i1 %PredC) to label %D [label %F] |
| |
| D: |
| callbr void asm "", "r,!i"(i1 %PredD) to label %A [label %F] |
| |
| E: |
| br label %exit |
| |
| F: |
| br label %exit |
| |
| G: |
| br label %F |
| |
| exit: |
| ret void |
| } |
| |
| define void @multiedge_both_callbr(i1 %Pred) { |
| ; CHECK-LABEL: define void @multiedge_both_callbr( |
| ; CHECK-SAME: i1 [[PRED:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: callbr void asm "", "r,!i"(i1 [[PRED]]) |
| ; CHECK-NEXT: to label %[[LOOP_NEXT:.*]] [label %[[LOOP_NEXT]]] |
| ; CHECK: [[LOOP_NEXT]]: |
| ; CHECK-NEXT: [[PHI_INTERNAL:%.*]] = phi i32 [ 1, %[[LOOP]] ], [ 1, %[[LOOP]] ] |
| ; CHECK-NEXT: callbr void asm "", "r,!i,!i"(i1 [[PRED]]) |
| ; CHECK-NEXT: to label %[[LOOP]] [label %[[LOOP_NEXT_TARGET_EXIT:.*]], label %[[LOOP_NEXT_TARGET_EXIT]]] |
| ; CHECK: [[EXIT:.*]]: |
| ; CHECK-NEXT: [[PHI_EXTERNAL:%.*]] = phi i32 [ 2, %[[LOOP_NEXT_TARGET_EXIT]] ] |
| ; CHECK-NEXT: ret void |
| ; CHECK: [[LOOP_NEXT_TARGET_EXIT]]: |
| ; CHECK-NEXT: br label %[[EXIT]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| callbr void asm "", "r,!i"(i1 %Pred) to label %loop.next [label %loop.next] |
| |
| loop.next: |
| %phi.internal = phi i32 [ 1, %loop ], [ 1, %loop ] |
| callbr void asm "", "r,!i,!i"(i1 %Pred) to label %loop [label %exit, label %exit] |
| |
| exit: |
| %phi.external = phi i32 [ 2, %loop.next ], [ 2, %loop.next ] |
| ret void |
| } |
| |
| define i32 @multiedge_restore_ssa_callbr() { |
| ; CHECK-LABEL: define i32 @multiedge_restore_ssa_callbr() { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[HEADER:.*]] |
| ; CHECK: [[HEADER]]: |
| ; CHECK-NEXT: [[VAL:%.*]] = add i32 0, 0 |
| ; CHECK-NEXT: callbr void asm "", "r,!i,!i"(i1 false) |
| ; CHECK-NEXT: to label %[[HEADER_TARGET_EXIT1:.*]] [label %[[HEADER_TARGET_COMMON_RET:.*]], label %[[SECOND_EXITING:.*]]] |
| ; CHECK: [[SECOND_EXITING]]: |
| ; CHECK-NEXT: callbr void asm "", "r,!i,!i"(i1 false) |
| ; CHECK-NEXT: to label %[[HEADER]] [label %[[SECOND_EXITING_TARGET_EXIT1:.*]], label %[[SECOND_EXITING_TARGET_COMMON_RET:.*]]] |
| ; CHECK: [[COMMON_RET:.*]]: |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: [[EXIT1:.*]]: |
| ; CHECK-NEXT: [[USE1:%.*]] = or i32 [[VAL_MOVED:%.*]], 0 |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: [[HEADER_TARGET_EXIT1]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD:.*]] |
| ; CHECK: [[HEADER_TARGET_COMMON_RET]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD]] |
| ; CHECK: [[SECOND_EXITING_TARGET_EXIT1]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD]] |
| ; CHECK: [[SECOND_EXITING_TARGET_COMMON_RET]]: |
| ; CHECK-NEXT: br label %[[LOOP_EXIT_GUARD]] |
| ; CHECK: [[LOOP_EXIT_GUARD]]: |
| ; CHECK-NEXT: [[VAL_MOVED]] = phi i32 [ [[VAL]], %[[HEADER_TARGET_EXIT1]] ], [ [[VAL]], %[[SECOND_EXITING_TARGET_EXIT1]] ], [ [[VAL]], %[[HEADER_TARGET_COMMON_RET]] ], [ [[VAL]], %[[SECOND_EXITING_TARGET_COMMON_RET]] ] |
| ; CHECK-NEXT: [[GUARD_EXIT1:%.*]] = phi i1 [ true, %[[HEADER_TARGET_EXIT1]] ], [ false, %[[HEADER_TARGET_COMMON_RET]] ], [ true, %[[SECOND_EXITING_TARGET_EXIT1]] ], [ false, %[[SECOND_EXITING_TARGET_COMMON_RET]] ] |
| ; CHECK-NEXT: br i1 [[GUARD_EXIT1]], label %[[EXIT1]], label %[[COMMON_RET]] |
| ; |
| entry: |
| br label %header |
| |
| header: ; preds = %second_exiting, %entry |
| %val = add i32 0, 0 |
| callbr void asm "", "r,!i,!i"(i1 false) to label %exit1 [label %common.ret, label %second_exiting] |
| |
| second_exiting: ; preds = %header |
| callbr void asm "", "r,!i,!i"(i1 false) to label %header [label %exit1, label %common.ret] |
| |
| common.ret: ; preds = %second_exiting, %header |
| ret i32 0 |
| |
| exit1: ; preds = %second_exiting, %header |
| %use1 = or i32 %val, 0 |
| ret i32 0 |
| } |