Home | History | Annotate | Download | only in JumpThreading
      1 ; RUN: opt -S -jump-threading < %s | FileCheck %s
      2 
      3 declare void @foo()
      4 declare void @bar()
      5 declare void @baz()
      6 declare void @quux()
      7 
      8 
      9 ; Jump threading of branch with select as condition.
     10 ; Mostly theoretical since instruction combining simplifies all selects of
     11 ; booleans where at least one operand is true/false/undef.
     12 
     13 ; CHECK-LABEL: @test_br(
     14 ; CHECK-NEXT: entry:
     15 ; CHECK-NEXT: br i1 %cond, label %L1,
     16 define void @test_br(i1 %cond, i1 %value) nounwind {
     17 entry:
     18   br i1 %cond, label %L0, label %L3
     19 L0:
     20   %expr = select i1 %cond, i1 true, i1 %value
     21   br i1 %expr, label %L1, label %L2
     22 
     23 L1:
     24   call void @foo()
     25   ret void
     26 L2:
     27   call void @bar()
     28   ret void
     29 L3:
     30   call void @baz()
     31   br label %L0
     32 }
     33 
     34 
     35 ; Jump threading of switch with select as condition.
     36 
     37 ; CHECK-LABEL: @test_switch(
     38 ; CHECK-NEXT: entry:
     39 ; CHECK-NEXT: br i1 %cond, label %L1,
     40 define void @test_switch(i1 %cond, i8 %value) nounwind {
     41 entry:
     42   br i1 %cond, label %L0, label %L4
     43 L0:
     44   %expr = select i1 %cond, i8 1, i8 %value
     45   switch i8 %expr, label %L3 [i8 1, label %L1 i8 2, label %L2]
     46 
     47 L1:
     48   call void @foo()
     49   ret void
     50 L2:
     51   call void @bar()
     52   ret void
     53 L3:
     54   call void @baz()
     55   ret void
     56 L4:
     57   call void @quux()
     58   br label %L0
     59 }
     60 
     61 ; Make sure the blocks in the indirectbr test aren't trivially removable as
     62 ; successors by taking their addresses.
     63 @anchor = constant [3 x i8*] [
     64   i8* blockaddress(@test_indirectbr, %L1),
     65   i8* blockaddress(@test_indirectbr, %L2),
     66   i8* blockaddress(@test_indirectbr, %L3)
     67 ]
     68 
     69 
     70 ; Jump threading of indirectbr with select as address.
     71 
     72 ; CHECK-LABEL: @test_indirectbr(
     73 ; CHECK-NEXT: entry:
     74 ; CHECK-NEXT: br i1 %cond, label %L1, label %L3
     75 define void @test_indirectbr(i1 %cond, i8* %address) nounwind {
     76 entry:
     77   br i1 %cond, label %L0, label %L3
     78 L0:
     79   %indirect.goto.dest = select i1 %cond, i8* blockaddress(@test_indirectbr, %L1), i8* %address
     80   indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3]
     81 
     82 L1:
     83   call void @foo()
     84   ret void
     85 L2:
     86   call void @bar()
     87   ret void
     88 L3:
     89   call void @baz()
     90   ret void
     91 }
     92 
     93 
     94 ; Jump threading of indirectbr with select as address.  Test increased
     95 ; duplication threshold for cases where indirectbr is being threaded
     96 ; through.
     97 
     98 ; CHECK-LABEL: @test_indirectbr_thresh(
     99 ; CHECK-NEXT: entry:
    100 ; CHECK-NEXT: br i1 %cond, label %L1, label %L3
    101 ; CHECK-NOT: indirectbr
    102 define void @test_indirectbr_thresh(i1 %cond, i8* %address) nounwind {
    103 entry:
    104   br i1 %cond, label %L0, label %L3
    105 L0:
    106   %indirect.goto.dest = select i1 %cond, i8* blockaddress(@test_indirectbr_thresh, %L1), i8* %address
    107   call void @quux()
    108   call void @quux()
    109   call void @quux()
    110   indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3]
    111 
    112 L1:
    113   call void @foo()
    114   ret void
    115 L2:
    116   call void @bar()
    117   ret void
    118 L3:
    119   call void @baz()
    120   ret void
    121 }
    122 
    123 
    124 ; A more complicated case: the condition is a select based on a comparison.
    125 
    126 ; CHECK-LABEL: @test_switch_cmp(
    127 ; CHECK-NEXT: entry:
    128 ; CHECK-NEXT: br i1 %cond, label %L0, label %[[THREADED:[A-Za-z.0-9]+]]
    129 ; CHECK: [[THREADED]]:
    130 ; CHECK-NEXT: call void @quux
    131 ; CHECK-NEXT: br label %L1
    132 define void @test_switch_cmp(i1 %cond, i32 %val, i8 %value) nounwind {
    133 entry:
    134   br i1 %cond, label %L0, label %L4
    135 L0:
    136   %val.phi = phi i32 [%val, %entry], [-1, %L4]
    137   %cmp = icmp slt i32 %val.phi, 0
    138   %expr = select i1 %cmp, i8 1, i8 %value
    139   switch i8 %expr, label %L3 [i8 1, label %L1 i8 2, label %L2]
    140 
    141 L1:
    142   call void @foo()
    143   ret void
    144 L2:
    145   call void @bar()
    146   ret void
    147 L3:
    148   call void @baz()
    149   ret void
    150 L4:
    151   call void @quux()
    152   br label %L0
    153 }
    154 
    155 ; Make sure the edge value of %0 from entry to L2 includes 0 and L3 is
    156 ; reachable.
    157 ; CHECK: test_switch_default
    158 ; CHECK: entry:
    159 ; CHECK: load
    160 ; CHECK: switch
    161 ; CHECK: [[THREADED:[A-Za-z.0-9]+]]:
    162 ; CHECK: store
    163 ; CHECK: br
    164 ; CHECK: L2:
    165 ; CHECK-SAME: preds = %entry, %entry
    166 ; CHECK-NEXT: phi i32
    167 define void @test_switch_default(i32* nocapture %status) nounwind {
    168 entry:
    169   %0 = load i32, i32* %status, align 4
    170   switch i32 %0, label %L2 [
    171     i32 5061, label %L1
    172     i32 0, label %L2
    173   ]
    174 
    175 L1:
    176   store i32 10025, i32* %status, align 4
    177   br label %L2
    178 
    179 L2:
    180   %1 = load i32, i32* %status, align 4
    181   %cmp57.i = icmp eq i32 %1, 0
    182   br i1 %cmp57.i, label %L3, label %L4
    183 
    184 L3:
    185   store i32 10000, i32* %status, align 4
    186   br label %L4
    187 
    188 L4:
    189   ret void
    190 }
    191 
    192 define void @unfold1(double %x, double %y) nounwind {
    193 entry:
    194   %sub = fsub double %x, %y
    195   %cmp = fcmp ogt double %sub, 1.000000e+01
    196   br i1 %cmp, label %cond.end4, label %cond.false
    197 
    198 cond.false:                                       ; preds = %entry
    199   %add = fadd double %x, %y
    200   %cmp1 = fcmp ogt double %add, 1.000000e+01
    201   %add. = select i1 %cmp1, double %add, double 0.000000e+00
    202   br label %cond.end4
    203 
    204 cond.end4:                                        ; preds = %entry, %cond.false
    205   %cond5 = phi double [ %add., %cond.false ], [ %sub, %entry ]
    206   %cmp6 = fcmp oeq double %cond5, 0.000000e+00
    207   br i1 %cmp6, label %if.then, label %if.end
    208 
    209 if.then:                                          ; preds = %cond.end4
    210   call void @foo()
    211   br label %if.end
    212 
    213 if.end:                                           ; preds = %if.then, %cond.end4
    214   ret void
    215 
    216 ; CHECK-LABEL: @unfold1
    217 ; CHECK: br i1 %cmp, label %cond.end4, label %cond.false
    218 ; CHECK: br i1 %cmp1, label %cond.end4, label %if.then
    219 ; CHECK: br i1 %cmp6, label %if.then, label %if.end
    220 ; CHECK: br label %if.end
    221 }
    222 
    223 
    224 define void @unfold2(i32 %x, i32 %y) nounwind {
    225 entry:
    226   %sub = sub nsw i32 %x, %y
    227   %cmp = icmp sgt i32 %sub, 10
    228   br i1 %cmp, label %cond.end4, label %cond.false
    229 
    230 cond.false:                                       ; preds = %entry
    231   %add = add nsw i32 %x, %y
    232   %cmp1 = icmp sgt i32 %add, 10
    233   %add. = select i1 %cmp1, i32 0, i32 %add
    234   br label %cond.end4
    235 
    236 cond.end4:                                        ; preds = %entry, %cond.false
    237   %cond5 = phi i32 [ %add., %cond.false ], [ %sub, %entry ]
    238   %cmp6 = icmp eq i32 %cond5, 0
    239   br i1 %cmp6, label %if.then, label %if.end
    240 
    241 if.then:                                          ; preds = %cond.end4
    242   call void @foo()
    243   br label %if.end
    244 
    245 if.end:                                           ; preds = %if.then, %cond.end4
    246   ret void
    247 
    248 ; CHECK-LABEL: @unfold2
    249 ; CHECK: br i1 %cmp, label %if.end, label %cond.false
    250 ; CHECK: br i1 %cmp1, label %if.then, label %cond.end4
    251 ; CHECK: br i1 %cmp6, label %if.then, label %if.end
    252 ; CHECK: br label %if.end
    253 }
    254 
    255 
    256 define i32 @unfold3(i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z, i32 %j) nounwind {
    257 entry:
    258   %add3 = add nsw i32 %j, 2
    259   %cmp.i = icmp slt i32 %u, %v
    260   br i1 %cmp.i, label %.exit, label %cond.false.i
    261 
    262 cond.false.i:                                     ; preds = %entry
    263   %cmp4.i = icmp sgt i32 %u, %v
    264   br i1 %cmp4.i, label %.exit, label %cond.false.6.i
    265 
    266 cond.false.6.i:                                   ; preds = %cond.false.i
    267   %cmp8.i = icmp slt i32 %w, %x
    268   br i1 %cmp8.i, label %.exit, label %cond.false.10.i
    269 
    270 cond.false.10.i:                                  ; preds = %cond.false.6.i
    271   %cmp13.i = icmp sgt i32 %w, %x
    272   br i1 %cmp13.i, label %.exit, label %cond.false.15.i
    273 
    274 cond.false.15.i:                                  ; preds = %cond.false.10.i
    275   %phitmp = icmp sge i32 %y, %z
    276   br label %.exit
    277 
    278 .exit:                                  ; preds = %entry, %cond.false.i, %cond.false.6.i, %cond.false.10.i, %cond.false.15.i
    279   %cond23.i = phi i1 [ false, %entry ], [ true, %cond.false.i ], [ false, %cond.false.6.i ], [ %phitmp, %cond.false.15.i ], [ true, %cond.false.10.i ]
    280   %j.add3 = select i1 %cond23.i, i32 %j, i32 %add3
    281   ret i32 %j.add3
    282 
    283 ; CHECK-LABEL: @unfold3
    284 ; CHECK: br i1 %cmp.i, label %.exit.thread2, label %cond.false.i
    285 ; CHECK: br i1 %cmp4.i, label %.exit.thread, label %cond.false.6.i
    286 ; CHECK: br i1 %cmp8.i, label %.exit.thread2, label %cond.false.10.i
    287 ; CHECK: br i1 %cmp13.i, label %.exit.thread, label %.exit
    288 ; CHECK: br i1 %phitmp, label %.exit.thread, label %.exit.thread2
    289 ; CHECK: br label %.exit.thread2
    290 }
    291 
    292 define i32 @unfold4(i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z, i32 %j) nounwind {
    293 entry:
    294   %add3 = add nsw i32 %j, 2
    295   %cmp.i = icmp slt i32 %u, %v
    296   br i1 %cmp.i, label %.exit, label %cond.false.i
    297 
    298 cond.false.i:                                     ; preds = %entry
    299   %cmp4.i = icmp sgt i32 %u, %v
    300   br i1 %cmp4.i, label %.exit, label %cond.false.6.i
    301 
    302 cond.false.6.i:                                   ; preds = %cond.false.i
    303   %cmp8.i = icmp slt i32 %w, %x
    304   br i1 %cmp8.i, label %.exit, label %cond.false.10.i
    305 
    306 cond.false.10.i:                                  ; preds = %cond.false.6.i
    307   %cmp13.i = icmp sgt i32 %w, %x
    308   br i1 %cmp13.i, label %.exit, label %cond.false.15.i
    309 
    310 cond.false.15.i:                                  ; preds = %cond.false.10.i
    311   %cmp19.i = icmp sge i32 %y, %z
    312   %conv = zext i1 %cmp19.i to i32
    313   br label %.exit
    314 
    315 .exit:                                  ; preds = %entry, %cond.false.i, %cond.false.6.i, %cond.false.10.i, %cond.false.15.i
    316   %cond23.i = phi i32 [ 1, %entry ], [ 0, %cond.false.i ], [ 1, %cond.false.6.i ], [ %conv, %cond.false.15.i ], [ 0, %cond.false.10.i ]
    317   %lnot.i18 = icmp eq i32 %cond23.i, 1
    318   %j.add3 = select i1 %lnot.i18, i32 %j, i32 %add3
    319   ret i32 %j.add3
    320 
    321 ; CHECK-LABEL: @unfold4
    322 ; CHECK: br i1 %cmp.i, label %.exit.thread, label %cond.false.i
    323 ; CHECK: br i1 %cmp4.i, label %.exit.thread3, label %cond.false.6.i
    324 ; CHECK: br i1 %cmp8.i, label %.exit.thread, label %cond.false.10.i
    325 ; CHECK: br i1 %cmp13.i, label %.exit.thread3, label %.exit
    326 ; CHECK: br i1 %lnot.i18, label %.exit.thread, label %.exit.thread3
    327 ; CHECK: br label %.exit.thread3
    328 }
    329 
    330 define i32 @unfold5(i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z, i32 %j) nounwind {
    331 entry:
    332   %add3 = add nsw i32 %j, 2
    333   %cmp.i = icmp slt i32 %u, %v
    334   br i1 %cmp.i, label %.exit, label %cond.false.i
    335 
    336 cond.false.i:                                     ; preds = %entry
    337   %cmp4.i = icmp sgt i32 %u, %v
    338   br i1 %cmp4.i, label %.exit, label %cond.false.6.i
    339 
    340 cond.false.6.i:                                   ; preds = %cond.false.i
    341   %cmp8.i = icmp slt i32 %w, %x
    342   br i1 %cmp8.i, label %.exit, label %cond.false.10.i
    343 
    344 cond.false.10.i:                                  ; preds = %cond.false.6.i
    345   %cmp13.i = icmp sgt i32 %w, %x
    346   br i1 %cmp13.i, label %.exit, label %cond.false.15.i
    347 
    348 cond.false.15.i:                                  ; preds = %cond.false.10.i
    349   %cmp19.i = icmp sge i32 %y, %z
    350   %conv = zext i1 %cmp19.i to i32
    351   br label %.exit
    352 
    353 .exit:                                  ; preds = %entry, %cond.false.i, %cond.false.6.i, %cond.false.10.i, %cond.false.15.i
    354   %cond23.i = phi i32 [ 2, %entry ], [ 3, %cond.false.i ], [ 1, %cond.false.6.i ], [ %conv, %cond.false.15.i ], [ 7, %cond.false.10.i ]
    355   %lnot.i18 = icmp sgt i32 %cond23.i, 5
    356   %j.add3 = select i1 %lnot.i18, i32 %j, i32 %cond23.i
    357   ret i32 %j.add3
    358 
    359 ; CHECK-LABEL: @unfold5
    360 ; CHECK: br i1 %cmp.i, label %.exit, label %cond.false.i
    361 ; CHECK: br i1 %cmp4.i, label %.exit, label %cond.false.6.i
    362 ; CHECK: br i1 %cmp8.i, label %.exit, label %cond.false.10.i
    363 ; CHECK: br i1 %cmp13.i, label %.exit, label %cond.false.15.i
    364 ; CHECK: br label %.exit
    365 }
    366