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