1 ; Test load/store pairs that act as memcpys. 2 ; 3 ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 4 5 @g1 = global i8 1 6 @g2 = global i16 2 7 @g3 = global i32 3 8 @g4 = global i64 4 9 @g5 = external global fp128, align 16 10 11 ; Test the simple i8 case. 12 define void @f1(i8 *%ptr1) { 13 ; CHECK-LABEL: f1: 14 ; CHECK: mvc 1(1,%r2), 0(%r2) 15 ; CHECK: br %r14 16 %ptr2 = getelementptr i8 *%ptr1, i64 1 17 %val = load i8 *%ptr1 18 store i8 %val, i8 *%ptr2 19 ret void 20 } 21 22 ; Test i8 cases where the value is zero-extended to 32 bits. 23 define void @f2(i8 *%ptr1) { 24 ; CHECK-LABEL: f2: 25 ; CHECK: mvc 1(1,%r2), 0(%r2) 26 ; CHECK: br %r14 27 %ptr2 = getelementptr i8 *%ptr1, i64 1 28 %val = load i8 *%ptr1 29 %ext = zext i8 %val to i32 30 %trunc = trunc i32 %ext to i8 31 store i8 %trunc, i8 *%ptr2 32 ret void 33 } 34 35 ; Test i8 cases where the value is zero-extended to 64 bits. 36 define void @f3(i8 *%ptr1) { 37 ; CHECK-LABEL: f3: 38 ; CHECK: mvc 1(1,%r2), 0(%r2) 39 ; CHECK: br %r14 40 %ptr2 = getelementptr i8 *%ptr1, i64 1 41 %val = load i8 *%ptr1 42 %ext = zext i8 %val to i64 43 %trunc = trunc i64 %ext to i8 44 store i8 %trunc, i8 *%ptr2 45 ret void 46 } 47 48 ; Test i8 cases where the value is sign-extended to 32 bits. 49 define void @f4(i8 *%ptr1) { 50 ; CHECK-LABEL: f4: 51 ; CHECK: mvc 1(1,%r2), 0(%r2) 52 ; CHECK: br %r14 53 %ptr2 = getelementptr i8 *%ptr1, i64 1 54 %val = load i8 *%ptr1 55 %ext = sext i8 %val to i32 56 %trunc = trunc i32 %ext to i8 57 store i8 %trunc, i8 *%ptr2 58 ret void 59 } 60 61 ; Test i8 cases where the value is sign-extended to 64 bits. 62 define void @f5(i8 *%ptr1) { 63 ; CHECK-LABEL: f5: 64 ; CHECK: mvc 1(1,%r2), 0(%r2) 65 ; CHECK: br %r14 66 %ptr2 = getelementptr i8 *%ptr1, i64 1 67 %val = load i8 *%ptr1 68 %ext = sext i8 %val to i64 69 %trunc = trunc i64 %ext to i8 70 store i8 %trunc, i8 *%ptr2 71 ret void 72 } 73 74 ; Test the simple i16 case. 75 define void @f6(i16 *%ptr1) { 76 ; CHECK-LABEL: f6: 77 ; CHECK: mvc 2(2,%r2), 0(%r2) 78 ; CHECK: br %r14 79 %ptr2 = getelementptr i16 *%ptr1, i64 1 80 %val = load i16 *%ptr1 81 store i16 %val, i16 *%ptr2 82 ret void 83 } 84 85 ; Test i16 cases where the value is zero-extended to 32 bits. 86 define void @f7(i16 *%ptr1) { 87 ; CHECK-LABEL: f7: 88 ; CHECK: mvc 2(2,%r2), 0(%r2) 89 ; CHECK: br %r14 90 %ptr2 = getelementptr i16 *%ptr1, i64 1 91 %val = load i16 *%ptr1 92 %ext = zext i16 %val to i32 93 %trunc = trunc i32 %ext to i16 94 store i16 %trunc, i16 *%ptr2 95 ret void 96 } 97 98 ; Test i16 cases where the value is zero-extended to 64 bits. 99 define void @f8(i16 *%ptr1) { 100 ; CHECK-LABEL: f8: 101 ; CHECK: mvc 2(2,%r2), 0(%r2) 102 ; CHECK: br %r14 103 %ptr2 = getelementptr i16 *%ptr1, i64 1 104 %val = load i16 *%ptr1 105 %ext = zext i16 %val to i64 106 %trunc = trunc i64 %ext to i16 107 store i16 %trunc, i16 *%ptr2 108 ret void 109 } 110 111 ; Test i16 cases where the value is sign-extended to 32 bits. 112 define void @f9(i16 *%ptr1) { 113 ; CHECK-LABEL: f9: 114 ; CHECK: mvc 2(2,%r2), 0(%r2) 115 ; CHECK: br %r14 116 %ptr2 = getelementptr i16 *%ptr1, i64 1 117 %val = load i16 *%ptr1 118 %ext = sext i16 %val to i32 119 %trunc = trunc i32 %ext to i16 120 store i16 %trunc, i16 *%ptr2 121 ret void 122 } 123 124 ; Test i16 cases where the value is sign-extended to 64 bits. 125 define void @f10(i16 *%ptr1) { 126 ; CHECK-LABEL: f10: 127 ; CHECK: mvc 2(2,%r2), 0(%r2) 128 ; CHECK: br %r14 129 %ptr2 = getelementptr i16 *%ptr1, i64 1 130 %val = load i16 *%ptr1 131 %ext = sext i16 %val to i64 132 %trunc = trunc i64 %ext to i16 133 store i16 %trunc, i16 *%ptr2 134 ret void 135 } 136 137 ; Test the simple i32 case. 138 define void @f11(i32 *%ptr1) { 139 ; CHECK-LABEL: f11: 140 ; CHECK: mvc 4(4,%r2), 0(%r2) 141 ; CHECK: br %r14 142 %ptr2 = getelementptr i32 *%ptr1, i64 1 143 %val = load i32 *%ptr1 144 store i32 %val, i32 *%ptr2 145 ret void 146 } 147 148 ; Test i32 cases where the value is zero-extended to 64 bits. 149 define void @f12(i32 *%ptr1) { 150 ; CHECK-LABEL: f12: 151 ; CHECK: mvc 4(4,%r2), 0(%r2) 152 ; CHECK: br %r14 153 %ptr2 = getelementptr i32 *%ptr1, i64 1 154 %val = load i32 *%ptr1 155 %ext = zext i32 %val to i64 156 %trunc = trunc i64 %ext to i32 157 store i32 %trunc, i32 *%ptr2 158 ret void 159 } 160 161 ; Test i32 cases where the value is sign-extended to 64 bits. 162 define void @f13(i32 *%ptr1) { 163 ; CHECK-LABEL: f13: 164 ; CHECK: mvc 4(4,%r2), 0(%r2) 165 ; CHECK: br %r14 166 %ptr2 = getelementptr i32 *%ptr1, i64 1 167 %val = load i32 *%ptr1 168 %ext = sext i32 %val to i64 169 %trunc = trunc i64 %ext to i32 170 store i32 %trunc, i32 *%ptr2 171 ret void 172 } 173 174 ; Test the i64 case. 175 define void @f14(i64 *%ptr1) { 176 ; CHECK-LABEL: f14: 177 ; CHECK: mvc 8(8,%r2), 0(%r2) 178 ; CHECK: br %r14 179 %ptr2 = getelementptr i64 *%ptr1, i64 1 180 %val = load i64 *%ptr1 181 store i64 %val, i64 *%ptr2 182 ret void 183 } 184 185 ; Test the f32 case. 186 define void @f15(float *%ptr1) { 187 ; CHECK-LABEL: f15: 188 ; CHECK: mvc 4(4,%r2), 0(%r2) 189 ; CHECK: br %r14 190 %ptr2 = getelementptr float *%ptr1, i64 1 191 %val = load float *%ptr1 192 store float %val, float *%ptr2 193 ret void 194 } 195 196 ; Test the f64 case. 197 define void @f16(double *%ptr1) { 198 ; CHECK-LABEL: f16: 199 ; CHECK: mvc 8(8,%r2), 0(%r2) 200 ; CHECK: br %r14 201 %ptr2 = getelementptr double *%ptr1, i64 1 202 %val = load double *%ptr1 203 store double %val, double *%ptr2 204 ret void 205 } 206 207 ; Test the f128 case. 208 define void @f17(fp128 *%ptr1) { 209 ; CHECK-LABEL: f17: 210 ; CHECK: mvc 16(16,%r2), 0(%r2) 211 ; CHECK: br %r14 212 %ptr2 = getelementptr fp128 *%ptr1, i64 1 213 %val = load fp128 *%ptr1 214 store fp128 %val, fp128 *%ptr2 215 ret void 216 } 217 218 ; Make sure that we don't use MVC if the load is volatile. 219 define void @f18(i64 *%ptr1) { 220 ; CHECK-LABEL: f18: 221 ; CHECK-NOT: mvc 222 ; CHECK: br %r14 223 %ptr2 = getelementptr i64 *%ptr1, i64 1 224 %val = load volatile i64 *%ptr1 225 store i64 %val, i64 *%ptr2 226 ret void 227 } 228 229 ; ...likewise the store. 230 define void @f19(i64 *%ptr1) { 231 ; CHECK-LABEL: f19: 232 ; CHECK-NOT: mvc 233 ; CHECK: br %r14 234 %ptr2 = getelementptr i64 *%ptr1, i64 1 235 %val = load i64 *%ptr1 236 store volatile i64 %val, i64 *%ptr2 237 ret void 238 } 239 240 ; Test that MVC is used for aligned loads and stores, even if there is 241 ; no way of telling whether they alias. 242 define void @f20(i64 *%ptr1, i64 *%ptr2) { 243 ; CHECK-LABEL: f20: 244 ; CHECK: mvc 0(8,%r3), 0(%r2) 245 ; CHECK: br %r14 246 %val = load i64 *%ptr1 247 store i64 %val, i64 *%ptr2 248 ret void 249 } 250 251 ; ...but if the loads aren't aligned, we can't be sure. 252 define void @f21(i64 *%ptr1, i64 *%ptr2) { 253 ; CHECK-LABEL: f21: 254 ; CHECK-NOT: mvc 255 ; CHECK: br %r14 256 %val = load i64 *%ptr1, align 2 257 store i64 %val, i64 *%ptr2, align 2 258 ret void 259 } 260 261 ; Test a case where there is definite overlap. 262 define void @f22(i64 %base) { 263 ; CHECK-LABEL: f22: 264 ; CHECK-NOT: mvc 265 ; CHECK: br %r14 266 %add = add i64 %base, 1 267 %ptr1 = inttoptr i64 %base to i64 * 268 %ptr2 = inttoptr i64 %add to i64 * 269 %val = load i64 *%ptr1, align 1 270 store i64 %val, i64 *%ptr2, align 1 271 ret void 272 } 273 274 ; Test that we can use MVC for global addresses for i8. 275 define void @f23(i8 *%ptr) { 276 ; CHECK-LABEL: f23: 277 ; CHECK: larl [[REG:%r[0-5]]], g1 278 ; CHECK: mvc 0(1,%r2), 0([[REG]]) 279 ; CHECK: br %r14 280 %val = load i8 *@g1 281 store i8 %val, i8 *%ptr 282 ret void 283 } 284 285 ; ...and again with the global on the store. 286 define void @f24(i8 *%ptr) { 287 ; CHECK-LABEL: f24: 288 ; CHECK: larl [[REG:%r[0-5]]], g1 289 ; CHECK: mvc 0(1,[[REG]]), 0(%r2) 290 ; CHECK: br %r14 291 %val = load i8 *%ptr 292 store i8 %val, i8 *@g1 293 ret void 294 } 295 296 ; Test that we use LHRL for i16. 297 define void @f25(i16 *%ptr) { 298 ; CHECK-LABEL: f25: 299 ; CHECK: lhrl [[REG:%r[0-5]]], g2 300 ; CHECK: sth [[REG]], 0(%r2) 301 ; CHECK: br %r14 302 %val = load i16 *@g2 303 store i16 %val, i16 *%ptr 304 ret void 305 } 306 307 ; ...likewise STHRL. 308 define void @f26(i16 *%ptr) { 309 ; CHECK-LABEL: f26: 310 ; CHECK: lh [[REG:%r[0-5]]], 0(%r2) 311 ; CHECK: sthrl [[REG]], g2 312 ; CHECK: br %r14 313 %val = load i16 *%ptr 314 store i16 %val, i16 *@g2 315 ret void 316 } 317 318 ; Test that we use LRL for i32. 319 define void @f27(i32 *%ptr) { 320 ; CHECK-LABEL: f27: 321 ; CHECK: lrl [[REG:%r[0-5]]], g3 322 ; CHECK: st [[REG]], 0(%r2) 323 ; CHECK: br %r14 324 %val = load i32 *@g3 325 store i32 %val, i32 *%ptr 326 ret void 327 } 328 329 ; ...likewise STRL. 330 define void @f28(i32 *%ptr) { 331 ; CHECK-LABEL: f28: 332 ; CHECK: l [[REG:%r[0-5]]], 0(%r2) 333 ; CHECK: strl [[REG]], g3 334 ; CHECK: br %r14 335 %val = load i32 *%ptr 336 store i32 %val, i32 *@g3 337 ret void 338 } 339 340 ; Test that we use LGRL for i64. 341 define void @f29(i64 *%ptr) { 342 ; CHECK-LABEL: f29: 343 ; CHECK: lgrl [[REG:%r[0-5]]], g4 344 ; CHECK: stg [[REG]], 0(%r2) 345 ; CHECK: br %r14 346 %val = load i64 *@g4 347 store i64 %val, i64 *%ptr 348 ret void 349 } 350 351 ; ...likewise STGRL. 352 define void @f30(i64 *%ptr) { 353 ; CHECK-LABEL: f30: 354 ; CHECK: lg [[REG:%r[0-5]]], 0(%r2) 355 ; CHECK: stgrl [[REG]], g4 356 ; CHECK: br %r14 357 %val = load i64 *%ptr 358 store i64 %val, i64 *@g4 359 ret void 360 } 361 362 ; Test that we can use MVC for global addresses for fp128. 363 define void @f31(fp128 *%ptr) { 364 ; CHECK-LABEL: f31: 365 ; CHECK: larl [[REG:%r[0-5]]], g5 366 ; CHECK: mvc 0(16,%r2), 0([[REG]]) 367 ; CHECK: br %r14 368 %val = load fp128 *@g5, align 16 369 store fp128 %val, fp128 *%ptr, align 16 370 ret void 371 } 372 373 ; ...and again with the global on the store. 374 define void @f32(fp128 *%ptr) { 375 ; CHECK-LABEL: f32: 376 ; CHECK: larl [[REG:%r[0-5]]], g5 377 ; CHECK: mvc 0(16,[[REG]]), 0(%r2) 378 ; CHECK: br %r14 379 %val = load fp128 *%ptr, align 16 380 store fp128 %val, fp128 *@g5, align 16 381 ret void 382 } 383 384 ; Test a case where offset disambiguation is enough. 385 define void @f33(i64 *%ptr1) { 386 ; CHECK-LABEL: f33: 387 ; CHECK: mvc 8(8,%r2), 0(%r2) 388 ; CHECK: br %r14 389 %ptr2 = getelementptr i64 *%ptr1, i64 1 390 %val = load i64 *%ptr1, align 1 391 store i64 %val, i64 *%ptr2, align 1 392 ret void 393 } 394 395 ; Test f21 in cases where TBAA tells us there is no alias. 396 define void @f34(i64 *%ptr1, i64 *%ptr2) { 397 ; CHECK-LABEL: f34: 398 ; CHECK: mvc 0(8,%r3), 0(%r2) 399 ; CHECK: br %r14 400 %val = load i64 *%ptr1, align 2, !tbaa !1 401 store i64 %val, i64 *%ptr2, align 2, !tbaa !2 402 ret void 403 } 404 405 ; Test f21 in cases where TBAA is present but doesn't help. 406 define void @f35(i64 *%ptr1, i64 *%ptr2) { 407 ; CHECK-LABEL: f35: 408 ; CHECK-NOT: mvc 409 ; CHECK: br %r14 410 %val = load i64 *%ptr1, align 2, !tbaa !1 411 store i64 %val, i64 *%ptr2, align 2, !tbaa !1 412 ret void 413 } 414 415 !0 = metadata !{ metadata !"root" } 416 !1 = metadata !{ metadata !"set1", metadata !0 } 417 !2 = metadata !{ metadata !"set2", metadata !0 } 418