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