Index: llvm/include/llvm/ADT/FloatingPointMode.h =================================================================== --- llvm/include/llvm/ADT/FloatingPointMode.h +++ llvm/include/llvm/ADT/FloatingPointMode.h @@ -144,6 +144,12 @@ Input != DenormalModeKind::Invalid; } + /// Return true if input denormals must be implicitly treated as 0. + constexpr bool inputsAreZero() const { + return Input == DenormalModeKind::PreserveSign || + Input == DenormalModeKind::PositiveZero; + } + /// Get the effective denormal mode if the mode if this caller calls into a /// function with \p Callee. This promotes dynamic modes to the mode of the /// caller. Index: llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -8007,6 +8007,20 @@ return SDValue(); } +/// If this FPClassTest can be performed with a fcmp to 0, return the test mask +/// for the floating-point mode. +static FPClassTest isFCmpEqualZero(FPClassTest Test, + const fltSemantics &Semantics, + const MachineFunction &MF) { + if (Test == fcZero && + MF.getDenormalMode(Semantics).Input == DenormalMode::IEEE) + return fcZero; + if (Test == (fcZero | fcSubnormal) && + MF.getDenormalMode(Semantics).inputsAreZero()) + return static_cast(fcZero | fcSubnormal); + return fcNone; +} + SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op, FPClassTest Test, SDNodeFlags Flags, const SDLoc &DL, @@ -8015,7 +8029,7 @@ assert(OperandVT.isFloatingPoint()); // Degenerated cases. - if (Test == 0) + if (Test == fcNone) return DAG.getBoolConstant(false, DL, ResultVT, OperandVT); if ((Test & fcAllFlags) == fcAllFlags) return DAG.getBoolConstant(true, DL, ResultVT, OperandVT); @@ -8045,18 +8059,14 @@ // Some checks can be implemented using float comparisons, if floating point // exceptions are ignored. if (Flags.hasNoFPExcept() && + // TODO: Should check isCondCodeLegal isOperationLegalOrCustom(ISD::SETCC, OperandVT.getScalarType())) { - if (Test == fcZero) { - DenormalMode Mode = DAG.getMachineFunction().getDenormalMode(Semantics); - if (Mode.Input == DenormalMode::IEEE) { - // 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. - // - // TODO: With DAZ, check == fcZero | fcSubnormal - return DAG.getSetCC(DL, ResultVT, Op, - DAG.getConstantFP(0.0, DL, OperandVT), - IsInverted ? ISD::SETUNE : ISD::SETOEQ); - } + if (isFCmpEqualZero(Test, Semantics, DAG.getMachineFunction()) != fcNone) { + // 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. + return DAG.getSetCC(DL, ResultVT, Op, + DAG.getConstantFP(0.0, DL, OperandVT), + IsInverted ? ISD::SETUNE : ISD::SETOEQ); } if (Test == fcNan) Index: llvm/test/CodeGen/X86/is_fpclass.ll =================================================================== --- llvm/test/CodeGen/X86/is_fpclass.ll +++ llvm/test/CodeGen/X86/is_fpclass.ll @@ -837,24 +837,24 @@ define i1 @issubnormal_or_zero_f_daz(float %x) #0 { ; CHECK-32-LABEL: issubnormal_or_zero_f_daz: ; CHECK-32: # %bb.0: # %entry -; CHECK-32-NEXT: movl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-32-NEXT: andl {{[0-9]+}}(%esp), %eax -; CHECK-32-NEXT: sete %cl -; CHECK-32-NEXT: decl %eax -; CHECK-32-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF -; CHECK-32-NEXT: setb %al -; CHECK-32-NEXT: orb %cl, %al +; CHECK-32-NEXT: flds {{[0-9]+}}(%esp) +; CHECK-32-NEXT: fldz +; 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: setnp %cl +; CHECK-32-NEXT: sete %al +; CHECK-32-NEXT: andb %cl, %al ; CHECK-32-NEXT: retl ; ; CHECK-64-LABEL: issubnormal_or_zero_f_daz: ; CHECK-64: # %bb.0: # %entry -; CHECK-64-NEXT: movd %xmm0, %eax -; CHECK-64-NEXT: andl $2147483647, %eax # imm = 0x7FFFFFFF -; CHECK-64-NEXT: sete %cl -; CHECK-64-NEXT: decl %eax -; CHECK-64-NEXT: cmpl $8388607, %eax # imm = 0x7FFFFF -; CHECK-64-NEXT: setb %al -; CHECK-64-NEXT: orb %cl, %al +; CHECK-64-NEXT: xorps %xmm1, %xmm1 +; CHECK-64-NEXT: cmpeqss %xmm0, %xmm1 +; CHECK-64-NEXT: movd %xmm1, %eax +; CHECK-64-NEXT: andl $1, %eax +; CHECK-64-NEXT: # kill: def $al killed $al killed $eax ; CHECK-64-NEXT: retq entry: %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 240) ; 0xf0 = "subnormal|zero" Index: llvm/unittests/ADT/FloatingPointMode.cpp =================================================================== --- llvm/unittests/ADT/FloatingPointMode.cpp +++ llvm/unittests/ADT/FloatingPointMode.cpp @@ -219,4 +219,11 @@ DenormalMode::getIEEE(), DenormalMode::getPreserveSign().mergeCalleeMode(DenormalMode::getIEEE())); } + +TEST(FloatingPointModeTest, DenormalModePredicates) { + EXPECT_TRUE(DenormalMode::getPreserveSign().inputsAreZero()); + EXPECT_TRUE(DenormalMode::getPositiveZero().inputsAreZero()); + EXPECT_FALSE(DenormalMode::getIEEE().inputsAreZero()); + EXPECT_FALSE(DenormalMode::getDynamic().inputsAreZero()); +} }