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. 12define 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. 23define 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. 36define 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. 49define 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. 62define 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. 75define 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. 86define 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. 99define 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. 112define 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. 125define 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. 138define 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. 149define 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. 162define 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. 175define 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. 186define 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. 197define 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. 208define 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. 219define 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. 230define 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. 242define 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. 252define 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. 262define 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. 275define 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. 286define 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. 297define 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. 308define 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. 319define 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. 330define 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. 341define 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. 352define 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. 363define 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. 374define 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. 385define 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. 396define 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. 406define 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