Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1246,17 +1246,37 @@ return Builder.CreateFCmp(FCmpInst::getOrderedPredicate(PredR), RHS0, RHS1); } +/// Return true if it's possible to assume IEEE treatment of input denormals in +/// \p F for \p Val. +static bool inputDenormalIsIEEE(const Function &F, const Value *Val) { + Type *Ty = Val->getType()->getScalarType(); + return F.getDenormalMode(Ty->getFltSemantics()).Input == DenormalMode::IEEE; +} + /// 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, + const Function &F, Value *LHS, Value *RHS) { const APFloat *ConstRHS; if (!match(RHS, m_APFloat(ConstRHS))) return {nullptr, 0}; if (ConstRHS->isZero()) { + // Compares with 0 are only exactly equal to fcZero if input denormals are + // not flushed. + if (FCmpInst::isEquality(Pred) && !inputDenormalIsIEEE(F, LHS)) + return {nullptr, 0}; + switch (Pred) { - // TODO: Compares eq/ne with 0 depends on the denormal handling mode. + case FCmpInst::FCMP_OEQ: // Match x == 0.0 + return {LHS, fcZero}; + case FCmpInst::FCMP_UEQ: // Match isnan(x) || (x == 0.0) + return {LHS, fcZero | fcNan}; + case FCmpInst::FCMP_UNE: // Match (x != 0.0) + return {LHS, ~fcZero & fcAllFlags}; + case FCmpInst::FCMP_ONE: // Match !isnan(x) && x != 0.0 + return {LHS, ~fcNan & ~fcZero & fcAllFlags}; 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. @@ -1474,9 +1494,11 @@ // potentially eliminate 4-6 instructions. If we can represent a test with a // single fcmp with fneg and fabs, that's likely a better canonical form. if (LHS->hasOneUse() && RHS->hasOneUse()) { - auto [ClassValRHS, ClassMaskRHS] = fcmpToClassTest(PredR, RHS0, RHS1); + auto [ClassValRHS, ClassMaskRHS] = + fcmpToClassTest(PredR, *RHS->getFunction(), RHS0, RHS1); if (ClassValRHS) { - auto [ClassValLHS, ClassMaskLHS] = fcmpToClassTest(PredL, LHS0, LHS1); + auto [ClassValLHS, ClassMaskLHS] = + fcmpToClassTest(PredL, *LHS->getFunction(), LHS0, LHS1); if (ClassValLHS == ClassValRHS) { unsigned CombinedMask = IsAnd ? (ClassMaskLHS & ClassMaskRHS) : (ClassMaskLHS | ClassMaskRHS); @@ -1498,8 +1520,9 @@ if (!FCmp || !FCmp->hasOneUse()) return false; - std::tie(ClassVal, ClassMask) = fcmpToClassTest( - FCmp->getPredicate(), FCmp->getOperand(0), FCmp->getOperand(1)); + std::tie(ClassVal, ClassMask) = + fcmpToClassTest(FCmp->getPredicate(), *FCmp->getParent()->getParent(), + FCmp->getOperand(0), FCmp->getOperand(1)); return ClassVal != nullptr; } 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 @@ -211,10 +211,8 @@ define i1 @fcmp_oeq_zero_or_class_normal(half %x) { ; CHECK-LABEL: @fcmp_oeq_zero_or_class_normal( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH0000 -; 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 360) +; CHECK-NEXT: ret i1 [[CLASS]] ; %oeq.inf = fcmp oeq half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -276,10 +274,8 @@ define i1 @class_normal_or_fcmp_oeq_zero(half %x) { ; CHECK-LABEL: @class_normal_or_fcmp_oeq_zero( -; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH0000 -; 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 360) +; CHECK-NEXT: ret i1 [[CLASS]] ; %oeq.inf = fcmp oeq half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -289,10 +285,8 @@ define i1 @fcmp_ueq_zero_or_class_normal(half %x) { ; CHECK-LABEL: @fcmp_ueq_zero_or_class_normal( -; CHECK-NEXT: [[UEQ_INF:%.*]] = fcmp ueq half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[UEQ_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 363) +; CHECK-NEXT: ret i1 [[CLASS]] ; %ueq.inf = fcmp ueq half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -302,10 +296,8 @@ define i1 @class_normal_or_fcmp_ueq_zero(half %x) { ; CHECK-LABEL: @class_normal_or_fcmp_ueq_zero( -; CHECK-NEXT: [[UEQ_INF:%.*]] = fcmp ueq half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[UEQ_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 363) +; CHECK-NEXT: ret i1 [[CLASS]] ; %ueq.inf = fcmp ueq half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -315,10 +307,8 @@ define i1 @fcmp_one_zero_or_class_normal(half %x) { ; CHECK-LABEL: @fcmp_one_zero_or_class_normal( -; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp one half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[ONE_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 924) +; CHECK-NEXT: ret i1 [[CLASS]] ; %one.inf = fcmp one half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -354,10 +344,8 @@ define i1 @class_normal_or_fcmp_one_zero(half %x) { ; CHECK-LABEL: @class_normal_or_fcmp_one_zero( -; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp one half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[ONE_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 924) +; CHECK-NEXT: ret i1 [[CLASS]] ; %one.inf = fcmp one half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -367,10 +355,8 @@ define i1 @fcmp_une_zero_or_class_normal(half %x) { ; CHECK-LABEL: @fcmp_une_zero_or_class_normal( -; CHECK-NEXT: [[UNE_INF:%.*]] = fcmp une half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[UNE_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = fcmp une half [[X:%.*]], 0xH0000 +; CHECK-NEXT: ret i1 [[CLASS]] ; %une.inf = fcmp une half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) @@ -380,10 +366,8 @@ define i1 @class_normal_or_fcmp_une_zero(half %x) { ; CHECK-LABEL: @class_normal_or_fcmp_une_zero( -; CHECK-NEXT: [[UNE_INF:%.*]] = fcmp une half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264) -; CHECK-NEXT: [[OR:%.*]] = or i1 [[UNE_INF]], [[CLASS]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: [[CLASS:%.*]] = fcmp une half [[X:%.*]], 0xH0000 +; CHECK-NEXT: ret i1 [[CLASS]] ; %une.inf = fcmp une half %x, 0.0 %class = call i1 @llvm.is.fpclass.f16(half %x, i32 264) Index: llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll =================================================================== --- llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll +++ llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll @@ -10,10 +10,7 @@ ; Base pattern !isfinite(x) || x == 0.0 define i1 @not_isfinite_or_zero_f16(half %x) { ; CHECK-LABEL: @not_isfinite_or_zero_f16( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -26,10 +23,7 @@ ; Base pattern x == 0.0 || !isfinite(x) define i1 @not_isfinite_or_zero_f16_commute_or(half %x) { ; CHECK-LABEL: @not_isfinite_or_zero_f16_commute_or( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPINF]], [[CMPZERO]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -42,10 +36,7 @@ ; Base pattern !isfinite(x) || x == -0.0 define i1 @not_isfinite_or_zero_f16_negzero(half %x) { ; CHECK-LABEL: @not_isfinite_or_zero_f16_negzero( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -57,10 +48,7 @@ define i1 @not_isfinite_or_fabs_oeq_zero_f16(half %x) { ; CHECK-LABEL: @not_isfinite_or_fabs_oeq_zero_f16( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -73,10 +61,7 @@ ; Base pattern !isfinite(x) || x == 0.0 define <2 x i1> @not_isfinite_or_zero_v2f16(<2 x half> %x) { ; CHECK-LABEL: @not_isfinite_or_zero_v2f16( -; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq <2 x half> [[FABS]], -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq <2 x half> [[X]], zeroinitializer -; CHECK-NEXT: [[CLASS:%.*]] = or <2 x i1> [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 615) ; CHECK-NEXT: ret <2 x i1> [[CLASS]] ; %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x) @@ -89,10 +74,7 @@ ; Base pattern !isfinite(x) || x == <0.0, -0.0> define <2 x i1> @not_isfinite_or_zero_v2f16_pos0_neg0_vec(<2 x half> %x) { ; CHECK-LABEL: @not_isfinite_or_zero_v2f16_pos0_neg0_vec( -; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq <2 x half> [[FABS]], -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq <2 x half> [[X]], zeroinitializer -; CHECK-NEXT: [[CLASS:%.*]] = or <2 x i1> [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 615) ; CHECK-NEXT: ret <2 x i1> [[CLASS]] ; %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x) @@ -105,10 +87,7 @@ ; Base pattern x == 0.0 || !isfinite(x) define <2 x i1> @not_isfinite_or_zero_v2f16_commute_or(<2 x half> %x) { ; CHECK-LABEL: @not_isfinite_or_zero_v2f16_commute_or( -; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq <2 x half> [[FABS]], -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq <2 x half> [[X]], zeroinitializer -; CHECK-NEXT: [[CLASS:%.*]] = or <2 x i1> [[CMPINF]], [[CMPZERO]] +; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 615) ; CHECK-NEXT: ret <2 x i1> [[CLASS]] ; %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x) @@ -121,10 +100,7 @@ ; Positive test define i1 @oeq_isinf_or_oeq_zero(half %x) { ; CHECK-LABEL: @oeq_isinf_or_oeq_zero( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 612) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -137,9 +113,7 @@ ; Missing fabs for infinity check define i1 @ueq_inf_or_oeq_zero(half %x) { ; CHECK-LABEL: @ueq_inf_or_oeq_zero( -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[X:%.*]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 611) ; CHECK-NEXT: ret i1 [[CLASS]] ; %cmpinf = fcmp ueq half %x, 0xH7C00 @@ -151,10 +125,7 @@ ; Extra fabs. define i1 @oeq_isinf_or_fabs_oeq_zero(half %x) { ; CHECK-LABEL: @oeq_isinf_or_fabs_oeq_zero( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 612) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -167,9 +138,7 @@ ; Positive test define i1 @ueq_0_or_oeq_inf(half %x) { ; CHECK-LABEL: @ueq_0_or_oeq_inf( -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH7C00 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 611) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -194,10 +163,7 @@ ; Positive test define i1 @ueq_inf_or_ueq_zero(half %x) { ; CHECK-LABEL: @ueq_inf_or_ueq_zero( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp ueq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -210,11 +176,7 @@ ; Positive test define i1 @not_isfinite_and_zero_f16(half %x) { ; CHECK-LABEL: @not_isfinite_and_zero_f16( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] -; CHECK-NEXT: ret i1 [[CLASS]] +; CHECK-NEXT: ret i1 false ; %fabs = call half @llvm.fabs.f16(half %x) %cmpinf = fcmp ueq half %fabs, 0xH7C00 @@ -262,10 +224,7 @@ ; Negative test define i1 @not_isfinite_or_zero_f16_neg_inf(half %x) { ; CHECK-LABEL: @not_isfinite_or_zero_f16_neg_inf( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xHFC00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 99) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -294,10 +253,7 @@ ; Negative test define i1 @oeq_0_or_fabs_ult_inf(half %x) { ; CHECK-LABEL: @oeq_0_or_fabs_ult_inf( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ult half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 507) ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -362,10 +318,7 @@ ; Negation of base pattern, isfinite(x) && !(x == 0.0) define i1 @negated_isfinite_or_zero_f16(half %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_f16( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408) ; CHECK-NEXT: ret i1 [[NOT_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -378,10 +331,7 @@ ; Commuted !(x == 0.0) && isfinite(x) define i1 @negated_isfinite_or_zero_f16_commute_and(half %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_f16_commute_and( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and i1 [[CMPINF]], [[CMPZERO]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408) ; CHECK-NEXT: ret i1 [[NOT_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -394,10 +344,7 @@ ; isfinite(x) && !(x == -0.0) define i1 @negated_isfinite_or_zero_f16_negzero(half %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_f16_negzero( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408) ; CHECK-NEXT: ret i1 [[NOT_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -410,10 +357,7 @@ ; Negated pattern define <2 x i1> @negated_isfinite_or_zero_v2f16(<2 x half> %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_v2f16( -; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one <2 x half> [[FABS]], -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une <2 x half> [[X]], zeroinitializer -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and <2 x i1> [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 408) ; CHECK-NEXT: ret <2 x i1> [[NOT_CLASS]] ; %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x) @@ -426,10 +370,7 @@ ; Negated pattern, commuted vector and define <2 x i1> @negated_isfinite_or_zero_v2f16_comumte(<2 x half> %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_v2f16_comumte( -; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one <2 x half> [[FABS]], -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une <2 x half> [[X]], zeroinitializer -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and <2 x i1> [[CMPINF]], [[CMPZERO]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 408) ; CHECK-NEXT: ret <2 x i1> [[NOT_CLASS]] ; %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x) @@ -442,10 +383,7 @@ ; Positive test define i1 @negated_isfinite_or_zero_f16_not_une_zero(half %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_f16_not_une_zero( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp one half [[X]], 0xH0000 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408) ; CHECK-NEXT: ret i1 [[NOT_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -458,11 +396,7 @@ ; Positive test define i1 @negated_isfinite_and_zero_f16(half %x) { ; CHECK-LABEL: @negated_isfinite_and_zero_f16( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp one half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] -; CHECK-NEXT: ret i1 [[NOT_CLASS]] +; CHECK-NEXT: ret i1 true ; %fabs = call half @llvm.fabs.f16(half %x) %cmpinf = fcmp one half %fabs, 0xH7C00 @@ -474,9 +408,7 @@ ; Negative test define i1 @negated_isfinite_or_zero_f16_swapped_constants(half %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_f16_swapped_constants( -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp one half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp une half [[X]], 0xH7C00 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 412) ; CHECK-NEXT: ret i1 [[NOT_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -525,10 +457,7 @@ ; Negative test define i1 @negated_isfinite_or_zero_f16_multi_use_cmp0_not_one_inf(half %x) { ; CHECK-LABEL: @negated_isfinite_or_zero_f16_multi_use_cmp0_not_one_inf( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp une half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[NOT_CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 411) ; CHECK-NEXT: ret i1 [[NOT_CLASS]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -560,10 +489,7 @@ define i1 @fcmp_une_0_or_fcmp_une_inf(half %x) { ; CHECK-LABEL: @fcmp_une_0_or_fcmp_une_inf( -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp une half [[X]], 0xH7C00 -; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: ret i1 true ; %cmpzero = fcmp une half %x, 0.0 %cmpinf = fcmp une half %x, 0xH7C00 @@ -573,10 +499,7 @@ define i1 @fcmp_one_0_and_fcmp_une_fabs_inf(half %x) { ; CHECK-LABEL: @fcmp_one_0_and_fcmp_une_fabs_inf( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp one half [[X]], 0xH0000 -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp une half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[AND:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408) ; CHECK-NEXT: ret i1 [[AND]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -588,10 +511,7 @@ define i1 @fcmp_une_0_and_fcmp_une_fabs_inf(half %x) { ; CHECK-LABEL: @fcmp_une_0_and_fcmp_une_fabs_inf( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp une half [[FABS]], 0xH7C00 -; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMPZERO]], [[CMPINF]] +; CHECK-NEXT: [[AND:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 411) ; CHECK-NEXT: ret i1 [[AND]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -603,10 +523,7 @@ define i1 @fcmp_une_0_and_fcmp_une_neginf(half %x) { ; CHECK-LABEL: @fcmp_une_0_and_fcmp_une_neginf( -; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp une half [[X:%.*]], 0xH0000 -; CHECK-NEXT: [[CMPINF:%.*]] = fcmp une half [[X]], 0xHFC00 -; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMPZERO]], [[CMPINF]] -; CHECK-NEXT: ret i1 [[OR]] +; CHECK-NEXT: ret i1 true ; %cmpzero = fcmp une half %x, 0.0 %cmpinf = fcmp une half %x, 0xHFC00 @@ -746,10 +663,7 @@ define i1 @not_zero_and_subnormal(half %x) { ; CHECK-LABEL: @not_zero_and_subnormal( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[CMP_ZERO:%.*]] = fcmp one half [[X]], 0xH0000 -; CHECK-NEXT: [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMP_ZERO]] +; CHECK-NEXT: [[OR:%.*]] = fcmp ord half [[X:%.*]], 0xH0000 ; CHECK-NEXT: ret i1 [[OR]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -877,10 +791,8 @@ define i1 @isnormal_or_zero(half %x) #0 { ; CHECK-LABEL: @isnormal_or_zero( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[AND1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 264) -; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[SPEC_SELECT:%.*]] = or i1 [[CMP]], [[AND1]] -; CHECK-NEXT: ret i1 [[SPEC_SELECT]] +; CHECK-NEXT: [[AND1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 360) +; CHECK-NEXT: ret i1 [[AND1]] ; entry: %iseq = fcmp ord half %x, 0xH0000 @@ -897,10 +809,7 @@ define i1 @isnormal_uge_or_zero_oeq(half %x) #0 { ; CHECK-LABEL: @isnormal_uge_or_zero_oeq( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[FABS:%.*]] = tail call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_NORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400 -; CHECK-NEXT: [[IS_ZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_NORMAL]], [[IS_ZERO]] +; CHECK-NEXT: [[OR:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 879) ; CHECK-NEXT: ret i1 [[OR]] ; entry: @@ -945,9 +854,7 @@ ; -> iszero define i1 @une_or_oge_smallest_normal(half %x) #0 { ; CHECK-LABEL: @une_or_oge_smallest_normal( -; CHECK-NEXT: [[IS_NORMAL_INF:%.*]] = fcmp oge half [[X:%.*]], 0xH0400 -; CHECK-NEXT: [[IS_UNE:%.*]] = fcmp une half [[X]], 0xH0000 -; CHECK-NEXT: [[OR:%.*]] = or i1 [[IS_UNE]], [[IS_NORMAL_INF]] +; CHECK-NEXT: [[OR:%.*]] = fcmp une half [[X:%.*]], 0xH0000 ; CHECK-NEXT: ret i1 [[OR]] ; %is.normal.inf = fcmp oge half %x, 0xH0400 @@ -1938,10 +1845,7 @@ ; TODO: This could fold to just fcmp olt half %fabs, 0xH0400 define i1 @subnormal_or_zero_ieee(half %x) #0 { ; CHECK-LABEL: @subnormal_or_zero_ieee( -; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) -; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400 -; CHECK-NEXT: [[IS_ZERO:%.*]] = fcmp oeq half [[X]], 0xH0000 -; CHECK-NEXT: [[AND:%.*]] = or i1 [[IS_SUBNORMAL]], [[IS_ZERO]] +; CHECK-NEXT: [[AND:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 240) ; CHECK-NEXT: ret i1 [[AND]] ; %fabs = call half @llvm.fabs.f16(half %x)