Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1207,6 +1207,172 @@ return Builder.CreateICmp(NewPred, NewV, ConstantInt::get(Ty, NewC)); } +/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the +/// same result as an fcmp with the given operands. +static std::pair fcmpToClassTest(FCmpInst::Predicate Pred, + Value *LHS, Value *RHS) { + const APFloat *ConstRHS; + if (!match(RHS, m_APFloat(ConstRHS))) + return {nullptr, 0}; + + if (ConstRHS->isZero()) { + switch (Pred) { +#if 0 + // TODO: Compares with 0 depends on the denormal handling mode. + case FCmpInst::FCMP_OEQ: // Match x == 0.0 + return {LHS, fcZero}; + case FCmpInst::FCMP_UEQ: // Match !(x != 0.0) + return {LHS, fcZero | fcNan}; + case FCmpInst::FCMP_UNE: // Match !(x == 0.0) + return {LHS, (~fcZero & fcAllFlags) | fcNan}; + case FCmpInst::FCMP_ONE: // Match x != 0.0 + return {LHS, ~fcNan & ~fcZero & fcAllFlags}; +#endif + case FCmpInst::FCMP_ORD: + // Canonical form of ord/uno is with a zero. We would also handle + // non-canonical other non-NaN constants or LHS == RHS. + return {LHS, ~fcNan & fcAllFlags}; + case FCmpInst::FCMP_UNO: + return {LHS, fcNan}; + default: + break; + } + + return {nullptr, 0}; + } + + Value *Src = LHS; + const bool IsFabs = match(LHS, m_FAbs(m_Value(Src))); + + // Compute the test mask that would return true for the ordered comparisons. + unsigned Mask; + + if (ConstRHS->isInfinity()) { + switch (Pred) { + case FCmpInst::FCMP_OEQ: + case FCmpInst::FCMP_UNE: { + // Match __builtin_isinf patterns + // + // fcmp oeq x, +inf -> is_fpclass x, fcPosInf + // fcmp ueq x, +inf -> is_fpclass x, fcPosInf|fcNan + // fcmp oeq fabs(x), +inf -> is_fpclass x, fcInf + // fcmp ueq fabs(x), +inf -> is_fpclass x, fcInf|fcNan + // + // fcmp oeq x, -inf -> is_fpclass x, fcNegInf + // fcmp ueq x, -inf -> is_fpclass x, fcNegInf|fcNan + // fcmp oeq fabs(x), -inf -> is_fpclass x, ~fcNan + // fcmp ueq fabs(x), -inf -> is_fpclass x, fcNan + + if (ConstRHS->isNegative()) { + Mask = fcNegInf; + if (IsFabs) + Mask = ~fcNan; // FIXME: Can't write a test + } else { + Mask = fcPosInf; + if (IsFabs) + Mask |= fcNegInf; + } + + break; + } + case FCmpInst::FCMP_ONE: + case FCmpInst::FCMP_UEQ: { + // Match __builtin_isinf patterns + // + // fcmp oeq x, +inf -> is_fpclass x, fcPosInf + // fcmp oeq fabs(x), +inf -> is_fpclass x, fcInf + // fcmp ueq x, +inf -> is_fpclass x, fcPosInf|fcNan + // fcmp ueq (fabs x), +inf -> is_fpclass x, fcInf|fcNan + // + // fcmp oeq x, -inf -> is_fpclass x, fcNegInf + // fcmp oeq fabs(x), -inf -> is_fpclass x, ~fcNan + // fcmp one x, -inf -> is_fpclass x, fcNegInf + // fcmp one fabs(x), -inf -> is_fpclass x, ~fcNan + if (ConstRHS->isNegative()) { + Mask = ~fcNegInf & ~fcNan; + if (IsFabs) + Mask = ~fcNan; + } else { + Mask = ~fcPosInf & ~fcNan; + if (IsFabs) + Mask &= ~fcNegInf; + } + + Mask &= fcAllFlags; + break; + } + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_UGE: { + if (ConstRHS->isNegative()) // TODO + return {nullptr, 0}; + + // fcmp olt fabs(x), +inf -> fcFinite + // fcmp uge fabs(x), +inf -> ~fcFinite + // fcmp olt x, +inf -> fcNegInf|fcSubnormal|fcNormal|fcZero + // fcmp uge x, +inf -> ~(fcFinite|fcNegInf) + Mask = fcFinite; + if (!IsFabs) + Mask |= fcNegInf; + break; + } + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_ULT: { + if (ConstRHS->isNegative()) // TODO + return {nullptr, 0}; + + // fcmp oge fabs(x), +inf -> fcPosInf + // fcmp oge x, +inf -> fcInf + // fcmp ult fabs(x), +inf -> ~fcPosInf + // fcmp ult x, +inf -> ~fcInf + Mask = fcPosInf; + if (IsFabs) + Mask |= fcNegInf; + break; + } + default: + return {nullptr, 0}; + } + } else if (ConstRHS->isSmallestNormalized() && !ConstRHS->isNegative()) { + // Match pattern that's used in __builtin_isnormal. + switch (Pred) { + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_UGE: { + // fcmp olt x, smallest_normal -> fcNegInf|fcSubnormal|fcZero + // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero + // fcmp uge x, smallest_normal -> ~(fcZero|fcSubnormal) + // fcmp uge fabs(x), smallest_normal -> ~(fcSubnormal|fcZero) + Mask = fcZero | fcSubnormal; + if (!IsFabs) + Mask |= fcNegNormal | fcNegInf; + + break; + } + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_ULT: { + // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf + // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal + // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf) + // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal) + Mask = fcPosInf | fcPosNormal; + if (IsFabs) + Mask |= fcNegInf | fcNegNormal; + break; + } + default: + return {nullptr, 0}; + } + } else + return {nullptr, 0}; + + // Invert the comparison for the unordered cases. + if (FCmpInst::isUnordered(Pred)) + Mask = ~Mask & fcAllFlags; + + assert((Mask & ~fcAllFlags) == 0); + + return {Src, Mask}; +} + Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS, bool IsAnd, bool IsLogicalSelect) { Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1); @@ -1268,6 +1434,19 @@ return nullptr; } +/// Match an fcmp against a special value that performs a test possible by +/// llvm.is.fpclass. +static bool matchIsFPClassLikeFCmp(Value *Op, Value *&ClassVal, + uint64_t &ClassMask) { + auto *FCmp = dyn_cast(Op); + if (!FCmp || !FCmp->hasOneUse()) + return false; + + std::tie(ClassVal, ClassMask) = fcmpToClassTest( + FCmp->getPredicate(), FCmp->getOperand(0), FCmp->getOperand(1)); + return ClassVal != nullptr; +} + /// or (is_fpclass x, mask0), (is_fpclass x, mask1) /// -> is_fpclass x, (mask0 | mask1) /// and (is_fpclass x, mask0), (is_fpclass x, mask1) @@ -1276,13 +1455,26 @@ /// -> is_fpclass x, (mask0 ^ mask1) Instruction *InstCombinerImpl::foldLogicOfIsFPClass(BinaryOperator &BO, Value *Op0, Value *Op1) { - Value *ClassVal; + Value *ClassVal0 = nullptr; + Value *ClassVal1 = nullptr; uint64_t ClassMask0, ClassMask1; - if (match(Op0, m_OneUse(m_Intrinsic( - m_Value(ClassVal), m_ConstantInt(ClassMask0)))) && + // Restrict to folding one fcmp into one is.fpclass for now, don't introduce a + // new class. + // + // TODO: Support forming is.fpclass out of 2 separate fcmps when codegen is + // better. + + bool IsLHSClass = + match(Op0, m_OneUse(m_Intrinsic( + m_Value(ClassVal0), m_ConstantInt(ClassMask0)))); + bool IsRHSClass = match(Op1, m_OneUse(m_Intrinsic( - m_Specific(ClassVal), m_ConstantInt(ClassMask1))))) { + m_Value(ClassVal1), m_ConstantInt(ClassMask1)))); + if (((IsLHSClass && IsRHSClass) || + ((!IsLHSClass && matchIsFPClassLikeFCmp(Op0, ClassVal0, ClassMask0)) || + (!IsRHSClass && matchIsFPClassLikeFCmp(Op1, ClassVal1, ClassMask1)))) && + ClassVal0 == ClassVal1) { unsigned NewClassMask; switch (BO.getOpcode()) { case Instruction::And: @@ -1298,8 +1490,7 @@ llvm_unreachable("not a binary logic operator"); } - // TODO: Also check for special fcmps - auto *II = cast(Op0); + auto *II = IsLHSClass ? cast(Op0) : cast(Op1); II->setArgOperand( 1, ConstantInt::get(II->getArgOperand(1)->getType(), NewClassMask)); return replaceInstUsesWith(BO, II); Index: llvm/test/Transforms/InstCombine/combine-is.fpclass-and-fcmp.ll =================================================================== --- llvm/test/Transforms/InstCombine/combine-is.fpclass-and-fcmp.ll +++ llvm/test/Transforms/InstCombine/combine-is.fpclass-and-fcmp.ll @@ -3,10 +3,8 @@ define i1 @fcmp_oeq_inf_or_class_normal(half %x) { ; CHECK-LABEL: @fcmp_oeq_inf_or_class_normal( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[OEQ_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776) +; CHECK-NEXT: ret i1 [[CLASS]] ; %oeq.inf = fcmp oeq half %x, 0xH7C00 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -16,10 +14,8 @@ define i1 @class_normal_or_fcmp_oeq_inf(half %x) { ; CHECK-LABEL: @class_normal_or_fcmp_oeq_inf( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[CLASS]], [[OEQ_INF]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776) +; CHECK-NEXT: ret i1 [[CLASS]] ; %oeq.inf = fcmp oeq half %x, 0xH7C00 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -29,10 +25,8 @@ define <2 x i1> @fcmp_oeq_inf_or_class_normal_vector(<2 x half> %x) { ; CHECK-LABEL: @fcmp_oeq_inf_or_class_normal_vector( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq <2 x half> [[X:%.*]], -; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[OEQ_INF]], [[CLASS]] -; CHECK-NEXT: ret <2 x i1> [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 776) +; CHECK-NEXT: ret <2 x i1> [[CLASS]] ; %oeq.inf = fcmp oeq <2 x half> %x, %class = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> %x, i32 264) @@ -129,11 +123,8 @@ define i1 @fcmp_isfinite_and_class_subnormal(half %x) { ; CHECK-LABEL: @fcmp_isfinite_and_class_subnormal( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp olt half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 144) -; CHECK-NEXT: [[AND:%.*]] = and i1 [[IS_FINITE]], [[SUBNORMAL_CLASS]] -; CHECK-NEXT: ret i1 [[AND]] +; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 144) +; CHECK-NEXT: ret i1 [[SUBNORMAL_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) %is.finite = fcmp olt half %fabs, 0xH7C00 @@ -144,11 +135,8 @@ define i1 @fcmp_isfinite_or_class_subnormal(half %x) { ; CHECK-LABEL: @fcmp_isfinite_or_class_subnormal( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp olt half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 144) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_FINITE]], [[SUBNORMAL_CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[SUBNORMAL_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504) +; CHECK-NEXT: ret i1 [[SUBNORMAL_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) %is.finite = fcmp olt half %fabs, 0xH7C00 @@ -160,11 +148,8 @@ ; -> isfinite define i1 @fcmp_issubnormal_or_class_finite(half %x) { ; CHECK-LABEL: @fcmp_issubnormal_or_class_finite( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 504) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_SUBNORMAL]], [[IS_FINITE_CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504) +; CHECK-NEXT: ret i1 [[IS_FINITE_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) %is.subnormal = fcmp olt half %fabs, 0xH0400 @@ -176,11 +161,8 @@ ; -> isfinite define i1 @class_finite_or_fcmp_issubnormal(half %x) { ; CHECK-LABEL: @class_finite_or_fcmp_issubnormal( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 504) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_FINITE_CLASS]], [[IS_SUBNORMAL]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504) +; CHECK-NEXT: ret i1 [[IS_FINITE_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) %is.subnormal = fcmp olt half %fabs, 0xH0400 @@ -192,11 +174,8 @@ ; -> issubnormal define i1 @fcmp_issubnormal_and_class_finite(half %x) { ; CHECK-LABEL: @fcmp_issubnormal_and_class_finite( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 504) -; CHECK-NEXT: [[AND:%.*]] = and i1 [[IS_SUBNORMAL]], [[IS_FINITE_CLASS]] -; CHECK-NEXT: ret i1 [[AND]] +; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 240) +; CHECK-NEXT: ret i1 [[IS_FINITE_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) %is.subnormal = fcmp olt half %fabs, 0xH0400 @@ -207,11 +186,8 @@ define i1 @class_inf_or_fcmp_issubnormal(half %x) { ; CHECK-LABEL: @class_inf_or_fcmp_issubnormal( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: [[IS_INF_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 516) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_INF_CLASS]], [[IS_SUBNORMAL]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[IS_INF_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 756) +; CHECK-NEXT: ret i1 [[IS_INF_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) %is.subnormal = fcmp olt half %fabs, 0xH0400 @@ -223,11 +199,8 @@ ; -> isfinite define <2 x i1> @class_finite_or_fcmp_issubnormal_vector(<2 x half> %x) { ; CHECK-LABEL: @class_finite_or_fcmp_issubnormal_vector( -; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) -; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt <2 x half> [[FABS]], -; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X]], i32 504) -; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[IS_FINITE_CLASS]], [[IS_SUBNORMAL]] -; CHECK-NEXT: ret <2 x i1> [[OR]] +; CHECK-NEXT: [[IS_FINITE_CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 504) +; CHECK-NEXT: ret <2 x i1> [[IS_FINITE_CLASS]] ; %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x) %is.subnormal = fcmp olt <2 x half> %fabs, @@ -342,10 +315,8 @@ define i1 @fcmp_oeq_inf_xor_class_normal(half %x) { ; CHECK-LABEL: @fcmp_oeq_inf_xor_class_normal( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[OEQ_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776) +; CHECK-NEXT: ret i1 [[CLASS]] ; %oeq.inf = fcmp oeq half %x, 0xH7C00 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -355,10 +326,8 @@ define i1 @class_normal_xor_fcmp_oeq_inf(half %x) { ; CHECK-LABEL: @class_normal_xor_fcmp_oeq_inf( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CLASS]], [[OEQ_INF]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776) +; CHECK-NEXT: ret i1 [[CLASS]] ; %oeq.inf = fcmp oeq half %x, 0xH7C00 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) Index: llvm/test/Transforms/InstCombine/is_fpclass.ll =================================================================== --- llvm/test/Transforms/InstCombine/is_fpclass.ll +++ llvm/test/Transforms/InstCombine/is_fpclass.ll @@ -746,9 +746,7 @@ define i1 @test_fold_and_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_and_class_f32_0( ; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 1) -; CHECK-NEXT: [[CLASS1:%.*]] = fcmp uno float [[A]], 0.000000e+00 -; CHECK-NEXT: [[AND:%.*]] = and i1 [[CLASS0]], [[CLASS1]] -; CHECK-NEXT: ret i1 [[AND]] +; CHECK-NEXT: ret i1 [[CLASS0]] ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = fcmp uno float %a, 0.000000e+00 @@ -924,10 +922,8 @@ define i1 @test_fold_xor_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_xor_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 1) -; CHECK-NEXT: [[CLASS1:%.*]] = fcmp uno float [[A]], 0.000000e+00 -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CLASS0]], [[CLASS1]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[CLASS0:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 2) +; CHECK-NEXT: ret i1 [[CLASS0]] ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = fcmp uno float %a, 0.000000e+00