mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-18 10:31:57 +00:00
7ac40c3ffa
(indirectbr (select cond, blockaddress(@fn, BlockA), blockaddress(@fn, BlockB))) into (br cond, BlockA, BlockB). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120943 91177308-0d34-0410-b5e6-96231b3b80d8
183 lines
5.0 KiB
LLVM
183 lines
5.0 KiB
LLVM
; 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]
|
|
}
|