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