; RUN: opt -S -simplifycfg < %s | FileCheck %s ; SimplifyCFG should eliminate redundant indirectbr edges. ; CHECK: indbrtest0 ; CHECK: indirectbr i8* %t, [label %BB0, label %BB1, label %BB2] ; CHECK: %x = phi i32 [ 0, %BB0 ], [ 1, %entry ] declare void @foo() declare void @A() declare void @B(i32) declare void @C() define void @indbrtest0(i8** %P, i8** %Q) { entry: store i8* blockaddress(@indbrtest0, %BB0), i8** %P store i8* blockaddress(@indbrtest0, %BB1), i8** %P store i8* blockaddress(@indbrtest0, %BB2), i8** %P call void @foo() %t = load i8** %Q indirectbr i8* %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2] BB0: call void @A() br label %BB1 BB1: %x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ] call void @B(i32 %x) ret void BB2: call void @C() ret void } ; SimplifyCFG should convert the indirectbr into a directbr. It would be even ; better if it removed the branch altogether, but simplifycfdg currently misses ; that because the predecessor is the entry block. ; CHECK: indbrtest1 ; CHECK: br label %BB0 define void @indbrtest1(i8** %P, i8** %Q) { entry: store i8* blockaddress(@indbrtest1, %BB0), i8** %P call void @foo() %t = load i8** %Q indirectbr i8* %t, [label %BB0, label %BB0] BB0: call void @A() ret void } ; SimplifyCFG should notice that BB0 does not have its address taken and ; remove it from entry's successor list. ; CHECK: indbrtest2 ; CHECK: entry: ; CHECK-NEXT: unreachable define void @indbrtest2(i8* %t) { entry: indirectbr i8* %t, [label %BB0, label %BB0] BB0: ret void } ; Make sure the blocks in the next few tests aren't trivially removable as ; successors by taking their addresses. @anchor = constant [13 x i8*] [ i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2), i8* blockaddress(@indbrtest3, %L3), i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L2), i8* blockaddress(@indbrtest4, %L3), i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2), i8* blockaddress(@indbrtest5, %L3), i8* blockaddress(@indbrtest5, %L4), i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L2), i8* blockaddress(@indbrtest6, %L3) ] ; SimplifyCFG should turn the indirectbr into a conditional branch on the ; condition of the select. ; CHECK: @indbrtest3 ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 %cond, label %L1, label %L2 ; CHECK-NOT: indirectbr ; CHECK-NOT: br ; CHECK-NOT: L3: define void @indbrtest3(i1 %cond, i8* %address) nounwind { entry: %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2) indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3] L1: call void @A() ret void L2: call void @C() ret void L3: call void @foo() ret void } ; SimplifyCFG should turn the indirectbr into an unconditional branch to the ; only possible destination. ; As in @indbrtest1, it should really remove the branch entirely, but it doesn't ; because it's in the entry block. ; CHECK: @indbrtest4 ; CHECK-NEXT: entry: ; CHECK-NEXT: br label %L1 define void @indbrtest4(i1 %cond) nounwind { entry: %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L1) indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3] L1: call void @A() ret void L2: call void @C() ret void L3: call void @foo() ret void } ; SimplifyCFG should turn the indirectbr into an unreachable because neither ; destination is listed as a successor. ; CHECK: @indbrtest5 ; CHECK-NEXT: entry: ; CHECK-NEXT: unreachable ; CHECK-NEXT: } define void @indbrtest5(i1 %cond, i8* %anchor) nounwind { entry: %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2) ; This needs to have more than one successor for this test, otherwise it gets ; replaced with an unconditional branch to the single successor. indirectbr i8* %indirect.goto.dest, [label %L3, label %L4] L1: call void @A() ret void L2: call void @C() ret void L3: call void @foo() ret void L4: call void @foo() ; This keeps blockaddresses not otherwise listed as successors from being zapped ; before SimplifyCFG even looks at the indirectbr. indirectbr i8* %anchor, [label %L1, label %L2] } ; The same as above, except the selected addresses are equal. ; CHECK: @indbrtest6 ; CHECK-NEXT: entry: ; CHECK-NEXT: unreachable ; CHECK-NEXT: } define void @indbrtest6(i1 %cond, i8* %anchor) nounwind { entry: %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L1) ; This needs to have more than one successor for this test, otherwise it gets ; replaced with an unconditional branch to the single successor. indirectbr i8* %indirect.goto.dest, [label %L2, label %L3] L1: call void @A() ret void L2: call void @C() ret void L3: call void @foo() ; This keeps blockaddresses not otherwise listed as successors from being zapped ; before SimplifyCFG even looks at the indirectbr. indirectbr i8* %anchor, [label %L1, label %L2] }