Index: llvm/include/llvm/IR/PatternMatch.h
===================================================================
--- llvm/include/llvm/IR/PatternMatch.h
+++ llvm/include/llvm/IR/PatternMatch.h
@@ -621,18 +621,36 @@
 struct is_inf {
   bool isValue(const APFloat &C) { return C.isInfinity(); }
 };
+
+struct is_pos_inf {
+  bool isValue(const APFloat &C) { return C.isInfinity() && !C.isNegative(); }
+};
+
 /// Match a positive or negative infinity FP constant.
 /// For vectors, this includes constants with undefined elements.
 inline cstfp_pred_ty<is_inf> m_Inf() { return cstfp_pred_ty<is_inf>(); }
+inline cstfp_pred_ty<is_pos_inf> m_PosInf() {
+  return cstfp_pred_ty<is_pos_inf>();
+}
 
 struct is_smallest_normalized {
   bool isValue(const APFloat &C) { return C.isSmallestNormalized(); }
 };
 
+struct is_pos_smallest_normalized {
+  bool isValue(const APFloat &C) {
+    return !C.isNegative() && C.isSmallestNormalized();
+  }
+};
+
 inline cstfp_pred_ty<is_smallest_normalized> m_SmallestNormalized() {
   return cstfp_pred_ty<is_smallest_normalized>();
 }
 
+inline cstfp_pred_ty<is_pos_smallest_normalized> m_PosSmallestNormalized() {
+  return cstfp_pred_ty<is_pos_smallest_normalized>();
+}
+
 struct is_noninf {
   bool isValue(const APFloat &C) { return !C.isInfinity(); }
 };
Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
===================================================================
--- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1205,6 +1205,86 @@
   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<Value *, unsigned> fcmpToClassTest(FCmpInst::Predicate Pred,
+                                                    Value *LHS, Value *RHS) {
+  if (Pred == FCmpInst::FCMP_OLT || Pred == FCmpInst::FCMP_UGE) {
+    // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero
+    // fcmp uge fabs(x), smallest_normal -> ~(fcSubnormal|fcZero)
+    // fcmp olt fabs(x), +inf -> fcFinite
+    // fcmp uge fabs(x), +inf -> ~fcFinite
+
+    unsigned Mask = 0;
+    if (match(RHS, m_PosInf()))
+      Mask = fcFinite;
+    else if (match(RHS, m_PosSmallestNormalized()))
+      Mask = fcZero | fcSubnormal;
+    else
+      return {nullptr, 0};
+
+    Value *Src = LHS;
+    if (match(LHS, m_FAbs(m_Value(Src)))) {
+      if (Pred == FCmpInst::FCMP_UGE)
+        Mask = ~Mask & fcAllFlags;
+      return {Src, Mask};
+    }
+
+    return {nullptr, 0};
+  }
+
+  if (!FCmpInst::isEquality(Pred))
+    return {nullptr, 0};
+
+  if (match(RHS, m_AnyZeroFP())) {
+    switch (Pred) {
+    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:
+      return {LHS, (~fcZero & fcAllFlags) | fcNan};
+    case FCmpInst::FCMP_ONE:
+      return {LHS, ~fcNan & ~fcZero & fcAllFlags};
+    default:
+      llvm_unreachable("not fcmp equality");
+    }
+  }
+
+  // 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
+  //
+  // TODO: Handle -inf
+  if (match(RHS, m_PosInf())) {
+    // TODO: Peek through fneg (fabs x)
+    unsigned InfMask = fcPosInf;
+    Value *Src = LHS;
+    if (match(LHS, m_FAbs(m_Value(Src))))
+      InfMask |= fcNegInf;
+
+    unsigned Class;
+    if (Pred == FCmpInst::FCMP_OEQ)
+      Class = InfMask;
+    else if (Pred == FCmpInst::FCMP_UEQ)
+      Class = InfMask | fcNan;
+    else if (Pred == FCmpInst::FCMP_UNE)
+      Class = fcNan | (~InfMask & fcAllFlags);
+    else if (Pred == FCmpInst::FCMP_ONE)
+      Class = ~(fcNan | InfMask) & fcAllFlags;
+    else
+      llvm_unreachable("not fcmp equality");
+
+    return {Src, Class};
+  }
+
+  return {nullptr, 0};
+}
+
 Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
                                           bool IsAnd, bool IsLogicalSelect) {
   Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1);
@@ -1263,6 +1343,25 @@
       return Builder.CreateFCmp(PredL, LHS0, RHS0);
   }
 
