|  | ; RUN: opt < %s -S -loop-simplify | FileCheck %s | 
|  | ; RUN: opt < %s -S -passes=loop-simplify | FileCheck %s | 
|  |  | 
|  | ; This function should get a preheader inserted before bb3, that is jumped | 
|  | ; to by bb1 & bb2 | 
|  | define void @test() { | 
|  | ; CHECK-LABEL: define void @test( | 
|  | entry: | 
|  | br i1 true, label %bb1, label %bb2 | 
|  |  | 
|  | bb1: | 
|  | br label %bb3 | 
|  | ; CHECK:      bb1: | 
|  | ; CHECK-NEXT:   br label %[[PH:.*]] | 
|  |  | 
|  | bb2: | 
|  | br label %bb3 | 
|  | ; CHECK:      bb2: | 
|  | ; CHECK-NEXT:   br label %[[PH]] | 
|  |  | 
|  | bb3: | 
|  | br label %bb3 | 
|  | ; CHECK:      [[PH]]: | 
|  | ; CHECK-NEXT:   br label %bb3 | 
|  | ; | 
|  | ; CHECK:      bb3: | 
|  | ; CHECK-NEXT:   br label %bb3 | 
|  | } | 
|  |  | 
|  | ; Test a case where we have multiple exit blocks as successors of a single loop | 
|  | ; block that need to be made dedicated exit blocks. We also have multiple | 
|  | ; exiting edges to one of the exit blocks that all should be rewritten. | 
|  | define void @test_multiple_exits_from_single_block(i8 %a, i8* %b.ptr) { | 
|  | ; CHECK-LABEL: define void @test_multiple_exits_from_single_block( | 
|  | entry: | 
|  | switch i8 %a, label %loop [ | 
|  | i8 0, label %exit.a | 
|  | i8 1, label %exit.b | 
|  | ] | 
|  | ; CHECK:      entry: | 
|  | ; CHECK-NEXT:   switch i8 %a, label %[[PH:.*]] [ | 
|  | ; CHECK-NEXT:     i8 0, label %exit.a | 
|  | ; CHECK-NEXT:     i8 1, label %exit.b | 
|  | ; CHECK-NEXT:   ] | 
|  |  | 
|  | loop: | 
|  | %b = load volatile i8, i8* %b.ptr | 
|  | switch i8 %b, label %loop [ | 
|  | i8 0, label %exit.a | 
|  | i8 1, label %exit.b | 
|  | i8 2, label %loop | 
|  | i8 3, label %exit.a | 
|  | i8 4, label %loop | 
|  | i8 5, label %exit.a | 
|  | i8 6, label %loop | 
|  | ] | 
|  | ; CHECK:      [[PH]]: | 
|  | ; CHECK-NEXT:   br label %loop | 
|  | ; | 
|  | ; CHECK:      loop: | 
|  | ; CHECK-NEXT:   %[[B:.*]] = load volatile i8, i8* %b.ptr | 
|  | ; CHECK-NEXT:   switch i8 %[[B]], label %[[BACKEDGE:.*]] [ | 
|  | ; CHECK-NEXT:     i8 0, label %[[LOOPEXIT_A:.*]] | 
|  | ; CHECK-NEXT:     i8 1, label %[[LOOPEXIT_B:.*]] | 
|  | ; CHECK-NEXT:     i8 2, label %[[BACKEDGE]] | 
|  | ; CHECK-NEXT:     i8 3, label %[[LOOPEXIT_A]] | 
|  | ; CHECK-NEXT:     i8 4, label %[[BACKEDGE]] | 
|  | ; CHECK-NEXT:     i8 5, label %[[LOOPEXIT_A]] | 
|  | ; CHECK-NEXT:     i8 6, label %[[BACKEDGE]] | 
|  | ; CHECK-NEXT:   ] | 
|  | ; | 
|  | ; CHECK:      [[BACKEDGE]]: | 
|  | ; CHECK-NEXT:   br label %loop | 
|  |  | 
|  | exit.a: | 
|  | ret void | 
|  | ; CHECK:      [[LOOPEXIT_A]]: | 
|  | ; CHECK-NEXT:   br label %exit.a | 
|  | ; | 
|  | ; CHECK:      exit.a: | 
|  | ; CHECK-NEXT:   ret void | 
|  |  | 
|  | exit.b: | 
|  | ret void | 
|  | ; CHECK:      [[LOOPEXIT_B]]: | 
|  | ; CHECK-NEXT:   br label %exit.b | 
|  | ; | 
|  | ; CHECK:      exit.b: | 
|  | ; CHECK-NEXT:   ret void | 
|  | } | 
|  |  | 
|  | ; Check that we leave already dedicated exits alone when forming dedicated exit | 
|  | ; blocks. | 
|  | define void @test_pre_existing_dedicated_exits(i1 %a, i1* %ptr) { | 
|  | ; CHECK-LABEL: define void @test_pre_existing_dedicated_exits( | 
|  | entry: | 
|  | br i1 %a, label %loop.ph, label %non_dedicated_exit | 
|  | ; CHECK:      entry: | 
|  | ; CHECK-NEXT:   br i1 %a, label %loop.ph, label %non_dedicated_exit | 
|  |  | 
|  | loop.ph: | 
|  | br label %loop.header | 
|  | ; CHECK:      loop.ph: | 
|  | ; CHECK-NEXT:   br label %loop.header | 
|  |  | 
|  | loop.header: | 
|  | %c1 = load volatile i1, i1* %ptr | 
|  | br i1 %c1, label %loop.body1, label %dedicated_exit1 | 
|  | ; CHECK:      loop.header: | 
|  | ; CHECK-NEXT:   %[[C1:.*]] = load volatile i1, i1* %ptr | 
|  | ; CHECK-NEXT:   br i1 %[[C1]], label %loop.body1, label %dedicated_exit1 | 
|  |  | 
|  | loop.body1: | 
|  | %c2 = load volatile i1, i1* %ptr | 
|  | br i1 %c2, label %loop.body2, label %non_dedicated_exit | 
|  | ; CHECK:      loop.body1: | 
|  | ; CHECK-NEXT:   %[[C2:.*]] = load volatile i1, i1* %ptr | 
|  | ; CHECK-NEXT:   br i1 %[[C2]], label %loop.body2, label %[[LOOPEXIT:.*]] | 
|  |  | 
|  | loop.body2: | 
|  | %c3 = load volatile i1, i1* %ptr | 
|  | br i1 %c3, label %loop.backedge, label %dedicated_exit2 | 
|  | ; CHECK:      loop.body2: | 
|  | ; CHECK-NEXT:   %[[C3:.*]] = load volatile i1, i1* %ptr | 
|  | ; CHECK-NEXT:   br i1 %[[C3]], label %loop.backedge, label %dedicated_exit2 | 
|  |  | 
|  | loop.backedge: | 
|  | br label %loop.header | 
|  | ; CHECK:      loop.backedge: | 
|  | ; CHECK-NEXT:   br label %loop.header | 
|  |  | 
|  | dedicated_exit1: | 
|  | ret void | 
|  | ; Check that there isn't a split loop exit. | 
|  | ; CHECK-NOT:    br label %dedicated_exit1 | 
|  | ; | 
|  | ; CHECK:      dedicated_exit1: | 
|  | ; CHECK-NEXT:   ret void | 
|  |  | 
|  | dedicated_exit2: | 
|  | ret void | 
|  | ; Check that there isn't a split loop exit. | 
|  | ; CHECK-NOT:    br label %dedicated_exit2 | 
|  | ; | 
|  | ; CHECK:      dedicated_exit2: | 
|  | ; CHECK-NEXT:   ret void | 
|  |  | 
|  | non_dedicated_exit: | 
|  | ret void | 
|  | ; CHECK:      [[LOOPEXIT]]: | 
|  | ; CHECK-NEXT:   br label %non_dedicated_exit | 
|  | ; | 
|  | ; CHECK:      non_dedicated_exit: | 
|  | ; CHECK-NEXT:   ret void | 
|  | } | 
|  |  | 
|  | ; Check that we form what dedicated exits we can even when some exits are | 
|  | ; reached via indirectbr which precludes forming dedicated exits. | 
|  | define void @test_form_some_dedicated_exits_despite_indirectbr(i8 %a, i8* %ptr, i8** %addr.ptr) { | 
|  | ; CHECK-LABEL: define void @test_form_some_dedicated_exits_despite_indirectbr( | 
|  | entry: | 
|  | switch i8 %a, label %loop.ph [ | 
|  | i8 0, label %exit.a | 
|  | i8 1, label %exit.b | 
|  | i8 2, label %exit.c | 
|  | ] | 
|  | ; CHECK:      entry: | 
|  | ; CHECK-NEXT:   switch i8 %a, label %loop.ph [ | 
|  | ; CHECK-NEXT:     i8 0, label %exit.a | 
|  | ; CHECK-NEXT:     i8 1, label %exit.b | 
|  | ; CHECK-NEXT:     i8 2, label %exit.c | 
|  | ; CHECK-NEXT:   ] | 
|  |  | 
|  | loop.ph: | 
|  | br label %loop.header | 
|  | ; CHECK:      loop.ph: | 
|  | ; CHECK-NEXT:   br label %loop.header | 
|  |  | 
|  | loop.header: | 
|  | %addr1 = load volatile i8*, i8** %addr.ptr | 
|  | indirectbr i8* %addr1, [label %loop.body1, label %exit.a] | 
|  | ; CHECK:      loop.header: | 
|  | ; CHECK-NEXT:   %[[ADDR1:.*]] = load volatile i8*, i8** %addr.ptr | 
|  | ; CHECK-NEXT:   indirectbr i8* %[[ADDR1]], [label %loop.body1, label %exit.a] | 
|  |  | 
|  | loop.body1: | 
|  | %b = load volatile i8, i8* %ptr | 
|  | switch i8 %b, label %loop.body2 [ | 
|  | i8 0, label %exit.a | 
|  | i8 1, label %exit.b | 
|  | i8 2, label %exit.c | 
|  | ] | 
|  | ; CHECK:      loop.body1: | 
|  | ; CHECK-NEXT:   %[[B:.*]] = load volatile i8, i8* %ptr | 
|  | ; CHECK-NEXT:   switch i8 %[[B]], label %loop.body2 [ | 
|  | ; CHECK-NEXT:     i8 0, label %exit.a | 
|  | ; CHECK-NEXT:     i8 1, label %[[LOOPEXIT:.*]] | 
|  | ; CHECK-NEXT:     i8 2, label %exit.c | 
|  | ; CHECK-NEXT:   ] | 
|  |  | 
|  | loop.body2: | 
|  | %addr2 = load volatile i8*, i8** %addr.ptr | 
|  | indirectbr i8* %addr2, [label %loop.backedge, label %exit.c] | 
|  | ; CHECK:      loop.body2: | 
|  | ; CHECK-NEXT:   %[[ADDR2:.*]] = load volatile i8*, i8** %addr.ptr | 
|  | ; CHECK-NEXT:   indirectbr i8* %[[ADDR2]], [label %loop.backedge, label %exit.c] | 
|  |  | 
|  | loop.backedge: | 
|  | br label %loop.header | 
|  | ; CHECK:      loop.backedge: | 
|  | ; CHECK-NEXT:   br label %loop.header | 
|  |  | 
|  | exit.a: | 
|  | ret void | 
|  | ; Check that there isn't a split loop exit. | 
|  | ; CHECK-NOT:    br label %exit.a | 
|  | ; | 
|  | ; CHECK:      exit.a: | 
|  | ; CHECK-NEXT:   ret void | 
|  |  | 
|  | exit.b: | 
|  | ret void | 
|  | ; CHECK:      [[LOOPEXIT]]: | 
|  | ; CHECK-NEXT:   br label %exit.b | 
|  | ; | 
|  | ; CHECK:      exit.b: | 
|  | ; CHECK-NEXT:   ret void | 
|  |  | 
|  | exit.c: | 
|  | ret void | 
|  | ; Check that there isn't a split loop exit. | 
|  | ; CHECK-NOT:    br label %exit.c | 
|  | ; | 
|  | ; CHECK:      exit.c: | 
|  | ; CHECK-NEXT:   ret void | 
|  | } |