1; Test strict multiplication of two f64s, producing an f128 result. 2; 3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 4 5declare fp128 @llvm.experimental.constrained.fmul.f128(fp128, fp128, metadata, metadata) 6declare double @llvm.experimental.constrained.fadd.f64(double, double, metadata, metadata) 7declare double @llvm.experimental.constrained.fptrunc.f64.f128(fp128, metadata, metadata) 8declare fp128 @llvm.experimental.constrained.fpext.f128.f64(double, metadata) 9 10declare double @foo() 11 12; Check register multiplication. "mxdbr %f0, %f2" is not valid from LLVM's 13; point of view, because %f2 is the low register of the FP128 %f0. Pass the 14; multiplier in %f4 instead. 15define void @f1(double %f1, double %dummy, double %f2, ptr %dst) #0 { 16; CHECK-LABEL: f1: 17; CHECK: mxdbr %f0, %f4 18; CHECK: std %f0, 0(%r2) 19; CHECK: std %f2, 8(%r2) 20; CHECK: br %r14 21 %f1x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 22 double %f1, 23 metadata !"fpexcept.strict") #0 24 %f2x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 25 double %f2, 26 metadata !"fpexcept.strict") #0 27 %res = call fp128 @llvm.experimental.constrained.fmul.f128( 28 fp128 %f1x, fp128 %f2x, 29 metadata !"round.dynamic", 30 metadata !"fpexcept.strict") #0 31 store fp128 %res, ptr %dst 32 ret void 33} 34 35; Check the low end of the MXDB range. 36define void @f2(double %f1, ptr %ptr, ptr %dst) #0 { 37; CHECK-LABEL: f2: 38; CHECK: mxdb %f0, 0(%r2) 39; CHECK: std %f0, 0(%r3) 40; CHECK: std %f2, 8(%r3) 41; CHECK: br %r14 42 %f2 = load double, ptr %ptr 43 %f1x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 44 double %f1, 45 metadata !"fpexcept.strict") #0 46 %f2x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 47 double %f2, 48 metadata !"fpexcept.strict") #0 49 %res = call fp128 @llvm.experimental.constrained.fmul.f128( 50 fp128 %f1x, fp128 %f2x, 51 metadata !"round.dynamic", 52 metadata !"fpexcept.strict") #0 53 store fp128 %res, ptr %dst 54 ret void 55} 56 57; Check the high end of the aligned MXDB range. 58define void @f3(double %f1, ptr %base, ptr %dst) #0 { 59; CHECK-LABEL: f3: 60; CHECK: mxdb %f0, 4088(%r2) 61; CHECK: std %f0, 0(%r3) 62; CHECK: std %f2, 8(%r3) 63; CHECK: br %r14 64 %ptr = getelementptr double, ptr %base, i64 511 65 %f2 = load double, ptr %ptr 66 %f1x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 67 double %f1, 68 metadata !"fpexcept.strict") #0 69 %f2x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 70 double %f2, 71 metadata !"fpexcept.strict") #0 72 %res = call fp128 @llvm.experimental.constrained.fmul.f128( 73 fp128 %f1x, fp128 %f2x, 74 metadata !"round.dynamic", 75 metadata !"fpexcept.strict") #0 76 store fp128 %res, ptr %dst 77 ret void 78} 79 80; Check the next doubleword up, which needs separate address logic. 81; Other sequences besides this one would be OK. 82define void @f4(double %f1, ptr %base, ptr %dst) #0 { 83; CHECK-LABEL: f4: 84; CHECK: aghi %r2, 4096 85; CHECK: mxdb %f0, 0(%r2) 86; CHECK: std %f0, 0(%r3) 87; CHECK: std %f2, 8(%r3) 88; CHECK: br %r14 89 %ptr = getelementptr double, ptr %base, i64 512 90 %f2 = load double, ptr %ptr 91 %f1x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 92 double %f1, 93 metadata !"fpexcept.strict") #0 94 %f2x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 95 double %f2, 96 metadata !"fpexcept.strict") #0 97 %res = call fp128 @llvm.experimental.constrained.fmul.f128( 98 fp128 %f1x, fp128 %f2x, 99 metadata !"round.dynamic", 100 metadata !"fpexcept.strict") #0 101 store fp128 %res, ptr %dst 102 ret void 103} 104 105; Check negative displacements, which also need separate address logic. 106define void @f5(double %f1, ptr %base, ptr %dst) #0 { 107; CHECK-LABEL: f5: 108; CHECK: aghi %r2, -8 109; CHECK: mxdb %f0, 0(%r2) 110; CHECK: std %f0, 0(%r3) 111; CHECK: std %f2, 8(%r3) 112; CHECK: br %r14 113 %ptr = getelementptr double, ptr %base, i64 -1 114 %f2 = load double, ptr %ptr 115 %f1x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 116 double %f1, 117 metadata !"fpexcept.strict") #0 118 %f2x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 119 double %f2, 120 metadata !"fpexcept.strict") #0 121 %res = call fp128 @llvm.experimental.constrained.fmul.f128( 122 fp128 %f1x, fp128 %f2x, 123 metadata !"round.dynamic", 124 metadata !"fpexcept.strict") #0 125 store fp128 %res, ptr %dst 126 ret void 127} 128 129; Check that MXDB allows indices. 130define void @f6(double %f1, ptr %base, i64 %index, ptr %dst) #0 { 131; CHECK-LABEL: f6: 132; CHECK: sllg %r1, %r3, 3 133; CHECK: mxdb %f0, 800(%r1,%r2) 134; CHECK: std %f0, 0(%r4) 135; CHECK: std %f2, 8(%r4) 136; CHECK: br %r14 137 %ptr1 = getelementptr double, ptr %base, i64 %index 138 %ptr2 = getelementptr double, ptr %ptr1, i64 100 139 %f2 = load double, ptr %ptr2 140 %f1x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 141 double %f1, 142 metadata !"fpexcept.strict") #0 143 %f2x = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 144 double %f2, 145 metadata !"fpexcept.strict") #0 146 %res = call fp128 @llvm.experimental.constrained.fmul.f128( 147 fp128 %f1x, fp128 %f2x, 148 metadata !"round.dynamic", 149 metadata !"fpexcept.strict") #0 150 store fp128 %res, ptr %dst 151 ret void 152} 153 154; Check that multiplications of spilled values can use MXDB rather than MXDBR. 155define double @f7(ptr %ptr0) #0 { 156; CHECK-LABEL: f7: 157; CHECK: brasl %r14, foo@PLT 158; CHECK: mxdb %f0, 160(%r15) 159; CHECK: br %r14 160 %ptr1 = getelementptr double, ptr %ptr0, i64 2 161 %ptr2 = getelementptr double, ptr %ptr0, i64 4 162 %ptr3 = getelementptr double, ptr %ptr0, i64 6 163 %ptr4 = getelementptr double, ptr %ptr0, i64 8 164 %ptr5 = getelementptr double, ptr %ptr0, i64 10 165 %ptr6 = getelementptr double, ptr %ptr0, i64 12 166 %ptr7 = getelementptr double, ptr %ptr0, i64 14 167 %ptr8 = getelementptr double, ptr %ptr0, i64 16 168 %ptr9 = getelementptr double, ptr %ptr0, i64 18 169 %ptr10 = getelementptr double, ptr %ptr0, i64 20 170 171 %val0 = load double, ptr %ptr0 172 %val1 = load double, ptr %ptr1 173 %val2 = load double, ptr %ptr2 174 %val3 = load double, ptr %ptr3 175 %val4 = load double, ptr %ptr4 176 %val5 = load double, ptr %ptr5 177 %val6 = load double, ptr %ptr6 178 %val7 = load double, ptr %ptr7 179 %val8 = load double, ptr %ptr8 180 %val9 = load double, ptr %ptr9 181 %val10 = load double, ptr %ptr10 182 183 %frob0 = call double @llvm.experimental.constrained.fadd.f64( 184 double %val0, double %val0, 185 metadata !"round.dynamic", 186 metadata !"fpexcept.strict") #0 187 %frob1 = call double @llvm.experimental.constrained.fadd.f64( 188 double %val1, double %val1, 189 metadata !"round.dynamic", 190 metadata !"fpexcept.strict") #0 191 %frob2 = call double @llvm.experimental.constrained.fadd.f64( 192 double %val2, double %val2, 193 metadata !"round.dynamic", 194 metadata !"fpexcept.strict") #0 195 %frob3 = call double @llvm.experimental.constrained.fadd.f64( 196 double %val3, double %val3, 197 metadata !"round.dynamic", 198 metadata !"fpexcept.strict") #0 199 %frob4 = call double @llvm.experimental.constrained.fadd.f64( 200 double %val4, double %val4, 201 metadata !"round.dynamic", 202 metadata !"fpexcept.strict") #0 203 %frob5 = call double @llvm.experimental.constrained.fadd.f64( 204 double %val5, double %val5, 205 metadata !"round.dynamic", 206 metadata !"fpexcept.strict") #0 207 %frob6 = call double @llvm.experimental.constrained.fadd.f64( 208 double %val6, double %val6, 209 metadata !"round.dynamic", 210 metadata !"fpexcept.strict") #0 211 %frob7 = call double @llvm.experimental.constrained.fadd.f64( 212 double %val7, double %val7, 213 metadata !"round.dynamic", 214 metadata !"fpexcept.strict") #0 215 %frob8 = call double @llvm.experimental.constrained.fadd.f64( 216 double %val8, double %val8, 217 metadata !"round.dynamic", 218 metadata !"fpexcept.strict") #0 219 %frob9 = call double @llvm.experimental.constrained.fadd.f64( 220 double %val9, double %val9, 221 metadata !"round.dynamic", 222 metadata !"fpexcept.strict") #0 223 %frob10 = call double @llvm.experimental.constrained.fadd.f64( 224 double %val10, double %val10, 225 metadata !"round.dynamic", 226 metadata !"fpexcept.strict") #0 227 228 store double %frob0, ptr %ptr0 229 store double %frob1, ptr %ptr1 230 store double %frob2, ptr %ptr2 231 store double %frob3, ptr %ptr3 232 store double %frob4, ptr %ptr4 233 store double %frob5, ptr %ptr5 234 store double %frob6, ptr %ptr6 235 store double %frob7, ptr %ptr7 236 store double %frob8, ptr %ptr8 237 store double %frob9, ptr %ptr9 238 store double %frob10, ptr %ptr10 239 240 %ret = call double @foo() #0 241 242 %accext0 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 243 double %ret, 244 metadata !"fpexcept.strict") #0 245 %ext0 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 246 double %frob0, 247 metadata !"fpexcept.strict") #0 248 %mul0 = call fp128 @llvm.experimental.constrained.fmul.f128( 249 fp128 %accext0, fp128 %ext0, 250 metadata !"round.dynamic", 251 metadata !"fpexcept.strict") #0 252 %extra0 = call fp128 @llvm.experimental.constrained.fmul.f128( 253 fp128 %mul0, fp128 0xL00000000000000003fff000001000000, 254 metadata !"round.dynamic", 255 metadata !"fpexcept.strict") #0 256 %trunc0 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 257 fp128 %extra0, 258 metadata !"round.dynamic", 259 metadata !"fpexcept.strict") #0 260 261 %accext1 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 262 double %trunc0, 263 metadata !"fpexcept.strict") #0 264 %ext1 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 265 double %frob1, 266 metadata !"fpexcept.strict") #0 267 %mul1 = call fp128 @llvm.experimental.constrained.fmul.f128( 268 fp128 %accext1, fp128 %ext1, 269 metadata !"round.dynamic", 270 metadata !"fpexcept.strict") #0 271 %extra1 = call fp128 @llvm.experimental.constrained.fmul.f128( 272 fp128 %mul1, fp128 0xL00000000000000003fff000002000000, 273 metadata !"round.dynamic", 274 metadata !"fpexcept.strict") #0 275 %trunc1 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 276 fp128 %extra1, 277 metadata !"round.dynamic", 278 metadata !"fpexcept.strict") #0 279 280 %accext2 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 281 double %trunc1, 282 metadata !"fpexcept.strict") #0 283 %ext2 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 284 double %frob2, 285 metadata !"fpexcept.strict") #0 286 %mul2 = call fp128 @llvm.experimental.constrained.fmul.f128( 287 fp128 %accext2, fp128 %ext2, 288 metadata !"round.dynamic", 289 metadata !"fpexcept.strict") #0 290 %extra2 = call fp128 @llvm.experimental.constrained.fmul.f128( 291 fp128 %mul2, fp128 0xL00000000000000003fff000003000000, 292 metadata !"round.dynamic", 293 metadata !"fpexcept.strict") #0 294 %trunc2 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 295 fp128 %extra2, 296 metadata !"round.dynamic", 297 metadata !"fpexcept.strict") #0 298 299 %accext3 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 300 double %trunc2, 301 metadata !"fpexcept.strict") #0 302 %ext3 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 303 double %frob3, 304 metadata !"fpexcept.strict") #0 305 %mul3 = call fp128 @llvm.experimental.constrained.fmul.f128( 306 fp128 %accext3, fp128 %ext3, 307 metadata !"round.dynamic", 308 metadata !"fpexcept.strict") #0 309 %extra3 = call fp128 @llvm.experimental.constrained.fmul.f128( 310 fp128 %mul3, fp128 0xL00000000000000003fff000004000000, 311 metadata !"round.dynamic", 312 metadata !"fpexcept.strict") #0 313 %trunc3 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 314 fp128 %extra3, 315 metadata !"round.dynamic", 316 metadata !"fpexcept.strict") #0 317 318 %accext4 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 319 double %trunc3, 320 metadata !"fpexcept.strict") #0 321 %ext4 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 322 double %frob4, 323 metadata !"fpexcept.strict") #0 324 %mul4 = call fp128 @llvm.experimental.constrained.fmul.f128( 325 fp128 %accext4, fp128 %ext4, 326 metadata !"round.dynamic", 327 metadata !"fpexcept.strict") #0 328 %extra4 = call fp128 @llvm.experimental.constrained.fmul.f128( 329 fp128 %mul4, fp128 0xL00000000000000003fff000005000000, 330 metadata !"round.dynamic", 331 metadata !"fpexcept.strict") #0 332 %trunc4 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 333 fp128 %extra4, 334 metadata !"round.dynamic", 335 metadata !"fpexcept.strict") #0 336 337 %accext5 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 338 double %trunc4, 339 metadata !"fpexcept.strict") #0 340 %ext5 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 341 double %frob5, 342 metadata !"fpexcept.strict") #0 343 %mul5 = call fp128 @llvm.experimental.constrained.fmul.f128( 344 fp128 %accext5, fp128 %ext5, 345 metadata !"round.dynamic", 346 metadata !"fpexcept.strict") #0 347 %extra5 = call fp128 @llvm.experimental.constrained.fmul.f128( 348 fp128 %mul5, fp128 0xL00000000000000003fff000006000000, 349 metadata !"round.dynamic", 350 metadata !"fpexcept.strict") #0 351 %trunc5 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 352 fp128 %extra5, 353 metadata !"round.dynamic", 354 metadata !"fpexcept.strict") #0 355 356 %accext6 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 357 double %trunc5, 358 metadata !"fpexcept.strict") #0 359 %ext6 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 360 double %frob6, 361 metadata !"fpexcept.strict") #0 362 %mul6 = call fp128 @llvm.experimental.constrained.fmul.f128( 363 fp128 %accext6, fp128 %ext6, 364 metadata !"round.dynamic", 365 metadata !"fpexcept.strict") #0 366 %extra6 = call fp128 @llvm.experimental.constrained.fmul.f128( 367 fp128 %mul6, fp128 0xL00000000000000003fff000007000000, 368 metadata !"round.dynamic", 369 metadata !"fpexcept.strict") #0 370 %trunc6 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 371 fp128 %extra6, 372 metadata !"round.dynamic", 373 metadata !"fpexcept.strict") #0 374 375 %accext7 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 376 double %trunc6, 377 metadata !"fpexcept.strict") #0 378 %ext7 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 379 double %frob7, 380 metadata !"fpexcept.strict") #0 381 %mul7 = call fp128 @llvm.experimental.constrained.fmul.f128( 382 fp128 %accext7, fp128 %ext7, 383 metadata !"round.dynamic", 384 metadata !"fpexcept.strict") #0 385 %extra7 = call fp128 @llvm.experimental.constrained.fmul.f128( 386 fp128 %mul7, fp128 0xL00000000000000003fff000008000000, 387 metadata !"round.dynamic", 388 metadata !"fpexcept.strict") #0 389 %trunc7 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 390 fp128 %extra7, 391 metadata !"round.dynamic", 392 metadata !"fpexcept.strict") #0 393 394 %accext8 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 395 double %trunc7, 396 metadata !"fpexcept.strict") #0 397 %ext8 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 398 double %frob8, 399 metadata !"fpexcept.strict") #0 400 %mul8 = call fp128 @llvm.experimental.constrained.fmul.f128( 401 fp128 %accext8, fp128 %ext8, 402 metadata !"round.dynamic", 403 metadata !"fpexcept.strict") #0 404 %extra8 = call fp128 @llvm.experimental.constrained.fmul.f128( 405 fp128 %mul8, fp128 0xL00000000000000003fff000009000000, 406 metadata !"round.dynamic", 407 metadata !"fpexcept.strict") #0 408 %trunc8 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 409 fp128 %extra8, 410 metadata !"round.dynamic", 411 metadata !"fpexcept.strict") #0 412 413 %accext9 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 414 double %trunc8, 415 metadata !"fpexcept.strict") #0 416 %ext9 = call fp128 @llvm.experimental.constrained.fpext.f128.f64( 417 double %frob9, 418 metadata !"fpexcept.strict") #0 419 %mul9 = call fp128 @llvm.experimental.constrained.fmul.f128( 420 fp128 %accext9, fp128 %ext9, 421 metadata !"round.dynamic", 422 metadata !"fpexcept.strict") #0 423 %extra9 = call fp128 @llvm.experimental.constrained.fmul.f128( 424 fp128 %mul9, fp128 0xL00000000000000003fff00000a000000, 425 metadata !"round.dynamic", 426 metadata !"fpexcept.strict") #0 427 %trunc9 = call double @llvm.experimental.constrained.fptrunc.f64.f128( 428 fp128 %extra9, 429 metadata !"round.dynamic", 430 metadata !"fpexcept.strict") #0 431 432 ret double %trunc9 433} 434 435attributes #0 = { strictfp } 436