+  // Turn at least two fcmps with constants into llvm.is.fpclass.
+  //
+  // If we can represent a combined value test with one class call, we can
+  // 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 [ClassValLHS, ClassMaskLHS] = fcmpToClassTest(PredL, LHS0, LHS1);
+    if (ClassValLHS) {
+      auto [ClassValRHS, ClassMaskRHS] = fcmpToClassTest(PredR, RHS0, RHS1);
+      if (ClassValLHS == ClassValRHS) {
+        unsigned CombinedMask = IsAnd ? (ClassMaskLHS & ClassMaskRHS)
+                                      : (ClassMaskLHS | ClassMaskRHS);
+        return Builder.CreateIntrinsic(
+            Intrinsic::is_fpclass, {ClassValLHS->getType()},
+            {ClassValLHS, Builder.getInt32(CombinedMask)});
+      }
+    }
+  }
+
   return nullptr;
 }
 
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,11 +10,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp ueq half %fabs, 0xH7C00
@@ -26,11 +23,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp ueq half %fabs, 0xH7C00
@@ -42,11 +36,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp ueq half %fabs, 0xH7C00
@@ -57,11 +48,8 @@
 
 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp ueq half %fabs, 0xH7C00
@@ -73,11 +61,8 @@
 ; 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:    ret <2 x i1> [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
 ;
   %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
   %cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
@@ -89,11 +74,8 @@
 ; 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:    ret <2 x i1> [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
 ;
   %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
   %cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
@@ -105,11 +87,8 @@
 ; 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:    ret <2 x i1> [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
 ;
   %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
   %cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
@@ -121,11 +100,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 612)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp oeq half %fabs, 0xH7C00
@@ -137,10 +113,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 611)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %cmpinf = fcmp ueq half %x, 0xH7C00
   %cmpzero = fcmp oeq half %x, 0xH0000
@@ -151,11 +125,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 612)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp oeq half %fabs, 0xH7C00
@@ -167,10 +138,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 611)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp ueq half %fabs, 0xH0000
@@ -194,11 +163,8 @@
 ; 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:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 615)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp ueq half %fabs, 0xH7C00
@@ -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
@@ -362,11 +324,8 @@
 ; 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:    ret i1 [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp one half %fabs, 0xH7C00
@@ -378,11 +337,8 @@
 ; 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:    ret i1 [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp one half %fabs, 0xH7C00
@@ -394,11 +350,8 @@
 ; 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:    ret i1 [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp one half %fabs, 0xH7C00
@@ -410,11 +363,8 @@
 ; 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:    ret <2 x i1> [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
 ;
   %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
   %cmpinf = fcmp one <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
@@ -426,11 +376,8 @@
 ; 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:    ret <2 x i1> [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
 ;
   %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
   %cmpinf = fcmp one <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
@@ -442,11 +389,8 @@
 ; 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:    ret i1 [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp one half %fabs, 0xH7C00
@@ -458,11 +402,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,10 +414,8 @@
 ; 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:    ret i1 [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 412)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpzero = fcmp one half %fabs, 0xH0000
@@ -525,11 +463,8 @@
 ; 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:    ret i1 [[NOT_CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 411)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp une half %fabs, 0xH7C00
@@ -560,10 +495,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,11 +505,8 @@
 
 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:    ret i1 [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 408)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpzero = fcmp one half %x, 0.0
@@ -588,11 +517,8 @@
 
 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:    ret i1 [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 411)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpzero = fcmp une half %x, 0.0
@@ -616,11 +542,8 @@
 
 define i1 @issubnormal_or_inf(half %x) {
 ; CHECK-LABEL: @issubnormal_or_inf(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 756)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp oeq half %fabs, 0xH7C00
@@ -646,11 +569,8 @@
 
 define i1 @not_issubnormal_or_inf(half %x) {
 ; CHECK-LABEL: @not_issubnormal_or_inf(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp une half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[NOT:%.*]] = and i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[NOT]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 267)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp une half %fabs, 0xH7C00
@@ -661,11 +581,8 @@
 
 define i1 @issubnormal_uge_or_inf(half %x) {
 ; CHECK-LABEL: @issubnormal_uge_or_inf(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[CLASS]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 783)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp oeq half %fabs, 0xH7C00
@@ -721,11 +638,8 @@
 
 define i1 @issubnormal_or_finite_olt(half %x) {
 ; CHECK-LABEL: @issubnormal_or_finite_olt(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp olt half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 504)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp olt half %fabs, 0xH7C00
@@ -737,11 +651,8 @@
 ; inf | nan | zero | subnormal
 define i1 @issubnormal_or_finite_uge(half %x) {
 ; CHECK-LABEL: @issubnormal_or_finite_uge(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp uge half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 759)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp uge half %fabs, 0xH7C00
@@ -752,11 +663,8 @@
 
 define i1 @issubnormal_and_finite_olt(half %x) {
 ; CHECK-LABEL: @issubnormal_and_finite_olt(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp olt half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 240)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp olt half %fabs, 0xH7C00
@@ -767,11 +675,8 @@
 
 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:    ret i1 [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmp.zero = fcmp one half %fabs, 0.0
@@ -782,11 +687,8 @@
 
 define i1 @fcmp_fabs_uge_inf_or_fabs_uge_smallest_norm(half %x) {
 ; CHECK-LABEL: @fcmp_fabs_uge_inf_or_fabs_uge_smallest_norm(
-; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
-; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp uge half [[FABS]], 0xH7C00
-; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
-; CHECK-NEXT:    ret i1 [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 783)
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %fabs = call half @llvm.fabs.f16(half %x)
   %cmpinf = fcmp uge half %fabs, 0xH7C00