Home | History | Annotate | Download | only in x86
      1 ; Tests various aspects of x86 branch encodings (near vs far,
      2 ; forward vs backward, using CFG labels, or local labels).
      3 
      4 ; Use -ffunction-sections so that the offsets reset for each function.
      5 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 \
      6 ; RUN:   -ffunction-sections | FileCheck %s
      7 
      8 ; Use atomic ops as filler, which shouldn't get optimized out.
      9 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32)
     10 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32)
     11 declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32)
     12 
     13 define internal void @test_near_backward(i32 %iptr, i32 %val) {
     14 entry:
     15   br label %next
     16 next:
     17   %ptr = inttoptr i32 %iptr to i32*
     18   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     19   br label %next2
     20 next2:
     21   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     22   %cmp = icmp ult i32 %val, 1
     23   br i1 %cmp, label %next2, label %next
     24 }
     25 
     26 ; CHECK-LABEL: test_near_backward
     27 ; CHECK:      8: {{.*}}  mov DWORD PTR
     28 ; CHECK-NEXT: a: {{.*}}  mfence
     29 ; CHECK-NEXT: d: {{.*}}  mov DWORD PTR
     30 ; CHECK-NEXT: f: {{.*}}  mfence
     31 ; CHECK-NEXT: 12: {{.*}} cmp
     32 ; CHECK-NEXT: 15: 72 f6 jb d
     33 ; CHECK-NEXT: 17: eb ef jmp 8
     34 
     35 ; Test one of the backward branches being too large for 8 bits
     36 ; and one being just okay.
     37 define internal void @test_far_backward1(i32 %iptr, i32 %val) {
     38 entry:
     39   br label %next
     40 next:
     41   %ptr = inttoptr i32 %iptr to i32*
     42   %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
     43   br label %next2
     44 next2:
     45   call void @llvm.nacl.atomic.store.i32(i32 %tmp, i32* %ptr, i32 6)
     46   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     47   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     48   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     49   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     50   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     51   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     52   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     53   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     54   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     55   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     56   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     57   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     58   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     59   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     60   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     61   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     62   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     63   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     64   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     65   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     66   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     67   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     68   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
     69   %cmp = icmp ugt i32 %val, 0
     70   br i1 %cmp, label %next2, label %next
     71 }
     72 
     73 ; CHECK-LABEL: test_far_backward1
     74 ; CHECK:      8: {{.*}}  mov {{.*}},DWORD PTR [e{{[^s]}}
     75 ; CHECK-NEXT: a: {{.*}}  mov DWORD PTR
     76 ; CHECK-NEXT: c: {{.*}}  mfence
     77 ; CHECK: 85: 77 83 ja a
     78 ; CHECK-NEXT: 87: e9 7c ff ff ff jmp 8
     79 
     80 ; Same as test_far_backward1, but with the conditional branch being
     81 ; the one that is too far.
     82 define internal void @test_far_backward2(i32 %iptr, i32 %val) {
     83 entry:
     84   br label %next
     85 next:
     86   %ptr = inttoptr i32 %iptr to i32*
     87   %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
     88   %tmp2 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
     89   %tmp3 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
     90   %tmp4 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
     91   %tmp5 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
     92   br label %next2
     93 next2:
     94   call void @llvm.nacl.atomic.store.i32(i32 %tmp, i32* %ptr, i32 6)
     95   call void @llvm.nacl.atomic.store.i32(i32 %tmp2, i32* %ptr, i32 6)
     96   call void @llvm.nacl.atomic.store.i32(i32 %tmp3, i32* %ptr, i32 6)
     97   call void @llvm.nacl.atomic.store.i32(i32 %tmp4, i32* %ptr, i32 6)
     98   call void @llvm.nacl.atomic.store.i32(i32 %tmp5, i32* %ptr, i32 6)
     99   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    100   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    101   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    102   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    103   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    104   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    105   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    106   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    107   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    108   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    109   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    110   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    111   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    112   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    113   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    114   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    115   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    116   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    117   %cmp = icmp sle i32 %val, 0
    118   br i1 %cmp, label %next, label %next2
    119 }
    120 
    121 ; CHECK-LABEL: test_far_backward2
    122 ; CHECK:      c:  {{.*}}  mov {{.*}},DWORD PTR [e{{[^s]}}
    123 ; CHECK:      14: {{.*}}  mov {{.*}},DWORD PTR
    124 ; CHECK-NEXT: 16: {{.*}}  mov DWORD PTR
    125 ; CHECK-NEXT: 18: {{.*}}  mfence
    126 ; CHECK: 8c: 0f 8e 7a ff ff ff jle c
    127 ; CHECK-NEXT: 92: eb 82 jmp 16
    128 
    129 define internal void @test_near_forward(i32 %iptr, i32 %val) {
    130 entry:
    131   br label %next1
    132 next1:
    133   %ptr = inttoptr i32 %iptr to i32*
    134   %cmp = icmp ult i32 %val, 1
    135   br i1 %cmp, label %next3, label %next2
    136 next2:
    137   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    138   br label %next3
    139 next3:
    140   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    141   br label %next1
    142 }
    143 ; Note: forward branches for non-local labels in Subzero currently use the fully
    144 ; relaxed form (4-byte offset) to avoid needing a relaxation pass.  When we use
    145 ; llvm-mc, it performs the relaxation pass and uses a 1-byte offset.
    146 ; CHECK-LABEL: test_near_forward
    147 ; CHECK:      [[BACKLABEL:[0-9a-f]+]]: {{.*}} cmp
    148 ; CHECK-NEXT: {{.*}} jb [[FORWARDLABEL:[0-9a-f]+]]
    149 ; CHECK-NEXT: {{.*}} mov DWORD PTR
    150 ; CHECK-NEXT: {{.*}} mfence
    151 ; CHECK-NEXT: [[FORWARDLABEL]]: {{.*}} mov DWORD PTR
    152 ; CHECK:      {{.*}} jmp [[BACKLABEL]]
    153 
    154 
    155 ; Unlike forward branches to cfg nodes, "local" forward branches
    156 ; always use a 1 byte displacement.
    157 ; Check local forward branches, followed by a near backward branch
    158 ; to make sure that the instruction size accounting for the forward
    159 ; branches are correct, by the time the backward branch is hit.
    160 ; A 64-bit compare happens to use local forward branches.
    161 define internal void @test_local_forward_then_back(i64 %val64, i32 %iptr,
    162                                                    i32 %val) {
    163 entry:
    164   br label %next
    165 next:
    166   %ptr = inttoptr i32 %iptr to i32*
    167   call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
    168   br label %next2
    169 next2:
    170   %cmp = icmp ult i64 %val64, 1
    171   br i1 %cmp, label %next, label %next2
    172 }
    173 ; CHECK-LABEL: test_local_forward_then_back
    174 ; CHECK:      {{.*}} mov DWORD PTR
    175 ; CHECK-NEXT: {{.*}} mfence
    176 ; CHECK-NEXT: [[LABEL:[0-9a-f]+]]: {{.*}} cmp
    177 ; CHECK-NEXT: {{.*}} jb
    178 ; CHECK-NEXT: {{.*}} ja
    179 ; CHECK-NEXT: {{.*}} cmp
    180 ; CHECK-NEXT: {{.*}} jb
    181 ; CHECK-NEXT: {{.*}} jmp [[LABEL]]
    182 
    183 
    184 ; Test that backward local branches also work and are small.
    185 ; Some of the atomic instructions use a cmpxchg loop.
    186 define internal void @test_local_backward(i64 %val64, i32 %iptr, i32 %val) {
    187 entry:
    188   br label %next
    189 next:
    190   %ptr = inttoptr i32 %iptr to i32*
    191   %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %val, i32 6)
    192   br label %next2
    193 next2:
    194   %success = icmp eq i32 1, %a
    195   br i1 %success, label %next, label %next2
    196 }
    197 ; CHECK-LABEL: test_local_backward
    198 ; CHECK:       9: {{.*}} mov {{.*}},DWORD
    199 ; CHECK:       b: {{.*}} mov
    200 ; CHECK-NEXT:  d: {{.*}} xor
    201 ; CHECK-NEXT:  f: {{.*}} lock cmpxchg
    202 ; CHECK-NEXT: 13: 75 f6 jne b
    203 ; CHECK:      1c: 74 eb je 9
    204