; 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 }