diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 140c97ccd90ba..6fd23b5ab9f5f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -8556,11 +8556,12 @@ static std::optional isFCmpEqualZero(FPClassTest Test, } SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op, - FPClassTest Test, SDNodeFlags Flags, - const SDLoc &DL, + const FPClassTest OrigTestMask, + SDNodeFlags Flags, const SDLoc &DL, SelectionDAG &DAG) const { EVT OperandVT = Op.getValueType(); assert(OperandVT.isFloatingPoint()); + FPClassTest Test = OrigTestMask; // Degenerated cases. if (Test == fcNone) @@ -8594,9 +8595,21 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op, // exceptions are ignored. if (Flags.hasNoFPExcept() && isOperationLegalOrCustom(ISD::SETCC, OperandVT.getScalarType())) { + FPClassTest FPTestMask = Test; + ISD::CondCode OrderedCmpOpcode = IsInverted ? ISD::SETUNE : ISD::SETOEQ; ISD::CondCode UnorderedCmpOpcode = IsInverted ? ISD::SETONE : ISD::SETUEQ; + // See if we can fold an | fcNan into an unordered compare. + FPClassTest OrderedFPTestMask = FPTestMask & ~fcNan; + + // Can't fold the ordered check if we're only testing for snan or qnan + // individually. + if ((FPTestMask & fcNan) != fcNan) + OrderedFPTestMask = FPTestMask; + + const bool IsOrdered = FPTestMask == OrderedFPTestMask; + if (std::optional IsCmp0 = isFCmpEqualZero(Test, Semantics, DAG.getMachineFunction()); IsCmp0 && (isCondCodeLegalOrCustom( @@ -8628,6 +8641,27 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op, return DAG.getSetCC(DL, ResultVT, Abs, Inf, IsInverted ? ISD::SETUNE : ISD::SETOEQ); } + + if (OrderedFPTestMask == (fcSubnormal | fcZero) && !IsOrdered) { + // TODO: Could handle ordered case, but it produces worse code for + // x86. Maybe handle ordered if fabs is free? + + ISD::CondCode OrderedOp = IsInverted ? ISD::SETUGE : ISD::SETOLT; + ISD::CondCode UnorderedOp = IsInverted ? ISD::SETOGE : ISD::SETULT; + + if (isCondCodeLegalOrCustom(IsOrdered ? OrderedOp : UnorderedOp, + OperandVT.getScalarType().getSimpleVT())) { + // (issubnormal(x) || iszero(x)) --> fabs(x) < smallest_normal + + // TODO: Maybe only makes sense if fabs is free. Integer test of + // exponent bits seems better for x86. + SDValue Abs = DAG.getNode(ISD::FABS, DL, OperandVT, Op); + SDValue SmallestNormal = DAG.getConstantFP( + APFloat::getSmallestNormalized(Semantics), DL, OperandVT); + return DAG.getSetCC(DL, ResultVT, Abs, SmallestNormal, + IsOrdered ? OrderedOp : UnorderedOp); + } + } } // In the general case use integer operations. diff --git a/llvm/test/CodeGen/X86/is_fpclass.ll b/llvm/test/CodeGen/X86/is_fpclass.ll index 532b2c09a9175..cc4d4c4543a51 100644 --- a/llvm/test/CodeGen/X86/is_fpclass.ll +++ b/llvm/test/CodeGen/X86/is_fpclass.ll @@ -2602,24 +2602,22 @@ define i1 @issubnormal_or_nan_f(float %x) { define i1 @issubnormal_or_zero_or_nan_f(float %x) { ; X86-LABEL: issubnormal_or_zero_or_nan_f: ; X86: # %bb.0: -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: testl $2139095040, %eax # imm = 0x7F800000 -; X86-NEXT: sete %cl -; X86-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; X86-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001 -; X86-NEXT: setge %al -; X86-NEXT: orb %cl, %al +; X86-NEXT: flds {{[0-9]+}}(%esp) +; X86-NEXT: fabs +; X86-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}} +; X86-NEXT: fxch %st(1) +; X86-NEXT: fucompp +; X86-NEXT: fnstsw %ax +; X86-NEXT: # kill: def $ah killed $ah killed $ax +; X86-NEXT: sahf +; X86-NEXT: setb %al ; X86-NEXT: retl ; ; X64-LABEL: issubnormal_or_zero_or_nan_f: ; X64: # %bb.0: -; X64-NEXT: movd %xmm0, %eax -; X64-NEXT: testl $2139095040, %eax # imm = 0x7F800000 -; X64-NEXT: sete %cl -; X64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; X64-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001 -; X64-NEXT: setge %al -; X64-NEXT: orb %cl, %al +; X64-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; X64-NEXT: ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; X64-NEXT: setb %al ; X64-NEXT: retq %class = tail call i1 @llvm.is.fpclass.f32(float %x, i32 243) ; 0xf0|0x3 = "subnormal|zero|nan" ret i1 %class @@ -2773,24 +2771,22 @@ define i1 @not_issubnormal_or_nan_f(float %x) { define i1 @not_issubnormal_or_zero_or_nan_f(float %x) { ; X86-LABEL: not_issubnormal_or_zero_or_nan_f: ; X86: # %bb.0: -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: testl $2139095040, %eax # imm = 0x7F800000 -; X86-NEXT: setne %cl -; X86-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; X86-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001 -; X86-NEXT: setl %al -; X86-NEXT: andb %cl, %al +; X86-NEXT: flds {{[0-9]+}}(%esp) +; X86-NEXT: fabs +; X86-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}} +; X86-NEXT: fxch %st(1) +; X86-NEXT: fucompp +; X86-NEXT: fnstsw %ax +; X86-NEXT: # kill: def $ah killed $ah killed $ax +; X86-NEXT: sahf +; X86-NEXT: setae %al ; X86-NEXT: retl ; ; X64-LABEL: not_issubnormal_or_zero_or_nan_f: ; X64: # %bb.0: -; X64-NEXT: movd %xmm0, %eax -; X64-NEXT: testl $2139095040, %eax # imm = 0x7F800000 -; X64-NEXT: setne %cl -; X64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; X64-NEXT: cmpl $2139095041, %eax # imm = 0x7F800001 -; X64-NEXT: setl %al -; X64-NEXT: andb %cl, %al +; X64-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; X64-NEXT: ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; X64-NEXT: setae %al ; X64-NEXT: retq %class = tail call i1 @llvm.is.fpclass.f32(float %x, i32 780) ; ~(0xf0|0x3) = ~"subnormal|zero|nan" ret i1 %class