Index: llvm/include/llvm/CodeGen/CodeGenCommonISel.h =================================================================== --- llvm/include/llvm/CodeGen/CodeGenCommonISel.h +++ llvm/include/llvm/CodeGen/CodeGenCommonISel.h @@ -222,9 +222,13 @@ /// (i.e. fewer instructions should be required to lower it). An example is the /// test "inf|normal|subnormal|zero", which is an inversion of "nan". /// \param Test The test as specified in 'is_fpclass' intrinsic invocation. +/// +/// \param UseFP The intention is to perform the comparison using floating-point +/// compare instructions which can nan tests. +/// /// \returns The inverted test, or fcNone, if inversion does not produce a /// simpler test. -FPClassTest invertFPClassTestIfSimpler(FPClassTest Test); +FPClassTest invertFPClassTestIfSimpler(FPClassTest Test, bool UseFP); /// Assuming the instruction \p MI is going to be deleted, attempt to salvage /// debug users of \p MI by writing the effect of \p MI in a DIExpression. Index: llvm/lib/CodeGen/CodeGenCommonISel.cpp =================================================================== --- llvm/lib/CodeGen/CodeGenCommonISel.cpp +++ llvm/lib/CodeGen/CodeGenCommonISel.cpp @@ -173,8 +173,9 @@ return SplitPoint; } -FPClassTest llvm::invertFPClassTestIfSimpler(FPClassTest Test) { +FPClassTest llvm::invertFPClassTestIfSimpler(FPClassTest Test, bool UseFP) { FPClassTest InvertedTest = static_cast(~Test & fcAllFlags); + // Pick the direction with fewer tests // TODO: Handle more combinations of cases that can be handled together switch (static_cast(InvertedTest)) { @@ -200,6 +201,14 @@ case fcSubnormal | fcZero: case fcSubnormal | fcZero | fcNan: return InvertedTest; + case fcInf | fcNan: + // If we're trying to use fcmp, we can take advantage of the nan check + // behavior of the compare (but this is more instructions in the integer + // expansion). + return UseFP ? InvertedTest : fcNone; + case fcFinite | fcNan: + // Inversion of fcInf, which can be done in a combined check. + return fcNone; default: return fcNone; } Index: llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -8031,11 +8031,12 @@ } SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op, - FPClassTest TestMask, + const FPClassTest OrigTestMask, SDNodeFlags Flags, const SDLoc &DL, SelectionDAG &DAG) const { EVT OperandVT = Op.getValueType(); assert(OperandVT.isFloatingPoint()); + FPClassTest TestMask = OrigTestMask; // Degenerated cases. if (TestMask == fcNone) @@ -8051,15 +8052,6 @@ OperandVT = MVT::f64; } - // Some checks may be represented as inversion of simpler check, for example - // "inf|normal|subnormal|zero" => !"nan". - bool IsInverted = false; - - if (FPClassTest InvertedCheck = invertFPClassTestIfSimpler(TestMask)) { - IsInverted = true; - TestMask = InvertedCheck; - } - // Floating-point type properties. EVT ScalarFloatVT = OperandVT.getScalarType(); const Type *FloatTy = ScalarFloatVT.getTypeForEVT(*DAG.getContext()); @@ -8071,10 +8063,20 @@ if (Flags.hasNoFPExcept() && // TODO: Should check isCondCodeLegal isOperationLegalOrCustom(ISD::SETCC, OperandVT.getScalarType())) { + FPClassTest FPTestMask = TestMask; + bool IsInvertedFP = false; + + if (FPClassTest InvertedFPCheck = + invertFPClassTestIfSimpler(FPTestMask, true)) { + FPTestMask = InvertedFPCheck; + IsInvertedFP = true; + } + if (std::optional IsCmp0 = - isFCmpEqualZero(TestMask, Semantics, DAG.getMachineFunction())) { - ISD::CondCode OrderedCmpOpcode = IsInverted ? ISD::SETONE : ISD::SETOEQ; - ISD::CondCode UnorderedCmpOpcode = IsInverted ? ISD::SETUNE : ISD::SETUEQ; + isFCmpEqualZero(FPTestMask, Semantics, DAG.getMachineFunction())) { + ISD::CondCode OrderedCmpOpcode = IsInvertedFP ? ISD::SETONE : ISD::SETOEQ; + ISD::CondCode UnorderedCmpOpcode = + IsInvertedFP ? ISD::SETUNE : ISD::SETUEQ; // If denormals could be implicitly treated as 0, this is not equivalent // to a compare with 0 since it will also be true for denormals. @@ -8083,19 +8085,34 @@ *IsCmp0 ? OrderedCmpOpcode : UnorderedCmpOpcode); } - if (TestMask == fcNan) + if (FPTestMask == fcNan) return DAG.getSetCC(DL, ResultVT, Op, Op, - IsInverted ? ISD::SETO : ISD::SETUO); - if (TestMask == fcInf) { + IsInvertedFP ? ISD::SETO : ISD::SETUO); + + if (FPTestMask == fcInf || FPTestMask == (fcInf | fcNan)) { + bool IsOrdered = FPTestMask == fcInf; + ISD::CondCode OrderedCmpOpcode = IsInvertedFP ? ISD::SETONE : ISD::SETOEQ; + ISD::CondCode UnorderedCmpOpcode = + IsInvertedFP ? ISD::SETUNE : ISD::SETUEQ; + // isinf(x) --> fabs(x) == inf SDValue Abs = DAG.getNode(ISD::FABS, DL, OperandVT, Op); SDValue Inf = DAG.getConstantFP(APFloat::getInf(Semantics), DL, OperandVT); return DAG.getSetCC(DL, ResultVT, Abs, Inf, - IsInverted ? ISD::SETONE : ISD::SETOEQ); + IsOrdered ? OrderedCmpOpcode : UnorderedCmpOpcode); } } + // Some checks may be represented as inversion of simpler check, for example + // "inf|normal|subnormal|zero" => !"nan". + bool IsInverted = false; + + if (FPClassTest InvertedCheck = invertFPClassTestIfSimpler(TestMask, false)) { + TestMask = InvertedCheck; + IsInverted = true; + } + // FIXME: Placeholder until FPClassTest is marked as a BitmaskEnum. unsigned Test = static_cast(TestMask); Index: llvm/test/CodeGen/PowerPC/is_fpclass.ll =================================================================== --- llvm/test/CodeGen/PowerPC/is_fpclass.ll +++ llvm/test/CodeGen/PowerPC/is_fpclass.ll @@ -169,14 +169,12 @@ define i1 @isfinite_float(float %x) nounwind { ; CHECK-LABEL: isfinite_float: ; CHECK: # %bb.0: -; CHECK-NEXT: xscvdpspn 0, 1 -; CHECK-NEXT: lis 4, 32640 -; CHECK-NEXT: mffprwz 3, 0 -; CHECK-NEXT: clrlwi 3, 3, 1 -; CHECK-NEXT: cmpw 3, 4 -; CHECK-NEXT: li 3, 0 -; CHECK-NEXT: li 4, 1 -; CHECK-NEXT: isellt 3, 4, 3 +; CHECK-NEXT: addis 3, 2, .LCPI11_0@toc@ha +; CHECK-NEXT: xsabsdp 0, 1 +; CHECK-NEXT: lfs 1, .LCPI11_0@toc@l(3) +; CHECK-NEXT: li 3, 1 +; CHECK-NEXT: fcmpu 0, 0, 1 +; CHECK-NEXT: iseleq 3, 0, 3 ; CHECK-NEXT: blr %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite" ret i1 %1 @@ -185,15 +183,13 @@ define i1 @isfinite_f128(fp128 %x) nounwind { ; CHECK-LABEL: isfinite_f128: ; CHECK: # %bb.0: -; CHECK-NEXT: stxv 34, -16(1) -; CHECK-NEXT: li 4, 32767 -; CHECK-NEXT: ld 3, -8(1) -; CHECK-NEXT: rldic 4, 4, 48, 1 -; CHECK-NEXT: clrldi 3, 3, 1 -; CHECK-NEXT: cmpd 3, 4 -; CHECK-NEXT: li 3, 0 -; CHECK-NEXT: li 4, 1 -; CHECK-NEXT: isellt 3, 4, 3 +; CHECK-NEXT: addis 3, 2, .LCPI12_0@toc@ha +; CHECK-NEXT: xsabsqp 2, 2 +; CHECK-NEXT: addi 3, 3, .LCPI12_0@toc@l +; CHECK-NEXT: lxv 35, 0(3) +; CHECK-NEXT: li 3, 1 +; CHECK-NEXT: xscmpuqp 0, 2, 3 +; CHECK-NEXT: iseleq 3, 0, 3 ; CHECK-NEXT: blr %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 504) ; 0x1f8 = "finite" ret i1 %1 Index: llvm/test/CodeGen/X86/is_fpclass.ll =================================================================== --- llvm/test/CodeGen/X86/is_fpclass.ll +++ llvm/test/CodeGen/X86/is_fpclass.ll @@ -247,18 +247,22 @@ define i1 @isfinite_f(float %x) { ; CHECK-32-LABEL: isfinite_f: ; CHECK-32: # %bb.0: # %entry -; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax -; CHECK-32-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000 -; CHECK-32-NEXT: setl %al +; CHECK-32-NEXT: flds {{[0-9]+}}(%esp) +; CHECK-32-NEXT: fabs +; CHECK-32-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}} +; CHECK-32-NEXT: fxch %st(1) +; CHECK-32-NEXT: fucompp +; CHECK-32-NEXT: fnstsw %ax +; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax +; CHECK-32-NEXT: sahf +; CHECK-32-NEXT: setb %al ; CHECK-32-NEXT: retl ; ; CHECK-64-LABEL: isfinite_f: ; CHECK-64: # %bb.0: # %entry -; CHECK-64-NEXT: movd %xmm0, %eax -; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000 -; CHECK-64-NEXT: setl %al +; CHECK-64-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; CHECK-64-NEXT: ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; CHECK-64-NEXT: setb %al ; CHECK-64-NEXT: retq entry: %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite" @@ -1174,20 +1178,22 @@ define i1 @isfinite_d(double %x) { ; CHECK-32-LABEL: isfinite_d: ; CHECK-32: # %bb.0: # %entry -; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax -; CHECK-32-NEXT: cmpl $2146435072, %eax # imm = 0x7FF00000 -; CHECK-32-NEXT: setl %al +; CHECK-32-NEXT: fldl {{[0-9]+}}(%esp) +; CHECK-32-NEXT: fabs +; CHECK-32-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}} +; CHECK-32-NEXT: fxch %st(1) +; CHECK-32-NEXT: fucompp +; CHECK-32-NEXT: fnstsw %ax +; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax +; CHECK-32-NEXT: sahf +; CHECK-32-NEXT: setb %al ; CHECK-32-NEXT: retl ; ; CHECK-64-LABEL: isfinite_d: ; CHECK-64: # %bb.0: # %entry -; CHECK-64-NEXT: movq %xmm0, %rax -; CHECK-64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF -; CHECK-64-NEXT: andq %rax, %rcx -; CHECK-64-NEXT: movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000 -; CHECK-64-NEXT: cmpq %rax, %rcx -; CHECK-64-NEXT: setl %al +; CHECK-64-NEXT: andpd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; CHECK-64-NEXT: ucomisd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; CHECK-64-NEXT: setb %al ; CHECK-64-NEXT: retq entry: %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 504) ; 0x1f8 = "finite" @@ -1965,18 +1971,22 @@ define i1 @not_isinf_or_nan_f(float %x) { ; CHECK-32-LABEL: not_isinf_or_nan_f: ; CHECK-32: # %bb.0: # %entry -; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax -; CHECK-32-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000 -; CHECK-32-NEXT: setl %al +; CHECK-32-NEXT: flds {{[0-9]+}}(%esp) +; CHECK-32-NEXT: fabs +; CHECK-32-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}} +; CHECK-32-NEXT: fxch %st(1) +; CHECK-32-NEXT: fucompp +; CHECK-32-NEXT: fnstsw %ax +; CHECK-32-NEXT: # kill: def $ah killed $ah killed $ax +; CHECK-32-NEXT: sahf +; CHECK-32-NEXT: setb %al ; CHECK-32-NEXT: retl ; ; CHECK-64-LABEL: not_isinf_or_nan_f: ; CHECK-64: # %bb.0: # %entry -; CHECK-64-NEXT: movd %xmm0, %eax -; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-64-NEXT: cmpl $2139095040, %eax # imm = 0x7F800000 -; CHECK-64-NEXT: setl %al +; CHECK-64-NEXT: andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; CHECK-64-NEXT: ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 +; CHECK-64-NEXT: setb %al ; CHECK-64-NEXT: retq entry: %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; ~(0x204|0x3) = "~(inf|nan)"