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