Home | History | Annotate | Download | only in X86
      1 ; RUN: llc < %s -march=x86-64 -mtriple=x86_64-unknown-linux-gnu -asm-verbose=false | FileCheck %s
      2 
      3 ; These tests check for loop branching structure, and that the loop align
      4 ; directive is placed in the expected place.
      5 
      6 ; CodeGen should insert a branch into the middle of the loop in
      7 ; order to avoid a branch within the loop.
      8 
      9 ; CHECK: simple:
     10 ;      CHECK:   jmp   .LBB0_1
     11 ; CHECK-NEXT:   align
     12 ; CHECK-NEXT: .LBB0_2:
     13 ; CHECK-NEXT:   callq loop_latch
     14 ; CHECK-NEXT: .LBB0_1:
     15 ; CHECK-NEXT:   callq loop_header
     16 
     17 define void @simple() nounwind {
     18 entry:
     19   br label %loop
     20 
     21 loop:
     22   call void @loop_header()
     23   %t0 = tail call i32 @get()
     24   %t1 = icmp slt i32 %t0, 0
     25   br i1 %t1, label %done, label %bb
     26 
     27 bb:
     28   call void @loop_latch()
     29   br label %loop
     30 
     31 done:
     32   call void @exit()
     33   ret void
     34 }
     35 
     36 ; CodeGen should move block_a to the top of the loop so that it
     37 ; falls through into the loop, avoiding a branch within the loop.
     38 
     39 ; CHECK: slightly_more_involved:
     40 ;      CHECK:   jmp .LBB1_1
     41 ; CHECK-NEXT:   align
     42 ; CHECK-NEXT: .LBB1_4:
     43 ; CHECK-NEXT:   callq bar99
     44 ; CHECK-NEXT: .LBB1_1:
     45 ; CHECK-NEXT:   callq body
     46 
     47 define void @slightly_more_involved() nounwind {
     48 entry:
     49   br label %loop
     50 
     51 loop:
     52   call void @body()
     53   %t0 = call i32 @get()
     54   %t1 = icmp slt i32 %t0, 2
     55   br i1 %t1, label %block_a, label %bb
     56 
     57 bb:
     58   %t2 = call i32 @get()
     59   %t3 = icmp slt i32 %t2, 99
     60   br i1 %t3, label %exit, label %loop
     61 
     62 block_a:
     63   call void @bar99()
     64   br label %loop
     65 
     66 exit:
     67   call void @exit()
     68   ret void
     69 }
     70 
     71 ; Same as slightly_more_involved, but block_a is now a CFG diamond with
     72 ; fallthrough edges which should be preserved.
     73 ; "callq block_a_merge_func" is tail duped.
     74 
     75 ; CHECK: yet_more_involved:
     76 ;      CHECK:   jmp .LBB2_1
     77 ; CHECK-NEXT:   align
     78 ; CHECK-NEXT: .LBB2_4:
     79 ; CHECK-NEXT:   callq bar99
     80 ; CHECK-NEXT:   callq get
     81 ; CHECK-NEXT:   cmpl $2999, %eax
     82 ; CHECK-NEXT:   jle .LBB2_5
     83 ; CHECK-NEXT:   callq block_a_false_func
     84 ; CHECK-NEXT:   callq block_a_merge_func
     85 ; CHECK-NEXT:   jmp .LBB2_1
     86 ; CHECK-NEXT: .LBB2_5:
     87 ; CHECK-NEXT:   callq block_a_true_func
     88 ; CHECK-NEXT:   callq block_a_merge_func
     89 ; CHECK-NEXT: .LBB2_1:
     90 ; CHECK-NEXT:   callq body
     91 
     92 define void @yet_more_involved() nounwind {
     93 entry:
     94   br label %loop
     95 
     96 loop:
     97   call void @body()
     98   %t0 = call i32 @get()
     99   %t1 = icmp slt i32 %t0, 2
    100   br i1 %t1, label %block_a, label %bb
    101 
    102 bb:
    103   %t2 = call i32 @get()
    104   %t3 = icmp slt i32 %t2, 99
    105   br i1 %t3, label %exit, label %loop
    106 
    107 block_a:
    108   call void @bar99()
    109   %z0 = call i32 @get()
    110   %z1 = icmp slt i32 %z0, 3000
    111   br i1 %z1, label %block_a_true, label %block_a_false
    112 
    113 block_a_true:
    114   call void @block_a_true_func()
    115   br label %block_a_merge
    116 
    117 block_a_false:
    118   call void @block_a_false_func()
    119   br label %block_a_merge
    120 
    121 block_a_merge:
    122   call void @block_a_merge_func()
    123   br label %loop
    124 
    125 exit:
    126   call void @exit()
    127   ret void
    128 }
    129 
    130 ; CodeGen should move the CFG islands that are part of the loop but don't
    131 ; conveniently fit anywhere so that they are at least contiguous with the
    132 ; loop.
    133 
    134 ; CHECK: cfg_islands:
    135 ;      CHECK:   jmp     .LBB3_1
    136 ; CHECK-NEXT:   align
    137 ; CHECK-NEXT: .LBB3_7:
    138 ; CHECK-NEXT:   callq   bar100
    139 ; CHECK-NEXT:   jmp     .LBB3_1
    140 ; CHECK-NEXT: .LBB3_8:
    141 ; CHECK-NEXT:   callq   bar101
    142 ; CHECK-NEXT:   jmp     .LBB3_1
    143 ; CHECK-NEXT: .LBB3_9:
    144 ; CHECK-NEXT:   callq   bar102
    145 ; CHECK-NEXT:   jmp     .LBB3_1
    146 ; CHECK-NEXT: .LBB3_5:
    147 ; CHECK-NEXT:   callq   loop_latch
    148 ; CHECK-NEXT: .LBB3_1:
    149 ; CHECK-NEXT:   callq   loop_header
    150 
    151 define void @cfg_islands() nounwind {
    152 entry:
    153   br label %loop
    154 
    155 loop:
    156   call void @loop_header()
    157   %t0 = call i32 @get()
    158   %t1 = icmp slt i32 %t0, 100
    159   br i1 %t1, label %block100, label %bb
    160 
    161 bb:
    162   %t2 = call i32 @get()
    163   %t3 = icmp slt i32 %t2, 101
    164   br i1 %t3, label %block101, label %bb1
    165 
    166 bb1:
    167   %t4 = call i32 @get()
    168   %t5 = icmp slt i32 %t4, 102
    169   br i1 %t5, label %block102, label %bb2
    170 
    171 bb2:
    172   %t6 = call i32 @get()
    173   %t7 = icmp slt i32 %t6, 103
    174   br i1 %t7, label %exit, label %bb3
    175 
    176 bb3:
    177   call void @loop_latch()
    178   br label %loop
    179 
    180 exit:
    181   call void @exit()
    182   ret void
    183 
    184 block100:
    185   call void @bar100()
    186   br label %loop
    187 
    188 block101:
    189   call void @bar101()
    190   br label %loop
    191 
    192 block102:
    193   call void @bar102()
    194   br label %loop
    195 }
    196 
    197 declare void @bar99() nounwind
    198 declare void @bar100() nounwind
    199 declare void @bar101() nounwind
    200 declare void @bar102() nounwind
    201 declare void @body() nounwind
    202 declare void @exit() nounwind
    203 declare void @loop_header() nounwind
    204 declare void @loop_latch() nounwind
    205 declare i32 @get() nounwind
    206 declare void @block_a_true_func() nounwind
    207 declare void @block_a_false_func() nounwind
    208 declare void @block_a_merge_func() nounwind
    209