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