Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1246,6 +1246,161 @@ return Builder.CreateFCmp(FCmpInst::getOrderedPredicate(PredR), RHS0, RHS1); } +/// 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) { + // TODO: Compares eq/ne with 0 depends on the denormal handling mode. + case FCmpInst::FCMP_ORD: + // Canonical form of ord/uno is with a zero. We could 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 oeq fabs(x), +inf -> is_fpclass x, fcInf + // fcmp oeq x, -inf -> is_fpclass x, fcNegInf + // fcmp oeq fabs(x), -inf -> is_fpclass x, 0 -> false + // + // fcmp une x, +inf -> is_fpclass x, ~fcPosInf + // fcmp une fabs(x), +inf -> is_fpclass x, ~fcInf + // fcmp une x, -inf -> is_fpclass x, ~fcNegInf + // fcmp une fabs(x), -inf -> is_fpclass x, fcAllFlags -> true + + if (ConstRHS->isNegative()) { + Mask = fcNegInf; + if (IsFabs) + Mask = 0; + } else { + Mask = fcPosInf; + if (IsFabs) + Mask |= fcNegInf; + } + + break; + } + case FCmpInst::FCMP_ONE: + case FCmpInst::FCMP_UEQ: { + // Match __builtin_isinf patterns + // fcmp one x, -inf -> is_fpclass x, fcNegInf + // fcmp one fabs(x), -inf -> is_fpclass x, ~fcNegInf & ~fcNan + // fcmp one x, +inf -> is_fpclass x, ~fcNegInf & ~fcNan + // fcmp one fabs(x), +inf -> is_fpclass x, ~fcInf & fcNan + // + // fcmp ueq x, +inf -> is_fpclass x, fcPosInf|fcNan + // fcmp ueq (fabs x), +inf -> is_fpclass x, fcInf|fcNan + // fcmp ueq x, -inf -> is_fpclass x, fcNegInf|fcNan + // fcmp ueq 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 -> fcInf + // fcmp oge x, +inf -> fcPosInf + // fcmp ult fabs(x), +inf -> ~fcInf + // fcmp ult x, +inf -> ~fcPosInf + 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|fcNegNormal|fcSubnormal|fcZero + // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero + // fcmp uge x, smallest_normal -> fcNan|fcPosNormal|fcPosInf + // 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); @@ -1316,6 +1471,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) @@ -1324,13 +1492,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: @@ -1346,8 +1527,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 @@ -607,10 +607,8 @@ define i1 @test_fold_or_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_or_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: [[OR:%.*]] = or i1 [[CLASS0]], [[CLASS1]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CLASS0]] ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = fcmp uno float %a, 0.000000e+00 @@ -620,10 +618,8 @@ define i1 @test_fold_or3_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_or3_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4) -; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[CLASS0]], [[CLASS2]] -; CHECK-NEXT: ret i1 [[OR_1]] +; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 7) +; CHECK-NEXT: ret i1 [[CLASS2]] ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2) @@ -635,24 +631,7 @@ define i1 @test_fold_or_all_tests_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_or_all_tests_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4) -; CHECK-NEXT: [[CLASS3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 8) -; CHECK-NEXT: [[CLASS4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 16) -; CHECK-NEXT: [[CLASS5:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 32) -; CHECK-NEXT: [[CLASS6:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 64) -; CHECK-NEXT: [[CLASS7:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 128) -; CHECK-NEXT: [[CLASS8:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 256) -; CHECK-NEXT: [[CLASS9:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 512) -; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[CLASS0]], [[CLASS2]] -; CHECK-NEXT: [[OR_2:%.*]] = or i1 [[OR_1]], [[CLASS3]] -; CHECK-NEXT: [[OR_3:%.*]] = or i1 [[OR_2]], [[CLASS4]] -; CHECK-NEXT: [[OR_4:%.*]] = or i1 [[OR_3]], [[CLASS5]] -; CHECK-NEXT: [[OR_5:%.*]] = or i1 [[OR_4]], [[CLASS6]] -; CHECK-NEXT: [[OR_6:%.*]] = or i1 [[OR_5]], [[CLASS7]] -; CHECK-NEXT: [[OR_7:%.*]] = or i1 [[OR_6]], [[CLASS8]] -; CHECK-NEXT: [[OR_8:%.*]] = or i1 [[OR_7]], [[CLASS9]] -; CHECK-NEXT: ret i1 [[OR_8]] +; CHECK-NEXT: ret i1 true ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2) @@ -759,9 +738,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 @@ -771,12 +748,8 @@ define i1 @test_fold_and3_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_and3_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 2) -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 7) -; CHECK-NEXT: [[AND_0:%.*]] = and i1 [[CLASS0]], [[CLASS1]] -; CHECK-NEXT: [[AND_1:%.*]] = and i1 [[AND_0]], [[CLASS2]] -; CHECK-NEXT: ret i1 [[AND_1]] +; CHECK-NEXT: [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 2) +; CHECK-NEXT: ret i1 [[CLASS1]] ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 3) %class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2) @@ -814,24 +787,7 @@ define i1 @test_fold_and_not_all_tests_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_and_not_all_tests_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = fcmp ord float [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 1019) -; CHECK-NEXT: [[CLASS3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 1015) -; CHECK-NEXT: [[CLASS4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 1007) -; CHECK-NEXT: [[CLASS5:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 991) -; CHECK-NEXT: [[CLASS6:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 959) -; CHECK-NEXT: [[CLASS7:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 895) -; CHECK-NEXT: [[CLASS8:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 767) -; CHECK-NEXT: [[CLASS9:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 511) -; CHECK-NEXT: [[AND_1:%.*]] = and i1 [[CLASS0]], [[CLASS2]] -; CHECK-NEXT: [[AND_2:%.*]] = and i1 [[AND_1]], [[CLASS3]] -; CHECK-NEXT: [[AND_3:%.*]] = and i1 [[AND_2]], [[CLASS4]] -; CHECK-NEXT: [[AND_4:%.*]] = and i1 [[AND_3]], [[CLASS5]] -; CHECK-NEXT: [[AND_5:%.*]] = and i1 [[AND_4]], [[CLASS6]] -; CHECK-NEXT: [[AND_6:%.*]] = and i1 [[AND_5]], [[CLASS7]] -; CHECK-NEXT: [[AND_7:%.*]] = and i1 [[AND_6]], [[CLASS8]] -; CHECK-NEXT: [[AND_8:%.*]] = and i1 [[AND_7]], [[CLASS9]] -; CHECK-NEXT: ret i1 [[AND_8]] +; CHECK-NEXT: ret i1 false ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1022) %class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 1021) @@ -958,10 +914,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 @@ -971,10 +925,8 @@ define i1 @test_fold_xor3_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_xor3_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4) -; CHECK-NEXT: [[XOR_1:%.*]] = xor i1 [[CLASS0]], [[CLASS2]] -; CHECK-NEXT: ret i1 [[XOR_1]] +; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A:%.*]], i32 7) +; CHECK-NEXT: ret i1 [[CLASS2]] ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2) @@ -986,24 +938,7 @@ define i1 @test_fold_xor_all_tests_class_f32_0(float %a) { ; CHECK-LABEL: @test_fold_xor_all_tests_class_f32_0( -; CHECK-NEXT: [[CLASS0:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4) -; CHECK-NEXT: [[CLASS3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 8) -; CHECK-NEXT: [[CLASS4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 16) -; CHECK-NEXT: [[CLASS5:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 32) -; CHECK-NEXT: [[CLASS6:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 64) -; CHECK-NEXT: [[CLASS7:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 128) -; CHECK-NEXT: [[CLASS8:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 256) -; CHECK-NEXT: [[CLASS9:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 512) -; CHECK-NEXT: [[XOR_1:%.*]] = xor i1 [[CLASS0]], [[CLASS2]] -; CHECK-NEXT: [[XOR_2:%.*]] = xor i1 [[XOR_1]], [[CLASS3]] -; CHECK-NEXT: [[XOR_3:%.*]] = xor i1 [[XOR_2]], [[CLASS4]] -; CHECK-NEXT: [[XOR_4:%.*]] = xor i1 [[XOR_3]], [[CLASS5]] -; CHECK-NEXT: [[XOR_5:%.*]] = xor i1 [[XOR_4]], [[CLASS6]] -; CHECK-NEXT: [[XOR_6:%.*]] = xor i1 [[XOR_5]], [[CLASS7]] -; CHECK-NEXT: [[XOR_7:%.*]] = xor i1 [[XOR_6]], [[CLASS8]] -; CHECK-NEXT: [[XOR_8:%.*]] = xor i1 [[XOR_7]], [[CLASS9]] -; CHECK-NEXT: ret i1 [[XOR_8]] +; CHECK-NEXT: ret i1 true ; %class0 = call i1 @llvm.is.fpclass.f32(float %a, i32 1) %class1 = call i1 @llvm.is.fpclass.f32(float %a, i32 2)