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