1; Test that floating-point strict compares are omitted if CC already has the 2; right value. 3; 4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 \ 5; RUN: -enable-misched=0 -no-integrated-as | FileCheck %s 6; 7; We need -enable-misched=0 to make sure f12 and following routines really 8; test the compare elimination pass. 9 10 11declare float @llvm.fabs.f32(float %f) 12 13; Test addition followed by EQ, which can use the CC result of the addition. 14define float @f1(float %a, float %b, ptr %dest) #0 { 15; CHECK-LABEL: f1: 16; CHECK: aebr %f0, %f2 17; CHECK-NEXT: ber %r14 18; CHECK: br %r14 19entry: 20 %res = call float @llvm.experimental.constrained.fadd.f32( 21 float %a, float %b, 22 metadata !"round.dynamic", 23 metadata !"fpexcept.strict") #0 24 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 25 float %res, float 0.0, 26 metadata !"oeq", 27 metadata !"fpexcept.strict") #0 28 br i1 %cmp, label %exit, label %store 29 30store: 31 store float %b, ptr %dest 32 br label %exit 33 34exit: 35 ret float %res 36} 37 38; ...and again with LT. 39define float @f2(float %a, float %b, ptr %dest) #0 { 40; CHECK-LABEL: f2: 41; CHECK: aebr %f0, %f2 42; CHECK-NEXT: blr %r14 43; CHECK: br %r14 44entry: 45 %res = call float @llvm.experimental.constrained.fadd.f32( 46 float %a, float %b, 47 metadata !"round.dynamic", 48 metadata !"fpexcept.strict") #0 49 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 50 float %res, float 0.0, 51 metadata !"olt", 52 metadata !"fpexcept.strict") #0 53 br i1 %cmp, label %exit, label %store 54 55store: 56 store float %b, ptr %dest 57 br label %exit 58 59exit: 60 ret float %res 61} 62 63; ...and again with GT. 64define float @f3(float %a, float %b, ptr %dest) #0 { 65; CHECK-LABEL: f3: 66; CHECK: aebr %f0, %f2 67; CHECK-NEXT: bhr %r14 68; CHECK: br %r14 69entry: 70 %res = call float @llvm.experimental.constrained.fadd.f32( 71 float %a, float %b, 72 metadata !"round.dynamic", 73 metadata !"fpexcept.strict") #0 74 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 75 float %res, float 0.0, 76 metadata !"ogt", 77 metadata !"fpexcept.strict") #0 78 br i1 %cmp, label %exit, label %store 79 80store: 81 store float %b, ptr %dest 82 br label %exit 83 84exit: 85 ret float %res 86} 87 88; ...and again with UEQ. 89define float @f4(float %a, float %b, ptr %dest) #0 { 90; CHECK-LABEL: f4: 91; CHECK: aebr %f0, %f2 92; CHECK-NEXT: bnlhr %r14 93; CHECK: br %r14 94entry: 95 %res = call float @llvm.experimental.constrained.fadd.f32( 96 float %a, float %b, 97 metadata !"round.dynamic", 98 metadata !"fpexcept.strict") #0 99 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 100 float %res, float 0.0, 101 metadata !"ueq", 102 metadata !"fpexcept.strict") #0 103 br i1 %cmp, label %exit, label %store 104 105store: 106 store float %b, ptr %dest 107 br label %exit 108 109exit: 110 ret float %res 111} 112 113; Subtraction also provides a zero-based CC value. 114define float @f5(float %a, float %b, ptr %dest) #0 { 115; CHECK-LABEL: f5: 116; CHECK: seb %f0, 0(%r2) 117; CHECK-NEXT: bnher %r14 118; CHECK: br %r14 119entry: 120 %cur = load float, ptr %dest 121 %res = call float @llvm.experimental.constrained.fsub.f32( 122 float %a, float %cur, 123 metadata !"round.dynamic", 124 metadata !"fpexcept.strict") #0 125 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 126 float %res, float 0.0, 127 metadata !"ult", 128 metadata !"fpexcept.strict") #0 129 br i1 %cmp, label %exit, label %store 130 131store: 132 store float %b, ptr %dest 133 br label %exit 134 135exit: 136 ret float %res 137} 138 139; Test the result of LOAD POSITIVE. We cannot omit the LTEBR. 140define float @f6(float %dummy, float %a, ptr %dest) #0 { 141; CHECK-LABEL: f6: 142; CHECK: lpdfr %f0, %f2 143; CHECK-NEXT: ltebr %f1, %f0 144; CHECK-NEXT: bhr %r14 145; CHECK: br %r14 146entry: 147 %res = call float @llvm.fabs.f32(float %a) #0 148 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 149 float %res, float 0.0, 150 metadata !"ogt", 151 metadata !"fpexcept.strict") #0 152 br i1 %cmp, label %exit, label %store 153 154store: 155 store float %res, ptr %dest 156 br label %exit 157 158exit: 159 ret float %res 160} 161 162; Test the result of LOAD NEGATIVE. We cannot omit the LTEBR. 163define float @f7(float %dummy, float %a, ptr %dest) #0 { 164; CHECK-LABEL: f7: 165; CHECK: lndfr %f0, %f2 166; CHECK-NEXT: ltebr %f1, %f0 167; CHECK-NEXT: blr %r14 168; CHECK: br %r14 169entry: 170 %abs = call float @llvm.fabs.f32(float %a) #0 171 %res = fneg float %abs 172 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 173 float %res, float 0.0, 174 metadata !"olt", 175 metadata !"fpexcept.strict") #0 176 br i1 %cmp, label %exit, label %store 177 178store: 179 store float %res, ptr %dest 180 br label %exit 181 182exit: 183 ret float %res 184} 185 186; Test the result of LOAD COMPLEMENT. We cannot omit the LTEBR. 187define float @f8(float %dummy, float %a, ptr %dest) #0 { 188; CHECK-LABEL: f8: 189; CHECK: lcdfr %f0, %f2 190; CHECK-NEXT: ltebr %f1, %f0 191; CHECK-NEXT: bler %r14 192; CHECK: br %r14 193entry: 194 %res = fneg float %a 195 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 196 float %res, float 0.0, 197 metadata !"ole", 198 metadata !"fpexcept.strict") #0 199 br i1 %cmp, label %exit, label %store 200 201store: 202 store float %res, ptr %dest 203 br label %exit 204 205exit: 206 ret float %res 207} 208 209; Multiplication (for example) does not modify CC. 210define float @f9(float %a, float %b, ptr %dest) #0 { 211; CHECK-LABEL: f9: 212; CHECK: meebr %f0, %f2 213; CHECK-NEXT: ltebr %f1, %f0 214; CHECK-NEXT: blhr %r14 215; CHECK: br %r14 216entry: 217 %res = call float @llvm.experimental.constrained.fmul.f32( 218 float %a, float %b, 219 metadata !"round.dynamic", 220 metadata !"fpexcept.strict") #0 221 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 222 float %res, float 0.0, 223 metadata !"one", 224 metadata !"fpexcept.strict") #0 225 br i1 %cmp, label %exit, label %store 226 227store: 228 store float %b, ptr %dest 229 br label %exit 230 231exit: 232 ret float %res 233} 234 235; Test a combination involving a CC-setting instruction followed by 236; a non-CC-setting instruction. 237define float @f10(float %a, float %b, float %c, ptr %dest) #0 { 238; CHECK-LABEL: f10: 239; CHECK: aebr %f0, %f2 240; CHECK-NEXT: debr %f0, %f4 241; CHECK-NEXT: ltebr %f1, %f0 242; CHECK-NEXT: bner %r14 243; CHECK: br %r14 244entry: 245 %add = call float @llvm.experimental.constrained.fadd.f32( 246 float %a, float %b, 247 metadata !"round.dynamic", 248 metadata !"fpexcept.strict") #0 249 %res = call float @llvm.experimental.constrained.fdiv.f32( 250 float %add, float %c, 251 metadata !"round.dynamic", 252 metadata !"fpexcept.strict") #0 253 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 254 float %res, float 0.0, 255 metadata !"une", 256 metadata !"fpexcept.strict") #0 257 br i1 %cmp, label %exit, label %store 258 259store: 260 store float %b, ptr %dest 261 br label %exit 262 263exit: 264 ret float %res 265} 266 267; Test a case where CC is set based on a different register from the 268; compare input. 269define float @f11(float %a, float %b, float %c, ptr %dest1, ptr %dest2) #0 { 270; CHECK-LABEL: f11: 271; CHECK: aebr %f0, %f2 272; CHECK-NEXT: sebr %f4, %f0 273; CHECK-DAG: ste %f4, 0(%r2) 274; CHECK-DAG: ltebr %f1, %f0 275; CHECK-NEXT: ber %r14 276; CHECK: br %r14 277entry: 278 %add = call float @llvm.experimental.constrained.fadd.f32( 279 float %a, float %b, 280 metadata !"round.dynamic", 281 metadata !"fpexcept.strict") #0 282 %sub = call float @llvm.experimental.constrained.fsub.f32( 283 float %c, float %add, 284 metadata !"round.dynamic", 285 metadata !"fpexcept.strict") #0 286 store float %sub, ptr %dest1 287 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 288 float %add, float 0.0, 289 metadata !"oeq", 290 metadata !"fpexcept.strict") #0 291 br i1 %cmp, label %exit, label %store 292 293store: 294 store float %sub, ptr %dest2 295 br label %exit 296 297exit: 298 ret float %add 299} 300 301; Test that LER does not get converted to LTEBR as %f0 is live after it. 302define float @f12(float %dummy, float %val) #0 { 303; CHECK-LABEL: f12: 304; CHECK: ler %f0, %f2 305; CHECK-NEXT: #APP 306; CHECK-NEXT: blah %f0 307; CHECK-NEXT: #NO_APP 308; CHECK-NEXT: ltebr %f1, %f2 309; CHECK-NEXT: blr %r14 310; CHECK: br %r14 311entry: 312 %ret = call float asm "blah $1", "=f,{f0}"(float %val) #0 313 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 314 float %val, float 0.0, 315 metadata !"olt", 316 metadata !"fpexcept.strict") #0 317 br i1 %cmp, label %exit, label %store 318 319store: 320 call void asm sideeffect "blah", ""() #0 321 br label %exit 322 323exit: 324 ret float %ret 325} 326 327; Test that LDR does not get converted to LTDBR as %f0 is live after it. 328define double @f13(double %dummy, double %val) #0 { 329; CHECK-LABEL: f13: 330; CHECK: ldr %f0, %f2 331; CHECK-NEXT: #APP 332; CHECK-NEXT: blah %f0 333; CHECK-NEXT: #NO_APP 334; CHECK-NEXT: ltdbr %f1, %f2 335; CHECK-NEXT: blr %r14 336; CHECK: br %r14 337entry: 338 %ret = call double asm "blah $1", "=f,{f0}"(double %val) #0 339 %cmp = call i1 @llvm.experimental.constrained.fcmp.f64( 340 double %val, double 0.0, 341 metadata !"olt", 342 metadata !"fpexcept.strict") #0 343 br i1 %cmp, label %exit, label %store 344 345store: 346 call void asm sideeffect "blah", ""() #0 347 br label %exit 348 349exit: 350 ret double %ret 351} 352 353; Test that LXR does not get converted to LTXBR as %f4 is live after it. 354define void @f14(ptr %ptr1, ptr %ptr2) #0 { 355; CHECK-LABEL: f14: 356; CHECK: lxr 357; CHECK-NEXT: dxbr 358; CHECK-NEXT: std 359; CHECK-NEXT: std 360; CHECK-NEXT: mxbr 361; CHECK-NEXT: std 362; CHECK-NEXT: std 363; CHECK-NEXT: ltxbr 364; CHECK-NEXT: blr %r14 365; CHECK: br %r14 366entry: 367 %val1 = load fp128, ptr %ptr1 368 %val2 = load fp128, ptr %ptr2 369 %div = fdiv fp128 %val1, %val2 370 store fp128 %div, ptr %ptr1 371 %mul = fmul fp128 %val1, %val2 372 store fp128 %mul, ptr %ptr2 373 %cmp = call i1 @llvm.experimental.constrained.fcmp.f128( 374 fp128 %val1, fp128 0xL00000000000000000000000000000000, 375 metadata !"olt", 376 metadata !"fpexcept.strict") #0 377 br i1 %cmp, label %exit, label %store 378 379store: 380 call void asm sideeffect "blah", ""() #0 381 br label %exit 382 383exit: 384 ret void 385} 386 387; Test a case where it is the source rather than destination of LER that 388; we need, but cannot convert the LER. 389define float @f15(float %val, float %dummy) #0 { 390; CHECK-LABEL: f15: 391; CHECK: ler %f2, %f0 392; CHECK-NEXT: #APP 393; CHECK-NEXT: blah %f2 394; CHECK-NEXT: #NO_APP 395; CHECK-NEXT: ltebr %f1, %f2 396; CHECK-NEXT: blr %r14 397; CHECK: br %r14 398entry: 399 %ret = call float asm "blah $1", "=f,{f2}"(float %val) #0 400 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 401 float %val, float 0.0, 402 metadata !"olt", 403 metadata !"fpexcept.strict") #0 404 br i1 %cmp, label %exit, label %store 405 406store: 407 call void asm sideeffect "blah", ""() #0 408 br label %exit 409 410exit: 411 ret float %ret 412} 413 414; Test a case where it is the source rather than destination of LDR that 415; we need, but cannot convert the LDR. 416define double @f16(double %val, double %dummy) #0 { 417; CHECK-LABEL: f16: 418; CHECK: ldr %f2, %f0 419; CHECK-NEXT: #APP 420; CHECK-NEXT: blah %f2 421; CHECK-NEXT: #NO_APP 422; CHECK-NEXT: ltdbr %f1, %f2 423; CHECK-NEXT: blr %r14 424; CHECK: br %r14 425entry: 426 %ret = call double asm "blah $1", "=f,{f2}"(double %val) #0 427 %cmp = call i1 @llvm.experimental.constrained.fcmp.f64( 428 double %val, double 0.0, 429 metadata !"olt", 430 metadata !"fpexcept.strict") #0 431 br i1 %cmp, label %exit, label %store 432 433store: 434 call void asm sideeffect "blah", ""() #0 435 br label %exit 436 437exit: 438 ret double %ret 439} 440 441; Repeat f2 with a comparison against -0. 442define float @f17(float %a, float %b, ptr %dest) #0 { 443; CHECK-LABEL: f17: 444; CHECK: aebr %f0, %f2 445; CHECK-NEXT: blr %r14 446; CHECK: br %r14 447entry: 448 %res = call float @llvm.experimental.constrained.fadd.f32( 449 float %a, float %b, 450 metadata !"round.dynamic", 451 metadata !"fpexcept.strict") #0 452 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 453 float %res, float -0.0, 454 metadata !"olt", 455 metadata !"fpexcept.strict") #0 456 br i1 %cmp, label %exit, label %store 457 458store: 459 store float %b, ptr %dest 460 br label %exit 461 462exit: 463 ret float %res 464} 465 466; Verify that we cannot omit the compare if there may be an intervening 467; change to the exception flags. 468define float @f18(float %a, float %b, ptr %dest) #0 { 469; CHECK-LABEL: f18: 470; CHECK: aebr %f0, %f2 471; CHECK: ltebr %f1, %f0 472; CHECK-NEXT: ber %r14 473; CHECK: br %r14 474entry: 475 %res = call float @llvm.experimental.constrained.fadd.f32( 476 float %a, float %b, 477 metadata !"round.dynamic", 478 metadata !"fpexcept.strict") #0 479 call void asm sideeffect "blah", ""() #0 480 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 481 float %res, float 0.0, 482 metadata !"oeq", 483 metadata !"fpexcept.strict") #0 484 br i1 %cmp, label %exit, label %store 485 486store: 487 store float %b, ptr %dest 488 br label %exit 489 490exit: 491 ret float %res 492} 493 494; Verify that we cannot convert LER to LTEBR and omit the compare if 495; there may be an intervening change to the exception flags. 496define float @f19(float %dummy, float %val) #0 { 497; CHECK-LABEL: f19: 498; CHECK: ler %f0, %f2 499; CHECK-NEXT: #APP 500; CHECK-NEXT: blah %f0 501; CHECK-NEXT: #NO_APP 502; CHECK-NEXT: ltebr %f1, %f2 503; CHECK-NEXT: blr %r14 504; CHECK: br %r14 505entry: 506 %ret = call float asm sideeffect "blah $1", "=f,{f0}"(float %val) #0 507 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32( 508 float %val, float 0.0, 509 metadata !"olt", 510 metadata !"fpexcept.strict") #0 511 br i1 %cmp, label %exit, label %store 512 513store: 514 call void asm sideeffect "blah", ""() #0 515 br label %exit 516 517exit: 518 ret float %ret 519} 520 521attributes #0 = { strictfp } 522 523declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) 524declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) 525declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) 526declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) 527declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata) 528declare i1 @llvm.experimental.constrained.fcmp.f64(double, double, metadata, metadata) 529declare i1 @llvm.experimental.constrained.fcmp.f128(fp128, fp128, metadata, metadata) 530