Home | History | Annotate | Download | only in SystemZ
      1 ; Test 32-bit conditional stores that are presented as selects.
      2 ;
      3 ; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
      4 
      5 declare void @foo(i32 *)
      6 
      7 ; Test the simple case, with the loaded value first.
      8 define void @f1(i32 *%ptr, i32 %alt, i32 %limit) {
      9 ; CHECK-LABEL: f1:
     10 ; CHECK-NOT: %r2
     11 ; CHECK: jl [[LABEL:[^ ]*]]
     12 ; CHECK-NOT: %r2
     13 ; CHECK: st %r3, 0(%r2)
     14 ; CHECK: [[LABEL]]:
     15 ; CHECK: br %r14
     16   %cond = icmp ult i32 %limit, 420
     17   %orig = load i32 , i32 *%ptr
     18   %res = select i1 %cond, i32 %orig, i32 %alt
     19   store i32 %res, i32 *%ptr
     20   ret void
     21 }
     22 
     23 ; ...and with the loaded value second
     24 define void @f2(i32 *%ptr, i32 %alt, i32 %limit) {
     25 ; CHECK-LABEL: f2:
     26 ; CHECK-NOT: %r2
     27 ; CHECK: jhe [[LABEL:[^ ]*]]
     28 ; CHECK-NOT: %r2
     29 ; CHECK: st %r3, 0(%r2)
     30 ; CHECK: [[LABEL]]:
     31 ; CHECK: br %r14
     32   %cond = icmp ult i32 %limit, 420
     33   %orig = load i32 , i32 *%ptr
     34   %res = select i1 %cond, i32 %alt, i32 %orig
     35   store i32 %res, i32 *%ptr
     36   ret void
     37 }
     38 
     39 ; Test cases where the value is explicitly sign-extended to 64 bits, with the
     40 ; loaded value first.
     41 define void @f3(i32 *%ptr, i64 %alt, i32 %limit) {
     42 ; CHECK-LABEL: f3:
     43 ; CHECK-NOT: %r2
     44 ; CHECK: jl [[LABEL:[^ ]*]]
     45 ; CHECK-NOT: %r2
     46 ; CHECK: st %r3, 0(%r2)
     47 ; CHECK: [[LABEL]]:
     48 ; CHECK: br %r14
     49   %cond = icmp ult i32 %limit, 420
     50   %orig = load i32 , i32 *%ptr
     51   %ext = sext i32 %orig to i64
     52   %res = select i1 %cond, i64 %ext, i64 %alt
     53   %trunc = trunc i64 %res to i32
     54   store i32 %trunc, i32 *%ptr
     55   ret void
     56 }
     57 
     58 ; ...and with the loaded value second
     59 define void @f4(i32 *%ptr, i64 %alt, i32 %limit) {
     60 ; CHECK-LABEL: f4:
     61 ; CHECK-NOT: %r2
     62 ; CHECK: jhe [[LABEL:[^ ]*]]
     63 ; CHECK-NOT: %r2
     64 ; CHECK: st %r3, 0(%r2)
     65 ; CHECK: [[LABEL]]:
     66 ; CHECK: br %r14
     67   %cond = icmp ult i32 %limit, 420
     68   %orig = load i32 , i32 *%ptr
     69   %ext = sext i32 %orig to i64
     70   %res = select i1 %cond, i64 %alt, i64 %ext
     71   %trunc = trunc i64 %res to i32
     72   store i32 %trunc, i32 *%ptr
     73   ret void
     74 }
     75 
     76 ; Test cases where the value is explicitly zero-extended to 32 bits, with the
     77 ; loaded value first.
     78 define void @f5(i32 *%ptr, i64 %alt, i32 %limit) {
     79 ; CHECK-LABEL: f5:
     80 ; CHECK-NOT: %r2
     81 ; CHECK: jl [[LABEL:[^ ]*]]
     82 ; CHECK-NOT: %r2
     83 ; CHECK: st %r3, 0(%r2)
     84 ; CHECK: [[LABEL]]:
     85 ; CHECK: br %r14
     86   %cond = icmp ult i32 %limit, 420
     87   %orig = load i32 , i32 *%ptr
     88   %ext = zext i32 %orig to i64
     89   %res = select i1 %cond, i64 %ext, i64 %alt
     90   %trunc = trunc i64 %res to i32
     91   store i32 %trunc, i32 *%ptr
     92   ret void
     93 }
     94 
     95 ; ...and with the loaded value second
     96 define void @f6(i32 *%ptr, i64 %alt, i32 %limit) {
     97 ; CHECK-LABEL: f6:
     98 ; CHECK-NOT: %r2
     99 ; CHECK: jhe [[LABEL:[^ ]*]]
    100 ; CHECK-NOT: %r2
    101 ; CHECK: st %r3, 0(%r2)
    102 ; CHECK: [[LABEL]]:
    103 ; CHECK: br %r14
    104   %cond = icmp ult i32 %limit, 420
    105   %orig = load i32 , i32 *%ptr
    106   %ext = zext i32 %orig to i64
    107   %res = select i1 %cond, i64 %alt, i64 %ext
    108   %trunc = trunc i64 %res to i32
    109   store i32 %trunc, i32 *%ptr
    110   ret void
    111 }
    112 
    113 ; Check the high end of the aligned ST range.
    114 define void @f7(i32 *%base, i32 %alt, i32 %limit) {
    115 ; CHECK-LABEL: f7:
    116 ; CHECK-NOT: %r2
    117 ; CHECK: jl [[LABEL:[^ ]*]]
    118 ; CHECK-NOT: %r2
    119 ; CHECK: st %r3, 4092(%r2)
    120 ; CHECK: [[LABEL]]:
    121 ; CHECK: br %r14
    122   %ptr = getelementptr i32, i32 *%base, i64 1023
    123   %cond = icmp ult i32 %limit, 420
    124   %orig = load i32 , i32 *%ptr
    125   %res = select i1 %cond, i32 %orig, i32 %alt
    126   store i32 %res, i32 *%ptr
    127   ret void
    128 }
    129 
    130 ; Check the next word up, which should use STY instead of ST.
    131 define void @f8(i32 *%base, i32 %alt, i32 %limit) {
    132 ; CHECK-LABEL: f8:
    133 ; CHECK-NOT: %r2
    134 ; CHECK: jl [[LABEL:[^ ]*]]
    135 ; CHECK-NOT: %r2
    136 ; CHECK: sty %r3, 4096(%r2)
    137 ; CHECK: [[LABEL]]:
    138 ; CHECK: br %r14
    139   %ptr = getelementptr i32, i32 *%base, i64 1024
    140   %cond = icmp ult i32 %limit, 420
    141   %orig = load i32 , i32 *%ptr
    142   %res = select i1 %cond, i32 %orig, i32 %alt
    143   store i32 %res, i32 *%ptr
    144   ret void
    145 }
    146 
    147 ; Check the high end of the aligned STY range.
    148 define void @f9(i32 *%base, i32 %alt, i32 %limit) {
    149 ; CHECK-LABEL: f9:
    150 ; CHECK-NOT: %r2
    151 ; CHECK: jl [[LABEL:[^ ]*]]
    152 ; CHECK-NOT: %r2
    153 ; CHECK: sty %r3, 524284(%r2)
    154 ; CHECK: [[LABEL]]:
    155 ; CHECK: br %r14
    156   %ptr = getelementptr i32, i32 *%base, i64 131071
    157   %cond = icmp ult i32 %limit, 420
    158   %orig = load i32 , i32 *%ptr
    159   %res = select i1 %cond, i32 %orig, i32 %alt
    160   store i32 %res, i32 *%ptr
    161   ret void
    162 }
    163 
    164 ; Check the next word up, which needs separate address logic.
    165 ; Other sequences besides this one would be OK.
    166 define void @f10(i32 *%base, i32 %alt, i32 %limit) {
    167 ; CHECK-LABEL: f10:
    168 ; CHECK-NOT: %r2
    169 ; CHECK: jl [[LABEL:[^ ]*]]
    170 ; CHECK-NOT: %r2
    171 ; CHECK: agfi %r2, 524288
    172 ; CHECK: st %r3, 0(%r2)
    173 ; CHECK: [[LABEL]]:
    174 ; CHECK: br %r14
    175   %ptr = getelementptr i32, i32 *%base, i64 131072
    176   %cond = icmp ult i32 %limit, 420
    177   %orig = load i32 , i32 *%ptr
    178   %res = select i1 %cond, i32 %orig, i32 %alt
    179   store i32 %res, i32 *%ptr
    180   ret void
    181 }
    182 
    183 ; Check the low end of the STY range.
    184 define void @f11(i32 *%base, i32 %alt, i32 %limit) {
    185 ; CHECK-LABEL: f11:
    186 ; CHECK-NOT: %r2
    187 ; CHECK: jl [[LABEL:[^ ]*]]
    188 ; CHECK-NOT: %r2
    189 ; CHECK: sty %r3, -524288(%r2)
    190 ; CHECK: [[LABEL]]:
    191 ; CHECK: br %r14
    192   %ptr = getelementptr i32, i32 *%base, i64 -131072
    193   %cond = icmp ult i32 %limit, 420
    194   %orig = load i32 , i32 *%ptr
    195   %res = select i1 %cond, i32 %orig, i32 %alt
    196   store i32 %res, i32 *%ptr
    197   ret void
    198 }
    199 
    200 ; Check the next word down, which needs separate address logic.
    201 ; Other sequences besides this one would be OK.
    202 define void @f12(i32 *%base, i32 %alt, i32 %limit) {
    203 ; CHECK-LABEL: f12:
    204 ; CHECK-NOT: %r2
    205 ; CHECK: jl [[LABEL:[^ ]*]]
    206 ; CHECK-NOT: %r2
    207 ; CHECK: agfi %r2, -524292
    208 ; CHECK: st %r3, 0(%r2)
    209 ; CHECK: [[LABEL]]:
    210 ; CHECK: br %r14
    211   %ptr = getelementptr i32, i32 *%base, i64 -131073
    212   %cond = icmp ult i32 %limit, 420
    213   %orig = load i32 , i32 *%ptr
    214   %res = select i1 %cond, i32 %orig, i32 %alt
    215   store i32 %res, i32 *%ptr
    216   ret void
    217 }
    218 
    219 ; Check that STY allows an index.
    220 define void @f13(i64 %base, i64 %index, i32 %alt, i32 %limit) {
    221 ; CHECK-LABEL: f13:
    222 ; CHECK-NOT: %r2
    223 ; CHECK: jl [[LABEL:[^ ]*]]
    224 ; CHECK-NOT: %r2
    225 ; CHECK: sty %r4, 4096(%r3,%r2)
    226 ; CHECK: [[LABEL]]:
    227 ; CHECK: br %r14
    228   %add1 = add i64 %base, %index
    229   %add2 = add i64 %add1, 4096
    230   %ptr = inttoptr i64 %add2 to i32 *
    231   %cond = icmp ult i32 %limit, 420
    232   %orig = load i32 , i32 *%ptr
    233   %res = select i1 %cond, i32 %orig, i32 %alt
    234   store i32 %res, i32 *%ptr
    235   ret void
    236 }
    237 
    238 ; Check that volatile loads are not matched.
    239 define void @f14(i32 *%ptr, i32 %alt, i32 %limit) {
    240 ; CHECK-LABEL: f14:
    241 ; CHECK: l {{%r[0-5]}}, 0(%r2)
    242 ; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]]
    243 ; CHECK: [[LABEL]]:
    244 ; CHECK: st {{%r[0-5]}}, 0(%r2)
    245 ; CHECK: br %r14
    246   %cond = icmp ult i32 %limit, 420
    247   %orig = load volatile i32 , i32 *%ptr
    248   %res = select i1 %cond, i32 %orig, i32 %alt
    249   store i32 %res, i32 *%ptr
    250   ret void
    251 }
    252 
    253 ; ...likewise stores.  In this case we should have a conditional load into %r3.
    254 define void @f15(i32 *%ptr, i32 %alt, i32 %limit) {
    255 ; CHECK-LABEL: f15:
    256 ; CHECK: jhe [[LABEL:[^ ]*]]
    257 ; CHECK: l %r3, 0(%r2)
    258 ; CHECK: [[LABEL]]:
    259 ; CHECK: st %r3, 0(%r2)
    260 ; CHECK: br %r14
    261   %cond = icmp ult i32 %limit, 420
    262   %orig = load i32 , i32 *%ptr
    263   %res = select i1 %cond, i32 %orig, i32 %alt
    264   store volatile i32 %res, i32 *%ptr
    265   ret void
    266 }
    267 
    268 ; Check that atomic loads are not matched.  The transformation is OK for
    269 ; the "unordered" case tested here, but since we don't try to handle atomic
    270 ; operations at all in this context, it seems better to assert that than
    271 ; to restrict the test to a stronger ordering.
    272 define void @f16(i32 *%ptr, i32 %alt, i32 %limit) {
    273 ; FIXME: should use a normal load instead of CS.
    274 ; CHECK-LABEL: f16:
    275 ; CHECK: l {{%r[0-5]}}, 0(%r2)
    276 ; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]]
    277 ; CHECK: [[LABEL]]:
    278 ; CHECK: st {{%r[0-5]}}, 0(%r2)
    279 ; CHECK: br %r14
    280   %cond = icmp ult i32 %limit, 420
    281   %orig = load atomic i32 , i32 *%ptr unordered, align 4
    282   %res = select i1 %cond, i32 %orig, i32 %alt
    283   store i32 %res, i32 *%ptr
    284   ret void
    285 }
    286 
    287 ; ...likewise stores.
    288 define void @f17(i32 *%ptr, i32 %alt, i32 %limit) {
    289 ; FIXME: should use a normal store instead of CS.
    290 ; CHECK-LABEL: f17:
    291 ; CHECK: jhe [[LABEL:[^ ]*]]
    292 ; CHECK: l %r3, 0(%r2)
    293 ; CHECK: [[LABEL]]:
    294 ; CHECK: st %r3, 0(%r2)
    295 ; CHECK: br %r14
    296   %cond = icmp ult i32 %limit, 420
    297   %orig = load i32 , i32 *%ptr
    298   %res = select i1 %cond, i32 %orig, i32 %alt
    299   store atomic i32 %res, i32 *%ptr unordered, align 4
    300   ret void
    301 }
    302 
    303 ; Try a frame index base.
    304 define void @f18(i32 %alt, i32 %limit) {
    305 ; CHECK-LABEL: f18:
    306 ; CHECK: brasl %r14, foo@PLT
    307 ; CHECK-NOT: %r15
    308 ; CHECK: jl [[LABEL:[^ ]*]]
    309 ; CHECK-NOT: %r15
    310 ; CHECK: st {{%r[0-9]+}}, {{[0-9]+}}(%r15)
    311 ; CHECK: [[LABEL]]:
    312 ; CHECK: brasl %r14, foo@PLT
    313 ; CHECK: br %r14
    314   %ptr = alloca i32
    315   call void @foo(i32 *%ptr)
    316   %cond = icmp ult i32 %limit, 420
    317   %orig = load i32 , i32 *%ptr
    318   %res = select i1 %cond, i32 %orig, i32 %alt
    319   store i32 %res, i32 *%ptr
    320   call void @foo(i32 *%ptr)
    321   ret void
    322 }
    323