Home | History | Annotate | Download | only in SimplifyCFG
      1 ; RUN: opt -S -simplifycfg < %s | FileCheck %s
      2 
      3 ; SimplifyCFG should eliminate redundant indirectbr edges.
      4 
      5 ; CHECK: indbrtest0
      6 ; CHECK: indirectbr i8* %t, [label %BB0, label %BB1, label %BB2]
      7 ; CHECK: %x = phi i32 [ 0, %BB0 ], [ 1, %entry ]
      8 
      9 declare void @foo()
     10 declare void @A()
     11 declare void @B(i32)
     12 declare void @C()
     13 
     14 define void @indbrtest0(i8** %P, i8** %Q) {
     15 entry:
     16   store i8* blockaddress(@indbrtest0, %BB0), i8** %P
     17   store i8* blockaddress(@indbrtest0, %BB1), i8** %P
     18   store i8* blockaddress(@indbrtest0, %BB2), i8** %P
     19   call void @foo()
     20   %t = load i8** %Q
     21   indirectbr i8* %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2]
     22 BB0:
     23   call void @A()
     24   br label %BB1
     25 BB1:
     26   %x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ]
     27   call void @B(i32 %x)
     28   ret void
     29 BB2:
     30   call void @C()
     31   ret void
     32 }
     33 
     34 ; SimplifyCFG should convert the indirectbr into a directbr. It would be even
     35 ; better if it removed the branch altogether, but simplifycfdg currently misses
     36 ; that because the predecessor is the entry block.
     37 
     38 ; CHECK: indbrtest1
     39 ; CHECK: br label %BB0
     40 
     41 define void @indbrtest1(i8** %P, i8** %Q) {
     42 entry:
     43   store i8* blockaddress(@indbrtest1, %BB0), i8** %P
     44   call void @foo()
     45   %t = load i8** %Q
     46   indirectbr i8* %t, [label %BB0, label %BB0]
     47 BB0:
     48   call void @A()
     49   ret void
     50 }
     51 
     52 ; SimplifyCFG should notice that BB0 does not have its address taken and
     53 ; remove it from entry's successor list.
     54 
     55 ; CHECK: indbrtest2
     56 ; CHECK: entry:
     57 ; CHECK-NEXT: unreachable
     58 
     59 define void @indbrtest2(i8* %t) {
     60 entry:
     61   indirectbr i8* %t, [label %BB0, label %BB0]
     62 BB0:
     63   ret void
     64 }
     65 
     66 
     67 ; Make sure the blocks in the next few tests aren't trivially removable as
     68 ; successors by taking their addresses.
     69 
     70 @anchor = constant [13 x i8*] [
     71   i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2), i8* blockaddress(@indbrtest3, %L3),
     72   i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L2), i8* blockaddress(@indbrtest4, %L3),
     73   i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2), i8* blockaddress(@indbrtest5, %L3), i8* blockaddress(@indbrtest5, %L4),
     74   i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L2), i8* blockaddress(@indbrtest6, %L3)
     75 ]
     76 
     77 ; SimplifyCFG should turn the indirectbr into a conditional branch on the
     78 ; condition of the select.
     79 
     80 ; CHECK-LABEL: @indbrtest3(
     81 ; CHECK-NEXT: entry:
     82 ; CHECK-NEXT: br i1 %cond, label %L1, label %L2
     83 ; CHECK-NOT: indirectbr
     84 ; CHECK-NOT: br
     85 ; CHECK-NOT: L3:
     86 define void @indbrtest3(i1 %cond, i8* %address) nounwind {
     87 entry:
     88   %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2)
     89   indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3]
     90 
     91 L1:
     92   call void @A()
     93   ret void
     94 L2:
     95   call void @C()
     96   ret void
     97 L3:
     98   call void @foo()
     99   ret void
    100 }
    101 
    102 ; SimplifyCFG should turn the indirectbr into an unconditional branch to the
    103 ; only possible destination.
    104 ; As in @indbrtest1, it should really remove the branch entirely, but it doesn't
    105 ; because it's in the entry block.
    106 
    107 ; CHECK-LABEL: @indbrtest4(
    108 ; CHECK-NEXT: entry:
    109 ; CHECK-NEXT: br label %L1
    110 define void @indbrtest4(i1 %cond) nounwind {
    111 entry:
    112   %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L1)
    113   indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3]
    114 
    115 L1:
    116   call void @A()
    117   ret void
    118 L2:
    119   call void @C()
    120   ret void
    121 L3:
    122   call void @foo()
    123   ret void
    124 }
    125 
    126 ; SimplifyCFG should turn the indirectbr into an unreachable because neither
    127 ; destination is listed as a successor.
    128 
    129 ; CHECK-LABEL: @indbrtest5(
    130 ; CHECK-NEXT: entry:
    131 ; CHECK-NEXT: unreachable
    132 ; CHECK-NEXT: }
    133 define void @indbrtest5(i1 %cond, i8* %anchor) nounwind {
    134 entry:
    135   %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2)
    136 ; This needs to have more than one successor for this test, otherwise it gets
    137 ; replaced with an unconditional branch to the single successor.
    138   indirectbr i8* %indirect.goto.dest, [label %L3, label %L4]
    139 
    140 L1:
    141   call void @A()
    142   ret void
    143 L2:
    144   call void @C()
    145   ret void
    146 L3:
    147   call void @foo()
    148   ret void
    149 L4:
    150   call void @foo()
    151 
    152 ; This keeps blockaddresses not otherwise listed as successors from being zapped
    153 ; before SimplifyCFG even looks at the indirectbr.
    154   indirectbr i8* %anchor, [label %L1, label %L2]
    155 }
    156 
    157 ; The same as above, except the selected addresses are equal.
    158 
    159 ; CHECK-LABEL: @indbrtest6(
    160 ; CHECK-NEXT: entry:
    161 ; CHECK-NEXT: unreachable
    162 ; CHECK-NEXT: }
    163 define void @indbrtest6(i1 %cond, i8* %anchor) nounwind {
    164 entry:
    165   %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L1)
    166 ; This needs to have more than one successor for this test, otherwise it gets
    167 ; replaced with an unconditional branch to the single successor.
    168   indirectbr i8* %indirect.goto.dest, [label %L2, label %L3]
    169 
    170 L1:
    171   call void @A()
    172   ret void
    173 L2:
    174   call void @C()
    175   ret void
    176 L3:
    177   call void @foo()
    178 
    179 ; This keeps blockaddresses not otherwise listed as successors from being zapped
    180 ; before SimplifyCFG even looks at the indirectbr.
    181   indirectbr i8* %anchor, [label %L1, label %L2]
    182 }
    183 
    184 ; PR10072
    185 
    186 @xblkx.bbs = internal unnamed_addr constant [9 x i8*] [i8* blockaddress(@indbrtest7, %xblkx.begin), i8* blockaddress(@indbrtest7, %xblkx.begin3), i8* blockaddress(@indbrtest7, %xblkx.begin4), i8* blockaddress(@indbrtest7, %xblkx.begin5), i8* blockaddress(@indbrtest7, %xblkx.begin6), i8* blockaddress(@indbrtest7, %xblkx.begin7), i8* blockaddress(@indbrtest7, %xblkx.begin8), i8* blockaddress(@indbrtest7, %xblkx.begin9), i8* blockaddress(@indbrtest7, %xblkx.end)]
    187 
    188 define void @indbrtest7() {
    189 escape-string.top:
    190   %xval202x = call i32 @xfunc5x()
    191   br label %xlab5x
    192 
    193 xlab8x:                                           ; preds = %xlab5x
    194   %xvaluex = call i32 @xselectorx()
    195   %xblkx.x = getelementptr [9 x i8*]* @xblkx.bbs, i32 0, i32 %xvaluex
    196   %xblkx.load = load i8** %xblkx.x
    197   indirectbr i8* %xblkx.load, [label %xblkx.begin, label %xblkx.begin3, label %xblkx.begin4, label %xblkx.begin5, label %xblkx.begin6, label %xblkx.begin7, label %xblkx.begin8, label %xblkx.begin9, label %xblkx.end]
    198 
    199 xblkx.begin:
    200   br label %xblkx.end
    201 
    202 xblkx.begin3:
    203   br label %xblkx.end
    204 
    205 xblkx.begin4:
    206   br label %xblkx.end
    207 
    208 xblkx.begin5:
    209   br label %xblkx.end
    210 
    211 xblkx.begin6:
    212   br label %xblkx.end
    213 
    214 xblkx.begin7:
    215   br label %xblkx.end
    216 
    217 xblkx.begin8:
    218   br label %xblkx.end
    219 
    220 xblkx.begin9:
    221   br label %xblkx.end
    222 
    223 xblkx.end:
    224   %yes.0 = phi i1 [ false, %xblkx.begin ], [ true, %xlab8x ], [ false, %xblkx.begin9 ], [ false, %xblkx.begin8 ], [ false, %xblkx.begin7 ], [ false, %xblkx.begin6 ], [ false, %xblkx.begin5 ], [ true, %xblkx.begin4 ], [ false, %xblkx.begin3 ]
    225   br i1 %yes.0, label %v2j, label %xlab17x
    226 
    227 v2j:
    228 ; CHECK: %xunusedx = call i32 @xactionx()
    229   %xunusedx = call i32 @xactionx()
    230   br label %xlab4x
    231 
    232 xlab17x:
    233   br label %xlab4x
    234 
    235 xlab4x:
    236   %incr19 = add i32 %xval704x.0, 1
    237   br label %xlab5x
    238 
    239 xlab5x:
    240   %xval704x.0 = phi i32 [ 0, %escape-string.top ], [ %incr19, %xlab4x ]
    241   %xval10x = icmp ult i32 %xval704x.0, %xval202x
    242   br i1 %xval10x, label %xlab8x, label %xlab9x
    243 
    244 xlab9x:
    245   ret void
    246 }
    247 
    248 declare i32 @xfunc5x()
    249 declare i8 @xfunc7x()
    250 declare i32 @xselectorx()
    251 declare i32 @xactionx()
    252