InstCombine: Handle folding fcmp of 0 into llvm.is.fpclass
authorMatt Arsenault <Matthew.Arsenault@amd.com>
Mon, 6 Feb 2023 15:49:50 +0000 (11:49 -0400)
committerMatt Arsenault <arsenm2@gmail.com>
Wed, 15 Mar 2023 11:07:55 +0000 (07:07 -0400)
This needs to consider the denormal mode.

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/combine-is.fpclass-and-fcmp.ll
llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll

index 0a9da92..4317725 100644 (file)
@@ -1273,17 +1273,37 @@ static Value *matchIsFiniteTest(InstCombiner::BuilderTy &Builder, FCmpInst *LHS,
   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<Value *, unsigned> 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.
@@ -1501,9 +1521,11 @@ Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
   // 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);
@@ -1525,8 +1547,9 @@ static bool matchIsFPClassLikeFCmp(Value *Op, Value *&ClassVal,
   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 a4ec836..9b53f17 100644 (file)
@@ -211,10 +211,8 @@ define <2 x i1> @class_finite_or_fcmp_issubnormal_vector(<2 x half> %x) {
 
 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 <2 x i1> @fcmp_oeq_zero_or_class_normal_dynamic_v2f16(<2 x half> %x) #2 {
 
 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 @class_normal_or_fcmp_oeq_zero(half %x) {
 
 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 @fcmp_ueq_zero_or_class_normal(half %x) {
 
 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 @class_normal_or_fcmp_ueq_zero(half %x) {
 
 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 @fcmp_one_zero_or_class_normal_dynamic(half %x) #2 {
 
 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 @class_normal_or_fcmp_one_zero(half %x) {
 
 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 @fcmp_une_zero_or_class_normal(half %x) {
 
 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 8230f96..e7d2168 100644 (file)
 ; 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 @@ define i1 @not_isfinite_or_zero_f16(half %x) {
 ; 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 @@ define i1 @not_isfinite_or_zero_f16_commute_or(half %x) {
 ; 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_zero_f16_negzero(half %x) {
 
 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 @@ define i1 @not_isfinite_or_fabs_oeq_zero_f16(half %x) {
 ; 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]], <half 0xH7C00, half 0xH7C00>
-; 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 @@ define <2 x i1> @not_isfinite_or_zero_v2f16(<2 x half> %x) {
 ; 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]], <half 0xH7C00, half 0xH7C00>
-; 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 @@ define <2 x i1> @not_isfinite_or_zero_v2f16_pos0_neg0_vec(<2 x half> %x) {
 ; 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]], <half 0xH7C00, half 0xH7C00>
-; 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 @@ define <2 x i1> @not_isfinite_or_zero_v2f16_commute_or(<2 x half> %x) {
 ; 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 @@ define i1 @oeq_isinf_or_oeq_zero(half %x) {
 ; 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 @@ define i1 @ueq_inf_or_oeq_zero(half %x) {
 ; 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 @@ define i1 @oeq_isinf_or_fabs_oeq_zero(half %x) {
 ; 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 @@ define i1 @not_isfinite_or_zero_f16_not_inf(half %x) {
 ; 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 @@ define i1 @ueq_inf_or_ueq_zero(half %x) {
 ; 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 @@ define i1 @not_isfinite_or_zero_f16_multi_use_cmp1(half %x, ptr %ptr) {
 ; 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 @@ define i1 @olt_0_or_fabs_ueq_inf(half %x) {
 ; 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 @@ define i1 @not_isfinite_or_zero_f16_not_fabs(half %x) {
 ; 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 @@ define i1 @negated_isfinite_or_zero_f16(half %x) {
 ; 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 @@ define i1 @negated_isfinite_or_zero_f16_commute_and(half %x) {
 ; 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 @@ define i1 @negated_isfinite_or_zero_f16_negzero(half %x) {
 ; 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]], <half 0xH7C00, half 0xH7C00>
-; 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 @@ define <2 x i1> @negated_isfinite_or_zero_v2f16(<2 x half> %x) {
 ; 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]], <half 0xH7C00, half 0xH7C00>
-; 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 @@ define <2 x i1> @negated_isfinite_or_zero_v2f16_comumte(<2 x half> %x) {
 ; 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 @@ define i1 @negated_isfinite_or_zero_f16_not_une_zero(half %x) {
 ; 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 @@ define i1 @negated_isfinite_and_zero_f16(half %x) {
 ; 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 @@ define i1 @negated_isfinite_or_zero_f16_multi_use_cmp1(half %x, ptr %ptr) {
 ; 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 @negated_isfinite_or_zero_f16_fabs_wrong_value(half %x, half %y) {
 
 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_une_0_or_fcmp_une_inf(half %x) {
 
 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_one_0_and_fcmp_une_fabs_inf(half %x) {
 
 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_fabs_inf(half %x) {
 
 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 @issubnormal_and_finite_olt(half %x) {
 
 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 @oeq_isinf_and_ord(half %x) {
 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 @@ entry:
 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 @@ define i1 @ord_or_isnormalinf(half %x) #0 {
 ; -> 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 @@ define i1 @not_zero_and_subnormal_dynamic(half %x) #2 {
 ; 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)