642 lines · plain
1; Test that floating-point strict compares are omitted if CC already has the2; right value.3;4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 \5; RUN: -enable-misched=0 -no-integrated-as | FileCheck %s6;7; We need -enable-misched=0 to make sure f12 and following routines really8; 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, %f217; CHECK-NEXT: ber %r1418; CHECK: br %r1419entry:20 %res = call float @llvm.experimental.constrained.fadd.f32(21 float %a, float %b,22 metadata !"round.dynamic",23 metadata !"fpexcept.strict") #024 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(25 float %res, float 0.0,26 metadata !"oeq",27 metadata !"fpexcept.strict") #028 br i1 %cmp, label %exit, label %store29 30store:31 store float %b, ptr %dest32 br label %exit33 34exit:35 ret float %res36}37 38; ...and again with LT.39define float @f2(float %a, float %b, ptr %dest) #0 {40; CHECK-LABEL: f2:41; CHECK: aebr %f0, %f242; CHECK-NEXT: blr %r1443; CHECK: br %r1444entry:45 %res = call float @llvm.experimental.constrained.fadd.f32(46 float %a, float %b,47 metadata !"round.dynamic",48 metadata !"fpexcept.strict") #049 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(50 float %res, float 0.0,51 metadata !"olt",52 metadata !"fpexcept.strict") #053 br i1 %cmp, label %exit, label %store54 55store:56 store float %b, ptr %dest57 br label %exit58 59exit:60 ret float %res61}62 63; ...and again with GT.64define float @f3(float %a, float %b, ptr %dest) #0 {65; CHECK-LABEL: f3:66; CHECK: aebr %f0, %f267; CHECK-NEXT: bhr %r1468; CHECK: br %r1469entry:70 %res = call float @llvm.experimental.constrained.fadd.f32(71 float %a, float %b,72 metadata !"round.dynamic",73 metadata !"fpexcept.strict") #074 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(75 float %res, float 0.0,76 metadata !"ogt",77 metadata !"fpexcept.strict") #078 br i1 %cmp, label %exit, label %store79 80store:81 store float %b, ptr %dest82 br label %exit83 84exit:85 ret float %res86}87 88; ...and again with UEQ.89define float @f4(float %a, float %b, ptr %dest) #0 {90; CHECK-LABEL: f4:91; CHECK: aebr %f0, %f292; CHECK-NEXT: bnlhr %r1493; CHECK: br %r1494entry:95 %res = call float @llvm.experimental.constrained.fadd.f32(96 float %a, float %b,97 metadata !"round.dynamic",98 metadata !"fpexcept.strict") #099 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(100 float %res, float 0.0,101 metadata !"ueq",102 metadata !"fpexcept.strict") #0103 br i1 %cmp, label %exit, label %store104 105store:106 store float %b, ptr %dest107 br label %exit108 109exit:110 ret float %res111}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 %r14118; CHECK: br %r14119entry:120 %cur = load float, ptr %dest121 %res = call float @llvm.experimental.constrained.fsub.f32(122 float %a, float %cur,123 metadata !"round.dynamic",124 metadata !"fpexcept.strict") #0125 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(126 float %res, float 0.0,127 metadata !"ult",128 metadata !"fpexcept.strict") #0129 br i1 %cmp, label %exit, label %store130 131store:132 store float %b, ptr %dest133 br label %exit134 135exit:136 ret float %res137}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, %f2143; CHECK-NEXT: ltebr %f1, %f0144; CHECK-NEXT: bhr %r14145; CHECK: br %r14146entry:147 %res = call float @llvm.fabs.f32(float %a) #0148 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(149 float %res, float 0.0,150 metadata !"ogt",151 metadata !"fpexcept.strict") #0152 br i1 %cmp, label %exit, label %store153 154store:155 store float %res, ptr %dest156 br label %exit157 158exit:159 ret float %res160}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, %f2166; CHECK-NEXT: ltebr %f1, %f0167; CHECK-NEXT: blr %r14168; CHECK: br %r14169entry:170 %abs = call float @llvm.fabs.f32(float %a) #0171 %res = fneg float %abs172 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(173 float %res, float 0.0,174 metadata !"olt",175 metadata !"fpexcept.strict") #0176 br i1 %cmp, label %exit, label %store177 178store:179 store float %res, ptr %dest180 br label %exit181 182exit:183 ret float %res184}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, %f2190; CHECK-NEXT: ltebr %f1, %f0191; CHECK-NEXT: bler %r14192; CHECK: br %r14193entry:194 %res = fneg float %a195 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(196 float %res, float 0.0,197 metadata !"ole",198 metadata !"fpexcept.strict") #0199 br i1 %cmp, label %exit, label %store200 201store:202 store float %res, ptr %dest203 br label %exit204 205exit:206 ret float %res207}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, %f2213; CHECK-NEXT: ltebr %f1, %f0214; CHECK-NEXT: blhr %r14215; CHECK: br %r14216entry:217 %res = call float @llvm.experimental.constrained.fmul.f32(218 float %a, float %b,219 metadata !"round.dynamic",220 metadata !"fpexcept.strict") #0221 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(222 float %res, float 0.0,223 metadata !"one",224 metadata !"fpexcept.strict") #0225 br i1 %cmp, label %exit, label %store226 227store:228 store float %b, ptr %dest229 br label %exit230 231exit:232 ret float %res233}234 235; Test a combination involving a CC-setting instruction followed by236; 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, %f2240; CHECK-NEXT: debr %f0, %f4241; CHECK-NEXT: ltebr %f1, %f0242; CHECK-NEXT: bner %r14243; CHECK: br %r14244entry:245 %add = call float @llvm.experimental.constrained.fadd.f32(246 float %a, float %b,247 metadata !"round.dynamic",248 metadata !"fpexcept.strict") #0249 %res = call float @llvm.experimental.constrained.fdiv.f32(250 float %add, float %c,251 metadata !"round.dynamic",252 metadata !"fpexcept.strict") #0253 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(254 float %res, float 0.0,255 metadata !"une",256 metadata !"fpexcept.strict") #0257 br i1 %cmp, label %exit, label %store258 259store:260 store float %b, ptr %dest261 br label %exit262 263exit:264 ret float %res265}266 267; Test a case where CC is set based on a different register from the268; compare input.269define float @f11(float %a, float %b, float %c, ptr %dest1, ptr %dest2) #0 {270; CHECK-LABEL: f11:271; CHECK: aebr %f0, %f2272; CHECK-NEXT: sebr %f4, %f0273; CHECK-DAG: ste %f4, 0(%r2)274; CHECK-DAG: ltebr %f1, %f0275; CHECK-NEXT: ber %r14276; CHECK: br %r14277entry:278 %add = call float @llvm.experimental.constrained.fadd.f32(279 float %a, float %b,280 metadata !"round.dynamic",281 metadata !"fpexcept.strict") #0282 %sub = call float @llvm.experimental.constrained.fsub.f32(283 float %c, float %add,284 metadata !"round.dynamic",285 metadata !"fpexcept.strict") #0286 store float %sub, ptr %dest1287 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(288 float %add, float 0.0,289 metadata !"oeq",290 metadata !"fpexcept.strict") #0291 br i1 %cmp, label %exit, label %store292 293store:294 store float %sub, ptr %dest2295 br label %exit296 297exit:298 ret float %add299}300 301define half @f12_half(half %dummy, half %val) #0 {302; CHECK-LABEL: f12_half:303; CHECK: ler %f9, %f2304; CHECK-NEXT: ler %f0, %f2305; CHECK-NEXT: #APP306; CHECK-NEXT: ler %f8, %f0307; CHECK-NEXT: #NO_APP308; CHECK-NEXT: lzer %f0309; CHECK-NEXT: brasl %r14, __extendhfsf2@PLT310; CHECK-NEXT: ler %f10, %f0311; CHECK-NEXT: ler %f0, %f9312; CHECK-NEXT: brasl %r14, __extendhfsf2@PLT313; CHECK-NEXT: cebr %f0, %f10314; CHECK-NEXT: jl .LBB11_2315; CHECK-NEXT:# %bb.1: # %store316; CHECK-NEXT: #APP317; CHECK-NEXT: blah318; CHECK-NEXT: #NO_APP319; CHECK-NEXT:.LBB11_2: # %exit320; CHECK-NEXT: ler %f0, %f8321; CHECK: br %r14322entry:323 %ret = call half asm "ler $0, $1", "=f,{f0}"(half %val) #0324 %cmp = call i1 @llvm.experimental.constrained.fcmp.f16(325 half %val, half 0.0,326 metadata !"olt",327 metadata !"fpexcept.strict") #0328 br i1 %cmp, label %exit, label %store329 330store:331 call void asm sideeffect "blah", ""() #0332 br label %exit333 334exit:335 ret half %ret336}337 338; Test that LER does not get converted to LTEBR as %f0 is live after it.339define float @f12(float %dummy, float %val) #0 {340; CHECK-LABEL: f12:341; CHECK: ler %f0, %f2342; CHECK-NEXT: #APP343; CHECK-NEXT: blah %f0344; CHECK-NEXT: #NO_APP345; CHECK-NEXT: ltebr %f1, %f2346; CHECK-NEXT: blr %r14347; CHECK: br %r14348entry:349 %ret = call float asm "$0 = blah $1", "=f,{f0}"(float %val) #0350 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(351 float %val, float 0.0,352 metadata !"olt",353 metadata !"fpexcept.strict") #0354 br i1 %cmp, label %exit, label %store355 356store:357 call void asm sideeffect "blah", ""() #0358 br label %exit359 360exit:361 ret float %ret362}363 364; Test that LDR does not get converted to LTDBR as %f0 is live after it.365define double @f13(double %dummy, double %val) #0 {366; CHECK-LABEL: f13:367; CHECK: ldr %f0, %f2368; CHECK-NEXT: #APP369; CHECK-NEXT: blah %f0370; CHECK-NEXT: #NO_APP371; CHECK-NEXT: ltdbr %f1, %f2372; CHECK-NEXT: blr %r14373; CHECK: br %r14374entry:375 %ret = call double asm "blah $1", "=f,{f0}"(double %val) #0376 %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(377 double %val, double 0.0,378 metadata !"olt",379 metadata !"fpexcept.strict") #0380 br i1 %cmp, label %exit, label %store381 382store:383 call void asm sideeffect "blah", ""() #0384 br label %exit385 386exit:387 ret double %ret388}389 390; Test that LXR does not get converted to LTXBR as %f4 is live after it.391define void @f14(ptr %ptr1, ptr %ptr2) #0 {392; CHECK-LABEL: f14:393; CHECK: lxr394; CHECK-NEXT: dxbr395; CHECK-NEXT: std396; CHECK-NEXT: std397; CHECK-NEXT: mxbr398; CHECK-NEXT: std399; CHECK-NEXT: std400; CHECK-NEXT: ltxbr401; CHECK-NEXT: blr %r14402; CHECK: br %r14403entry:404 %val1 = load fp128, ptr %ptr1405 %val2 = load fp128, ptr %ptr2406 %div = fdiv fp128 %val1, %val2407 store fp128 %div, ptr %ptr1408 %mul = fmul fp128 %val1, %val2409 store fp128 %mul, ptr %ptr2410 %cmp = call i1 @llvm.experimental.constrained.fcmp.f128(411 fp128 %val1, fp128 0xL00000000000000000000000000000000,412 metadata !"olt",413 metadata !"fpexcept.strict") #0414 br i1 %cmp, label %exit, label %store415 416store:417 call void asm sideeffect "blah", ""() #0418 br label %exit419 420exit:421 ret void422}423 424define half @f15_half(half %val, half %dummy) #0 {425; CHECK-LABEL: f15_half:426; CHECK: ler %f9, %f0427; CHECK-NEXT: ler %f2, %f0428; CHECK-NEXT: #APP429; CHECK-NEXT: ler %f8, %f2430; CHECK-NEXT: #NO_APP431; CHECK-NEXT: lzer %f0432; CHECK-NEXT: brasl %r14, __extendhfsf2@PLT433; CHECK-NEXT: ler %f10, %f0434; CHECK-NEXT: ler %f0, %f9435; CHECK-NEXT: brasl %r14, __extendhfsf2@PLT436; CHECK-NEXT: cebr %f0, %f10437; CHECK-NEXT: jl .LBB15_2438; CHECK-NEXT:# %bb.1: # %store439; CHECK-NEXT: #APP440; CHECK-NEXT: blah441; CHECK-NEXT: #NO_APP442; CHECK-NEXT:.LBB15_2: # %exit443; CHECK-NEXT: ler %f0, %f8444; CHECK: br %r14445entry:446 %ret = call half asm "ler $0, $1", "=f,{f2}"(half %val) #0447 %cmp = call i1 @llvm.experimental.constrained.fcmp.f16(448 half %val, half 0.0,449 metadata !"olt",450 metadata !"fpexcept.strict") #0451 br i1 %cmp, label %exit, label %store452 453store:454 call void asm sideeffect "blah", ""() #0455 br label %exit456 457exit:458 ret half %ret459}460 461; Test a case where it is the source rather than destination of LER that462; we need, but cannot convert the LER.463define float @f15(float %val, float %dummy) #0 {464; CHECK-LABEL: f15:465; CHECK: ler %f2, %f0466; CHECK-NEXT: #APP467; CHECK-NEXT: blah %f2468; CHECK-NEXT: #NO_APP469; CHECK-NEXT: ltebr %f1, %f2470; CHECK-NEXT: blr %r14471; CHECK: br %r14472entry:473 %ret = call float asm "blah $1", "=f,{f2}"(float %val) #0474 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(475 float %val, float 0.0,476 metadata !"olt",477 metadata !"fpexcept.strict") #0478 br i1 %cmp, label %exit, label %store479 480store:481 call void asm sideeffect "blah", ""() #0482 br label %exit483 484exit:485 ret float %ret486}487 488; Test a case where it is the source rather than destination of LDR that489; we need, but cannot convert the LDR.490define double @f16(double %val, double %dummy) #0 {491; CHECK-LABEL: f16:492; CHECK: ldr %f2, %f0493; CHECK-NEXT: #APP494; CHECK-NEXT: blah %f2495; CHECK-NEXT: #NO_APP496; CHECK-NEXT: ltdbr %f1, %f2497; CHECK-NEXT: blr %r14498; CHECK: br %r14499entry:500 %ret = call double asm "blah $1", "=f,{f2}"(double %val) #0501 %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(502 double %val, double 0.0,503 metadata !"olt",504 metadata !"fpexcept.strict") #0505 br i1 %cmp, label %exit, label %store506 507store:508 call void asm sideeffect "blah", ""() #0509 br label %exit510 511exit:512 ret double %ret513}514 515; Repeat f2 with a comparison against -0.516define float @f17(float %a, float %b, ptr %dest) #0 {517; CHECK-LABEL: f17:518; CHECK: aebr %f0, %f2519; CHECK-NEXT: blr %r14520; CHECK: br %r14521entry:522 %res = call float @llvm.experimental.constrained.fadd.f32(523 float %a, float %b,524 metadata !"round.dynamic",525 metadata !"fpexcept.strict") #0526 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(527 float %res, float -0.0,528 metadata !"olt",529 metadata !"fpexcept.strict") #0530 br i1 %cmp, label %exit, label %store531 532store:533 store float %b, ptr %dest534 br label %exit535 536exit:537 ret float %res538}539 540; Verify that we cannot omit the compare if there may be an intervening541; change to the exception flags.542define float @f18(float %a, float %b, ptr %dest) #0 {543; CHECK-LABEL: f18:544; CHECK: aebr %f0, %f2545; CHECK: ltebr %f1, %f0546; CHECK-NEXT: ber %r14547; CHECK: br %r14548entry:549 %res = call float @llvm.experimental.constrained.fadd.f32(550 float %a, float %b,551 metadata !"round.dynamic",552 metadata !"fpexcept.strict") #0553 call void asm sideeffect "blah", ""() #0554 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(555 float %res, float 0.0,556 metadata !"oeq",557 metadata !"fpexcept.strict") #0558 br i1 %cmp, label %exit, label %store559 560store:561 store float %b, ptr %dest562 br label %exit563 564exit:565 ret float %res566}567 568define half @f19_half(half %dummy, half %val) #0 {569; CHECK-LABEL: f19_half:570; CHECK: ler %f9, %f2571; CHECK-NEXT: ler %f0, %f2572; CHECK-NEXT: #APP573; CHECK-NEXT: ler %f8, %f0574; CHECK-NEXT: #NO_APP575; CHECK-NEXT: lzer %f0576; CHECK-NEXT: brasl %r14, __extendhfsf2@PLT577; CHECK-NEXT: ler %f10, %f0578; CHECK-NEXT: ler %f0, %f9579; CHECK-NEXT: brasl %r14, __extendhfsf2@PLT580; CHECK-NEXT: cebr %f0, %f10581; CHECK-NEXT: jl .LBB20_2582; CHECK-NEXT:# %bb.1: # %store583; CHECK-NEXT: #APP584; CHECK-NEXT: blah585; CHECK-NEXT: #NO_APP586; CHECK-NEXT:.LBB20_2: # %exit587; CHECK-NEXT: ler %f0, %f8588; CHECK: br %r14589entry:590 %ret = call half asm sideeffect "ler $0, $1", "=f,{f0}"(half %val) #0591 %cmp = call i1 @llvm.experimental.constrained.fcmp.f16(592 half %val, half 0.0,593 metadata !"olt",594 metadata !"fpexcept.strict") #0595 br i1 %cmp, label %exit, label %store596 597store:598 call void asm sideeffect "blah", ""() #0599 br label %exit600 601exit:602 ret half %ret603}604 605; Verify that we cannot convert LER to LTEBR and omit the compare if606; there may be an intervening change to the exception flags.607define float @f19(float %dummy, float %val) #0 {608; CHECK-LABEL: f19:609; CHECK: ler %f0, %f2610; CHECK-NEXT: #APP611; CHECK-NEXT: blah %f0612; CHECK-NEXT: #NO_APP613; CHECK-NEXT: ltebr %f1, %f2614; CHECK-NEXT: blr %r14615; CHECK: br %r14616entry:617 %ret = call float asm sideeffect "blah $1", "=f,{f0}"(float %val) #0618 %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(619 float %val, float 0.0,620 metadata !"olt",621 metadata !"fpexcept.strict") #0622 br i1 %cmp, label %exit, label %store623 624store:625 call void asm sideeffect "blah", ""() #0626 br label %exit627 628exit:629 ret float %ret630}631 632attributes #0 = { strictfp }633 634declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)635declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata)636declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata)637declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata)638declare i1 @llvm.experimental.constrained.fcmp.f16(half, half, metadata, metadata)639declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata)640declare i1 @llvm.experimental.constrained.fcmp.f64(double, double, metadata, metadata)641declare i1 @llvm.experimental.constrained.fcmp.f128(fp128, fp128, metadata, metadata)642