[llvm] efebb4c - InstCombine: Add baseline tests for and/or of fcmp to class combine

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 13 08:21:53 PST 2022


Author: Matt Arsenault
Date: 2022-12-13T11:11:43-05:00
New Revision: efebb4c353a8a27597a3b397fbbf91b5736a86f8

URL: https://github.com/llvm/llvm-project/commit/efebb4c353a8a27597a3b397fbbf91b5736a86f8
DIFF: https://github.com/llvm/llvm-project/commit/efebb4c353a8a27597a3b397fbbf91b5736a86f8.diff

LOG: InstCombine: Add baseline tests for and/or of fcmp to class combine

This is for patterns like !isfinite || zero.

Added: 
    llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
new file mode 100644
index 000000000000..308b8913a3d0
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
@@ -0,0 +1,2066 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; Test and/or of fcmps that could be folded to llvm.is.fpclass
+
+; --------------------------------------------------------------------
+; Base pattern, !isfinite(x) || x == 0.0
+; --------------------------------------------------------------------
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpinf, %cmpzero
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, -0.0
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %fabs, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
+  %cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
+  %cmpzero = fcmp oeq <2 x half> %x, zeroinitializer
+  %class = or <2 x i1> %cmpzero, %cmpinf
+  ret <2 x i1> %class
+}
+
+; 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]]
+;
+  %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
+  %cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
+  %cmpzero = fcmp oeq <2 x half> %x, <half 0.0, half -0.0>
+  %class = or <2 x i1> %cmpzero, %cmpinf
+  ret <2 x i1> %class
+}
+
+; 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]]
+;
+  %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
+  %cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
+  %cmpzero = fcmp oeq <2 x half> %x, zeroinitializer
+  %class = or <2 x i1> %cmpinf, %cmpzero
+  ret <2 x i1> %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %cmpinf = fcmp ueq half %x, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %fabs, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH0000
+  %cmpzero = fcmp oeq half %x, 0xH7C00
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Positive test
+define i1 @not_isfinite_or_zero_f16_not_inf(half %x) {
+; CHECK-LABEL: @not_isfinite_or_zero_f16_not_inf(
+; CHECK-NEXT:    ret i1 true
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C01
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp ueq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = and i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Negative test
+define i1 @not_isfinite_or_zero_f16_multi_use_cmp0(half %x, ptr %ptr) {
+; CHECK-LABEL: @not_isfinite_or_zero_f16_multi_use_cmp0(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    store i1 [[CMPINF]], ptr [[PTR:%.*]], align 1
+; CHECK-NEXT:    [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  store i1 %cmpinf, ptr %ptr
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Negative test
+define i1 @not_isfinite_or_zero_f16_multi_use_cmp1(half %x, ptr %ptr) {
+; CHECK-LABEL: @not_isfinite_or_zero_f16_multi_use_cmp1(
+; 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:    store i1 [[CMPZERO]], ptr [[PTR:%.*]], align 1
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  store i1 %cmpzero, ptr %ptr
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xHFC00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Negative test
+define i1 @olt_0_or_fabs_ueq_inf(half %x) {
+; CHECK-LABEL: @olt_0_or_fabs_ueq_inf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[CMPZERO:%.*]] = fcmp olt half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp olt half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; 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:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ult half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Negative test
+define i1 @not_isfinite_or_zero_f16_multi_not_0(half %x, ptr %ptr) {
+; CHECK-LABEL: @not_isfinite_or_zero_f16_multi_not_0(
+; 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]], 0xH3C00
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 1.0
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Negative test
+define i1 @not_isfinite_or_zero_f16_fabs_wrong_val(half %x, half %y) {
+; CHECK-LABEL: @not_isfinite_or_zero_f16_fabs_wrong_val(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[Y:%.*]])
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %y)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; Negative test
+define i1 @not_isfinite_or_zero_f16_not_fabs(half %x) {
+; CHECK-LABEL: @not_isfinite_or_zero_f16_not_fabs(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.canonicalize.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]]
+;
+  %fabs = call half @llvm.canonicalize.f16(half %x)
+  %cmpinf = fcmp ueq half %fabs, 0xH7C00
+  %cmpzero = fcmp oeq half %x, 0xH0000
+  %class = or i1 %cmpzero, %cmpinf
+  ret i1 %class
+}
+
+; --------------------------------------------------------------------
+; Negated pattern, isfinite(x) && !(x == 0.0)
+; --------------------------------------------------------------------
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, 0xH0000
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, 0xH0000
+  %not.class = and i1 %cmpinf, %cmpzero
+  ret i1 %not.class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, -0.0
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; 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]]
+;
+  %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
+  %cmpinf = fcmp one <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
+  %cmpzero = fcmp une <2 x half> %x, zeroinitializer
+  %not.class = and <2 x i1> %cmpzero, %cmpinf
+  ret <2 x i1> %not.class
+}
+
+; 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]]
+;
+  %fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
+  %cmpinf = fcmp one <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
+  %cmpzero = fcmp une <2 x half> %x, zeroinitializer
+  %not.class = and <2 x i1> %cmpinf, %cmpzero
+  ret <2 x i1> %not.class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp one half %x, 0xH0000
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, 0xH0000
+  %not.class = or i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpzero = fcmp one half %fabs, 0xH0000
+  %cmpinf = fcmp une half %x, 0xH7C00
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; Negative test
+define i1 @negated_isfinite_or_zero_f16_multi_use_cmp0(half %x, ptr %ptr) {
+; CHECK-LABEL: @negated_isfinite_or_zero_f16_multi_use_cmp0(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp one half [[FABS]], 0xH7C00
+; CHECK-NEXT:    store i1 [[CMPINF]], ptr [[PTR:%.*]], align 1
+; CHECK-NEXT:    [[CMPZERO:%.*]] = fcmp une half [[X]], 0xH0000
+; CHECK-NEXT:    [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[NOT_CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  store i1 %cmpinf, ptr %ptr
+  %cmpzero = fcmp une half %x, 0xH0000
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; Negative test
+define i1 @negated_isfinite_or_zero_f16_multi_use_cmp1(half %x, ptr %ptr) {
+; CHECK-LABEL: @negated_isfinite_or_zero_f16_multi_use_cmp1(
+; 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:    store i1 [[CMPZERO]], ptr [[PTR:%.*]], align 1
+; CHECK-NEXT:    [[NOT_CLASS:%.*]] = and i1 [[CMPZERO]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[NOT_CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, 0xH0000
+  store i1 %cmpzero, ptr %ptr
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp une half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, 0xH0000
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; Negative test
+define i1 @negated_isfinite_or_zero_f16_fabs_wrong_value(half %x, half %y) {
+; CHECK-LABEL: @negated_isfinite_or_zero_f16_fabs_wrong_value(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[Y:%.*]])
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %y)
+  %cmpinf = fcmp one half %fabs, 0xH7C00
+  %cmpzero = fcmp une half %x, 0xH0000
+  %not.class = and i1 %cmpzero, %cmpinf
+  ret i1 %not.class
+}
+
+; --------------------------------------------------------------------
+; Other fcmp to class recognition
+; --------------------------------------------------------------------
+
+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]]
+;
+  %cmpzero = fcmp une half %x, 0.0
+  %cmpinf = fcmp une half %x, 0xH7C00
+  %or = or i1 %cmpzero, %cmpinf
+  ret i1 %or
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpzero = fcmp one half %x, 0.0
+  %cmpinf = fcmp une half %fabs, 0xH7C00
+  %and = and i1 %cmpzero, %cmpinf
+  ret i1 %and
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpzero = fcmp une half %x, 0.0
+  %cmpinf = fcmp une half %fabs, 0xH7C00
+  %and = and i1 %cmpzero, %cmpinf
+  ret i1 %and
+}
+
+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]]
+;
+  %cmpzero = fcmp une half %x, 0.0
+  %cmpinf = fcmp une half %x, 0xHFC00
+  %or = or i1 %cmpzero, %cmpinf
+  ret i1 %or
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %class
+}
+
+define i1 @olt_smallest_normal_or_inf(half %x) {
+; CHECK-LABEL: @olt_smallest_normal_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 [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400 ; missing fabs
+  %class = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %class
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp une half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp uge half %fabs, 0xH0400
+  %not = and i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %not
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp uge half %fabs, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %class
+}
+
+; Negative test, not smallest normal
+define i1 @issubnormal_or_inf_wrong_val(half %x) {
+; CHECK-LABEL: @issubnormal_or_inf_wrong_val(
+; 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]], 0xH0401
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH0401
+  %class = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %class
+}
+
+define i1 @issubnormal_or_inf_neg_smallest_normal(half %x) {
+; CHECK-LABEL: @issubnormal_or_inf_neg_smallest_normal(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    ret i1 [[CMPINF]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH8400
+  %class = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %class
+}
+
+define i1 @fneg_fabs_olt_neg_smallest_normal_or_inf(half %x) {
+; CHECK-LABEL: @fneg_fabs_olt_neg_smallest_normal_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 ogt half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMPINF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %fneg.fabs = fneg half %fabs
+  %cmp.smallest.normal = fcmp olt half %fneg.fabs, 0xH8400
+  %class = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %class
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp olt half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
+  %or = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %or
+}
+
+; 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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp uge half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
+  %or = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %or
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp olt half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
+  %and = and i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %and
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmp.zero = fcmp one half %fabs, 0.0
+  %cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
+  %or = or i1 %cmp.smallest.normal, %cmp.zero
+  ret i1 %or
+}
+
+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]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp uge half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp uge half %fabs, 0xH0400
+  %or = or i1 %cmp.smallest.normal, %cmpinf
+  ret i1 %or
+}
+
+; --------------------------------------------------------------------
+; Test ord/uno
+; --------------------------------------------------------------------
+
+define i1 @is_finite_and_ord(half %x) {
+; CHECK-LABEL: @is_finite_and_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[ORD]], [[IS_FINITE]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.finite = fcmp ueq half %fabs, 0xH7C00
+  %ord = fcmp ord half %x, %x
+  %and = and i1 %ord, %is.finite
+  ret i1 %and
+}
+
+define i1 @is_finite_and_uno(half %x) {
+; CHECK-LABEL: @is_finite_and_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[UNO]], [[IS_FINITE]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.finite = fcmp ueq half %fabs, 0xH7C00
+  %uno = fcmp uno half %x, %x
+  %and = and i1 %uno, %is.finite
+  ret i1 %and
+}
+
+define i1 @is_finite_or_ord(half %x) {
+; CHECK-LABEL: @is_finite_or_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ORD]], [[IS_FINITE]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.finite = fcmp ueq half %fabs, 0xH7C00
+  %ord = fcmp ord half %x, %x
+  %or = or i1 %ord, %is.finite
+  ret i1 %or
+}
+
+define i1 @is_finite_or_uno(half %x) {
+; CHECK-LABEL: @is_finite_or_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[UNO]], [[IS_FINITE]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.finite = fcmp ueq half %fabs, 0xH7C00
+  %uno = fcmp uno half %x, %x
+  %or = or i1 %uno, %is.finite
+  ret i1 %or
+}
+
+define i1 @oeq_isinf_or_uno(half %x) {
+; CHECK-LABEL: @oeq_isinf_or_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMPINF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0000
+  %class = or i1 %cmpinf, %uno
+  ret i1 %class
+}
+
+define i1 @oeq_isinf_or_ord(half %x) {
+; CHECK-LABEL: @oeq_isinf_or_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMPINF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %uno = fcmp ord half %x, 0xH0000
+  %class = or i1 %cmpinf, %uno
+  ret i1 %class
+}
+
+define i1 @oeq_isinf_and_uno(half %x) {
+; CHECK-LABEL: @oeq_isinf_and_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMPINF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0000
+  %and = and i1 %cmpinf, %uno
+  ret i1 %and
+}
+
+define i1 @oeq_isinf_and_ord(half %x) {
+; CHECK-LABEL: @oeq_isinf_and_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[CMPINF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMPINF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %cmpinf = fcmp oeq half %fabs, 0xH7C00
+  %uno = fcmp ord half %x, 0xH0000
+  %and = and i1 %cmpinf, %uno
+  ret i1 %and
+}
+
+; --------------------------------------------------------------------
+; isnormal(x) || x == 0.0
+; --------------------------------------------------------------------
+
+define i1 @isnormal_or_zero(half %x) #0 {
+; CHECK-LABEL: @isnormal_or_zero(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ISEQ:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    [[FABS:%.*]] = tail call half @llvm.fabs.f16(half [[X]])
+; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ult half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[ISNORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[ISEQ]], [[ISINF]]
+; CHECK-NEXT:    [[AND1:%.*]] = and i1 [[ISNORMAL]], [[AND]]
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq half [[X]], 0xH0000
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1 [[CMP]], [[AND1]]
+; CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
+;
+entry:
+  %iseq = fcmp ord half %x, 0xH0000
+  %fabs = tail call half @llvm.fabs.f16(half %x)
+  %isinf = fcmp ult half %fabs, 0xH7C00
+  %isnormal = fcmp uge half %fabs, 0xH0400
+  %and = and i1 %iseq, %isinf
+  %and1 = and i1 %isnormal, %and
+  %cmp = fcmp oeq half %x, 0xH0000
+  %spec.select = or i1 %cmp, %and1
+  ret i1 %spec.select
+}
+
+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:    ret i1 [[OR]]
+;
+entry:
+  %fabs = tail call half @llvm.fabs.f16(half %x)
+  %is.normal = fcmp uge half %fabs, 0xH0400
+  %is.zero = fcmp oeq half %x, 0xH0000
+  %or = or i1 %is.normal, %is.zero
+  ret i1 %or
+}
+
+; --------------------------------------------------------------------
+; smallest_normal check part of isnormal(x)
+; --------------------------------------------------------------------
+
+; -> ord
+define i1 @isnormalinf_or_ord(half %x) #0 {
+; CHECK-LABEL: @isnormalinf_or_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[IS_NORMAL_INF]], [[IS_ORD]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %is.ord = fcmp ord half %x, 0xH0000
+  %or = or i1 %is.normal.inf, %is.ord
+  ret i1 %or
+}
+
+; -> ord
+define i1 @ord_or_isnormalinf(half %x) #0 {
+; CHECK-LABEL: @ord_or_isnormalinf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[IS_ORD]], [[IS_NORMAL_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %is.ord = fcmp ord half %x, 0xH0000
+  %or = or i1 %is.ord, %is.normal.inf
+  ret i1 %or
+}
+
+; No fabs
+; -> 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:    ret i1 [[OR]]
+;
+  %is.normal.inf = fcmp oge half %x, 0xH0400
+  %is.une = fcmp une half %x, 0xH0000
+  %or = or i1 %is.une, %is.normal.inf
+  ret i1 %or
+}
+
+; -> normal | inf
+define i1 @isnormalinf_or_inf(half %x) #0 {
+; CHECK-LABEL: @isnormalinf_or_inf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[IS_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %is.inf = fcmp oeq half %fabs, 0xH7C00
+  %or = or i1 %is.normal.inf, %is.inf
+  ret i1 %or
+}
+
+; -> pinf | pnormal
+define i1 @posisnormalinf_or_posinf(half %x) #0 {
+; CHECK-LABEL: @posisnormalinf_or_posinf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_POS_NORMAL_INF:%.*]] = fcmp oge half [[X]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[IS_POS_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.pos.normal.inf = fcmp oge half %x, 0xH0400
+  %is.inf = fcmp oeq half %fabs, 0xH7C00
+  %or = or i1 %is.pos.normal.inf, %is.inf
+  ret i1 %or
+}
+
+; -> normal | inf
+define i1 @isnormalinf_or_posinf(half %x) #0 {
+; CHECK-LABEL: @isnormalinf_or_posinf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_POS_INF:%.*]] = fcmp oeq half [[X]], 0xH7C00
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[IS_NORMAL_INF]], [[IS_POS_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %is.pos.inf = fcmp oeq half %x, 0xH7C00
+  %or = or i1 %is.normal.inf, %is.pos.inf
+  ret i1 %or
+}
+
+; -> pinf|ninf
+define i1 @isnormalinf_and_inf(half %x) #0 {
+; CHECK-LABEL: @isnormalinf_and_inf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[IS_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %is.inf = fcmp oeq half %fabs, 0xH7C00
+  %and = and i1 %is.normal.inf, %is.inf
+  ret i1 %and
+}
+
+; -> pinf
+define i1 @posisnormalinf_and_posinf(half %x) #0 {
+; CHECK-LABEL: @posisnormalinf_and_posinf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_POS_NORMAL_INF:%.*]] = fcmp oge half [[X]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[IS_POS_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.pos.normal.inf = fcmp oge half %x, 0xH0400
+  %is.inf = fcmp oeq half %fabs, 0xH7C00
+  %and = and i1 %is.pos.normal.inf, %is.inf
+  ret i1 %and
+}
+
+; -> pinf
+define i1 @isnormalinf_and_posinf(half %x) #0 {
+; CHECK-LABEL: @isnormalinf_and_posinf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_POS_INF:%.*]] = fcmp oeq half [[X]], 0xH7C00
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[IS_NORMAL_INF]], [[IS_POS_INF]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %is.pos.inf = fcmp oeq half %x, 0xH7C00
+  %and = and i1 %is.normal.inf, %is.pos.inf
+  ret i1 %and
+}
+
+; --------------------------------------------------------------------
+; smallest_normal check part of isnormal(x) with inverted compare
+; --------------------------------------------------------------------
+
+; -> true
+define i1 @not_isnormalinf_or_ord(half %x) #0 {
+; CHECK-LABEL: @not_isnormalinf_or_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[NOT_IS_NORMAL_INF:%.*]] = fcmp ult half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[NOT_IS_NORMAL_INF]], [[IS_ORD]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %not.is.normal.inf = fcmp ult half %fabs, 0xH0400
+  %is.ord = fcmp ord half %x, 0xH0000
+  %or = or i1 %not.is.normal.inf, %is.ord
+  ret i1 %or
+}
+
+; -> subnormal | zero
+define i1 @not_isnormalinf_and_ord(half %x) #0 {
+; CHECK-LABEL: @not_isnormalinf_and_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[NOT_IS_NORMAL_INF:%.*]] = fcmp ult half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[NOT_IS_NORMAL_INF]], [[IS_ORD]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %not.is.normal.inf = fcmp ult half %fabs, 0xH0400
+  %is.ord = fcmp ord half %x, 0xH0000
+  %and = and i1 %not.is.normal.inf, %is.ord
+  ret i1 %and
+}
+
+; -> ~ninf
+define i1 @not_isnormalinf_or_inf(half %x) #0 {
+; CHECK-LABEL: @not_isnormalinf_or_inf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[NOT_IS_NORMAL_INF:%.*]] = fcmp ult half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp olt half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[NOT_IS_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %not.is.normal.inf = fcmp ult half %fabs, 0xH0400
+  %is.inf = fcmp olt half %fabs, 0xH7C00
+  %or = or i1 %not.is.normal.inf, %is.inf
+  ret i1 %or
+}
+
+; -> subnormal | zero | nan
+define i1 @not_isnormalinf_or_uno(half %x) #0 {
+; CHECK-LABEL: @not_isnormalinf_or_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[NOT_IS_NORMAL_INF:%.*]] = fcmp ult half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[NOT_IS_NORMAL_INF]], [[IS_UNO]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %not.is.normal.inf = fcmp ult half %fabs, 0xH0400
+  %is.uno = fcmp uno half %fabs, 0.0
+  %or = or i1 %not.is.normal.inf, %is.uno
+  ret i1 %or
+}
+
+; -> subnormal | zero | nan
+define i1 @not_isnormalinf_or_uno_nofabs(half %x) #0 {
+; CHECK-LABEL: @not_isnormalinf_or_uno_nofabs(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[NOT_IS_NORMAL_INF:%.*]] = fcmp ult half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[IS_UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[NOT_IS_NORMAL_INF]], [[IS_UNO]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %not.is.normal.inf = fcmp ult half %fabs, 0xH0400
+  %is.uno = fcmp uno half %x, 0.0
+  %or = or i1 %not.is.normal.inf, %is.uno
+  ret i1 %or
+}
+
+; -> ~pnormal
+define i1 @not_negisnormalinf_or_inf(half %x) #0 {
+; CHECK-LABEL: @not_negisnormalinf_or_inf(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[NOT_IS_NEG_NORMAL_INF:%.*]] = fcmp ult half [[X]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[NOT_IS_NEG_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %not.is.neg.normal.inf = fcmp ult half %x, 0xH0400
+  %is.inf = fcmp oeq half %fabs, 0xH7C00
+  %or = or i1 %not.is.neg.normal.inf, %is.inf
+  ret i1 %or
+}
+
+; -> ~pnormal
+define i1 @not_negisnormalinf_or_posinf(half %x) #0 {
+; CHECK-LABEL: @not_negisnormalinf_or_posinf(
+; CHECK-NEXT:    [[NOT_IS_POS_NORMAL_INF:%.*]] = fcmp ult half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq half [[X]], 0xH7C00
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[NOT_IS_POS_NORMAL_INF]], [[IS_INF]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %not.is.pos.normal.inf = fcmp ult half %x, 0xH0400
+  %is.inf = fcmp oeq half %x, 0xH7C00
+  %or = or i1 %not.is.pos.normal.inf, %is.inf
+  ret i1 %or
+}
+
+; -> ninf | nnormal
+define i1 @not_isposnormalinf_and_isnormalinf(half %x) #0 {
+; CHECK-LABEL: @not_isposnormalinf_and_isnormalinf(
+; CHECK-NEXT:    [[NOT_IS_POS_NORMAL_INF:%.*]] = fcmp ult half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X]])
+; CHECK-NEXT:    [[IS_NORMAL_INF:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[NOT_IS_POS_NORMAL_INF]], [[IS_NORMAL_INF]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %not.is.pos.normal.inf = fcmp ult half %x, 0xH0400
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.normal.inf = fcmp oge half %fabs, 0xH0400
+  %and = and i1 %not.is.pos.normal.inf, %is.normal.inf
+  ret i1 %and
+}
+
+; -> ord
+define i1 @olt_smallest_normal_or_ord(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_or_ord(
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ord = fcmp ord half %x, 0.0
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %ord
+  ret i1 %class
+}
+
+; -> ~pinf
+define i1 @olt_smallest_normal_or_uno(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_or_uno(
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %uno = fcmp uno half %x, 0.0
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %uno
+  ret i1 %class
+}
+
+define i1 @olt_smallest_normal_or_finite(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_or_finite(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[IS_FINITE:%.*]] = fcmp olt half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[IS_FINITE]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.finite = fcmp olt half %fabs, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %is.finite
+  ret i1 %class
+}
+
+define i1 @uge_smallest_normal_or_ord(half %x) #0 {
+; CHECK-LABEL: @uge_smallest_normal_or_ord(
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ord = fcmp ord half %x, 0.0
+  %cmp.smallest.normal = fcmp uge half %x, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %ord
+  ret i1 %class
+}
+
+; -> nan | pnormal | pinf
+define i1 @uge_smallest_normal_or_uno(half %x) #0 {
+; CHECK-LABEL: @uge_smallest_normal_or_uno(
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %uno = fcmp uno half %x, 0.0
+  %cmp.smallest.normal = fcmp uge half %x, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %uno
+  ret i1 %class
+}
+
+; -> uno
+define i1 @uge_smallest_normal_and_uno(half %x) #0 {
+; CHECK-LABEL: @uge_smallest_normal_and_uno(
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[CMP_SMALLEST_NORMAL]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %uno = fcmp uno half %x, 0.0
+  %cmp.smallest.normal = fcmp uge half %x, 0xH0400
+  %class = and i1 %cmp.smallest.normal, %uno
+  ret i1 %class
+}
+
+; -> true
+define i1 @olt_infinity_or_finite(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_or_finite(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[LT_INFINITY]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %cmp.smallest.normal, %lt.infinity
+  ret i1 %class
+}
+
+; -> zero|subnormal|normal
+define i1 @olt_infinity_and_finite(half %x) #0 { ; bustttedddd
+; CHECK-LABEL: @olt_infinity_and_finite(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[CMP_SMALLEST_NORMAL]], [[LT_INFINITY]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = and i1 %cmp.smallest.normal, %lt.infinity
+  ret i1 %class
+}
+
+; -> ord
+define i1 @olt_infinity_or_ord(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_or_ord(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[LT_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %ord = fcmp ord half %x, 0xH0400
+  %class = or i1 %lt.infinity, %ord
+  ret i1 %class
+}
+
+; -> ~posinf
+define i1 @olt_infinity_or_uno(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_or_uno(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[LT_INFINITY]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0400
+  %class = or i1 %lt.infinity, %uno
+  ret i1 %class
+}
+
+define i1 @olt_infinity_or_subnormal(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_or_subnormal(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X]])
+; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[LT_INFINITY]], [[IS_SUBNORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.subnormal = fcmp olt half %fabs, 0xH0400
+  %class = or i1 %lt.infinity, %is.subnormal
+  ret i1 %class
+}
+
+define i1 @olt_infinity_and_subnormal(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_and_subnormal(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X]])
+; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[LT_INFINITY]], [[IS_SUBNORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.subnormal = fcmp olt half %fabs, 0xH0400
+  %class = and i1 %lt.infinity, %is.subnormal
+  ret i1 %class
+}
+
+define i1 @olt_infinity_and_not_subnormal(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_and_not_subnormal(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X]])
+; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[LT_INFINITY]], [[IS_SUBNORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %is.subnormal = fcmp olt half %fabs, 0xH0400
+  %not.subnormal = xor i1 %is.subnormal, true
+  %class = and i1 %lt.infinity, %not.subnormal
+  ret i1 %class
+}
+
+; -> ninf
+define i1 @olt_infinity_and_ueq_inf(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_and_ueq_inf(
+; CHECK-NEXT:    [[LT_INFINITY:%.*]] = fcmp olt half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X]])
+; CHECK-NEXT:    [[EQ_INF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[LT_INFINITY]], [[EQ_INF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %eq.inf = fcmp ueq half %fabs, 0xH7C00
+  %class = and i1 %lt.infinity, %eq.inf
+  ret i1 %class
+}
+
+; -> true
+define i1 @olt_infinity_or_ueq_inf(half %x) #0 {
+; CHECK-LABEL: @olt_infinity_or_ueq_inf(
+; CHECK-NEXT:    ret i1 true
+;
+  %lt.infinity = fcmp olt half %x, 0xH7C00
+  %eq.inf = fcmp ueq half %x, 0xH7C00
+  %class = or i1 %lt.infinity, %eq.inf
+  ret i1 %class
+}
+
+; -> pnormal
+define i1 @olt_smallest_normal_or_ueq_inf(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_or_ueq_inf(
+; CHECK-NEXT:    [[LT_NORMAL:%.*]] = fcmp olt half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[EQ_INF:%.*]] = fcmp ueq half [[X]], 0xH7C00
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[LT_NORMAL]], [[EQ_INF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.normal = fcmp olt half %x, 0xH0400
+  %eq.inf = fcmp ueq half %x, 0xH7C00
+  %class = or i1 %lt.normal, %eq.inf
+  ret i1 %class
+}
+
+; -> ~pinf
+define i1 @olt_smallest_normal_or_une_inf(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_or_une_inf(
+; CHECK-NEXT:    [[LT_NORMAL:%.*]] = fcmp olt half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[EQ_INF:%.*]] = fcmp une half [[X]], 0xH7C00
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[LT_NORMAL]], [[EQ_INF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.normal = fcmp olt half %x, 0xH0400
+  %eq.inf = fcmp une half %x, 0xH7C00
+  %class = or i1 %lt.normal, %eq.inf
+  ret i1 %class
+}
+
+; -> ninf | nnormal | subnormal | zero
+define i1 @olt_smallest_normal_and_une_inf(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_and_une_inf(
+; CHECK-NEXT:    [[LT_NORMAL:%.*]] = fcmp olt half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[EQ_INF:%.*]] = fcmp une half [[X]], 0xH7C00
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[LT_NORMAL]], [[EQ_INF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.normal = fcmp olt half %x, 0xH0400
+  %eq.inf = fcmp une half %x, 0xH7C00
+  %class = and i1 %lt.normal, %eq.inf
+  ret i1 %class
+}
+
+define i1 @olt_smallest_normal_and_une_inf_or_oeq_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_and_une_inf_or_oeq_smallest_normal(
+; CHECK-NEXT:    [[LT_NORMAL:%.*]] = fcmp olt half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[EQ_INF:%.*]] = fcmp une half [[X]], 0xH7C00
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[LT_NORMAL]], [[EQ_INF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.normal = fcmp olt half %x, 0xH0400
+  %eq.inf = fcmp une half %x, 0xH7C00
+  %class = and i1 %lt.normal, %eq.inf
+  %eq.normal = fcmp oeq half %x, 0xH0400
+  %eq.largest.normal = or i1 %eq.normal, %class
+  ret i1 %class
+}
+
+define i1 @olt_smallest_normal_and_une_inf_or_one_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @olt_smallest_normal_and_une_inf_or_one_smallest_normal(
+; CHECK-NEXT:    [[LT_NORMAL:%.*]] = fcmp olt half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    [[EQ_INF:%.*]] = fcmp une half [[X]], 0xH7C00
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[LT_NORMAL]], [[EQ_INF]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %lt.normal = fcmp olt half %x, 0xH0400
+  %eq.inf = fcmp une half %x, 0xH7C00
+  %class = and i1 %lt.normal, %eq.inf
+  %ne.normal = fcmp one half %x, 0xH0400
+  %eq.largest.normal = or i1 %ne.normal, %class
+  ret i1 %class
+}
+
+define i1 @oge_fabs_eq_inf_and_ord(half %x) #0 {
+; CHECK-LABEL: @oge_fabs_eq_inf_and_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[OGE_FABS_INF:%.*]] = fcmp oge half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[OGE_FABS_INF]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %oge.fabs.inf = fcmp oge half %fabs, 0xH7C00
+  %ord = fcmp ord half %x, 0xH0000
+  %and = and i1 %oge.fabs.inf, %ord
+  ret i1 %and
+}
+
+define i1 @oge_eq_inf_and_ord(half %x) #0 {
+; CHECK-LABEL: @oge_eq_inf_and_ord(
+; CHECK-NEXT:    [[OGE_FABS_INF:%.*]] = fcmp oge half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[OGE_FABS_INF]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %oge.fabs.inf = fcmp oge half %x, 0xH7C00
+  %ord = fcmp ord half %x, 0xH0000
+  %and = and i1 %oge.fabs.inf, %ord
+  ret i1 %and
+}
+
+define i1 @oge_fabs_eq_inf_or_uno(half %x) #0 {
+; CHECK-LABEL: @oge_fabs_eq_inf_or_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[OGE_FABS_INF:%.*]] = fcmp oge half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[OGE_FABS_INF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %oge.fabs.inf = fcmp oge half %fabs, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0000
+  %or = or i1 %oge.fabs.inf, %uno
+  ret i1 %or
+}
+
+define i1 @oge_eq_inf_or_uno(half %x) #0 {
+; CHECK-LABEL: @oge_eq_inf_or_uno(
+; CHECK-NEXT:    [[OGE_FABS_INF:%.*]] = fcmp oge half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[OGE_FABS_INF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %oge.fabs.inf = fcmp oge half %x, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0000
+  %or = or i1 %oge.fabs.inf, %uno
+  ret i1 %or
+}
+
+define i1 @ult_fabs_eq_inf_and_ord(half %x) #0 {
+; CHECK-LABEL: @ult_fabs_eq_inf_and_ord(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[ULT_FABS_INF:%.*]] = fcmp ult half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[ULT_FABS_INF]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %ult.fabs.inf = fcmp ult half %fabs, 0xH7C00
+  %ord = fcmp ord half %x, 0xH0000
+  %and = and i1 %ult.fabs.inf, %ord
+  ret i1 %and
+}
+
+define i1 @ult_eq_inf_and_ord(half %x) #0 {
+; CHECK-LABEL: @ult_eq_inf_and_ord(
+; CHECK-NEXT:    [[ULT_FABS_INF:%.*]] = fcmp ult half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[ULT_FABS_INF]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %ult.fabs.inf = fcmp ult half %x, 0xH7C00
+  %ord = fcmp ord half %x, 0xH0000
+  %and = and i1 %ult.fabs.inf, %ord
+  ret i1 %and
+}
+
+define i1 @ult_fabs_eq_inf_or_uno(half %x) #0 {
+; CHECK-LABEL: @ult_fabs_eq_inf_or_uno(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[ULT_FABS_INF:%.*]] = fcmp ult half [[FABS]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ULT_FABS_INF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %ult.fabs.inf = fcmp ult half %fabs, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0000
+  %or = or i1 %ult.fabs.inf, %uno
+  ret i1 %or
+}
+
+define i1 @ult_eq_inf_or_uno(half %x) #0 {
+; CHECK-LABEL: @ult_eq_inf_or_uno(
+; CHECK-NEXT:    [[ULT_FABS_INF:%.*]] = fcmp ult half [[X:%.*]], 0xH7C00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ULT_FABS_INF]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %ult.fabs.inf = fcmp ult half %x, 0xH7C00
+  %uno = fcmp uno half %x, 0xH0000
+  %or = or i1 %ult.fabs.inf, %uno
+  ret i1 %or
+}
+
+
+; Can't do anything with this
+define i1 @oeq_neginfinity_or_oeq_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_or_oeq_smallest_normal(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp oeq half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[OEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp oeq half %x, 0xH0400
+  %class = or i1 %oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ninf | fcZero | fcSubnormal
+define i1 @oeq_neginfinity_or_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_or_olt_smallest_normal(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[OEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ninf
+define i1 @oeq_neginfinity_and_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_and_olt_smallest_normal(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[OEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = and i1 %oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ninf | pnormal | pinf
+define i1 @oeq_neginfinity_or_oge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_or_oge_smallest_normal(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp oge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[OEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp oge half %x, 0xH0400
+  %class = or i1 %oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> false
+define i1 @oeq_neginfinity_and_oge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_and_oge_smallest_normal(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp oge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[OEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp oge half %x, 0xH0400
+  %class = and i1 %oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ord
+define i1 @oeq_neginfinity_or_ord(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_or_ord(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[OEQ_NEG_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %ord = fcmp ord half %x, 0.0
+  %class = or i1 %oeq.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> ninf
+define i1 @oeq_neginfinity_and_ord(half %x) #0 {
+; CHECK-LABEL: @oeq_neginfinity_and_ord(
+; CHECK-NEXT:    [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[OEQ_NEG_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
+  %ord = fcmp ord half %x, 0.0
+  %class = and i1 %oeq.neg.infinity, %ord
+  ret i1 %class
+}
+
+; can't do anything with this
+define i1 @une_neginfinity_or_oeq_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @une_neginfinity_or_oeq_smallest_normal(
+; CHECK-NEXT:    [[UNE_NEG_INFINITY:%.*]] = fcmp une half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp oeq half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[UNE_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %une.neg.infinity = fcmp une half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp oeq half %x, 0xH0400
+  %class = or i1 %une.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> true
+define i1 @une_neginfinity_or_ord(half %x) #0 {
+; CHECK-LABEL: @une_neginfinity_or_ord(
+; CHECK-NEXT:    [[UNE_NEG_INFINITY:%.*]] = fcmp une half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[UNE_NEG_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %une.neg.infinity = fcmp une half %x, 0xHFC00
+  %ord = fcmp ord half %x, 0.0
+  %class = or i1 %une.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> ~(nan | ninf)
+define i1 @une_neginfinity_and_ord(half %x) #0 {
+; CHECK-LABEL: @une_neginfinity_and_ord(
+; CHECK-NEXT:    [[UNE_NEG_INFINITY:%.*]] = fcmp une half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[UNE_NEG_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %une.neg.infinity = fcmp une half %x, 0xHFC00
+  %ord = fcmp ord half %x, 0.0
+  %class = and i1 %une.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> ord
+define i1 @one_neginfinity_or_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @one_neginfinity_or_olt_smallest_normal(
+; CHECK-NEXT:    [[ONE_NEG_INFINITY:%.*]] = fcmp one half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[ONE_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %one.neg.infinity = fcmp one half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %one.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ~(nan|ninf)
+define i1 @one_neginfinity_and_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @one_neginfinity_and_olt_smallest_normal(
+; CHECK-NEXT:    [[ONE_NEG_INFINITY:%.*]] = fcmp one half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[ONE_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %one.neg.infinity = fcmp one half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = and i1 %one.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ~ninf
+define i1 @one_neginfinity_or_uno(half %x) #0 {
+; CHECK-LABEL: @one_neginfinity_or_uno(
+; CHECK-NEXT:    [[ONE_NEG_INFINITY:%.*]] = fcmp one half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[ONE_NEG_INFINITY]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %one.neg.infinity = fcmp one half %x, 0xHFC00
+  %uno = fcmp uno half %x, 0.0
+  %class = or i1 %one.neg.infinity, %uno
+  ret i1 %class
+}
+
+; -> ~ninf
+define i1 @one_neginfinity_and_ord(half %x) #0 {
+; CHECK-LABEL: @one_neginfinity_and_ord(
+; CHECK-NEXT:    [[ONE_NEG_INFINITY:%.*]] = fcmp one half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[ONE_NEG_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %one.neg.infinity = fcmp one half %x, 0xHFC00
+  %ord = fcmp uno half %x, 0.0
+  %class = and i1 %one.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> pnormal|pinf
+define i1 @one_neginfinity_and_uge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @one_neginfinity_and_uge_smallest_normal(
+; CHECK-NEXT:    [[ONE_NEG_INFINITY:%.*]] = fcmp one half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[ONE_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %one.neg.infinity = fcmp one half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp uge half %x, 0xH0400
+  %class = and i1 %one.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ~(pnormal|pinf)
+define i1 @ueq_neginfinity_or_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @ueq_neginfinity_or_olt_smallest_normal(
+; CHECK-NEXT:    [[UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[UEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ueq.neg.infinity = fcmp ueq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %ueq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ninf
+define i1 @ueq_neginfinity_and_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @ueq_neginfinity_and_olt_smallest_normal(
+; CHECK-NEXT:    [[UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[UEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ueq.neg.infinity = fcmp ueq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = and i1 %ueq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> nan|ninf
+define i1 @ueq_neginfinity_or_uno(half %x) #0 {
+; CHECK-LABEL: @ueq_neginfinity_or_uno(
+; CHECK-NEXT:    [[UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[UEQ_NEG_INFINITY]], [[UNO]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ueq.neg.infinity = fcmp ueq half %x, 0xHFC00
+  %uno = fcmp uno half %x, 0.0
+  %class = or i1 %ueq.neg.infinity, %uno
+  ret i1 %class
+}
+
+; -> nan|ninf
+define i1 @ueq_neginfinity_and_ord(half %x) #0 {
+; CHECK-LABEL: @ueq_neginfinity_and_ord(
+; CHECK-NEXT:    [[UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp uno half [[X]], 0xH0000
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[UEQ_NEG_INFINITY]], [[ORD]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ueq.neg.infinity = fcmp ueq half %x, 0xHFC00
+  %ord = fcmp uno half %x, 0.0
+  %class = and i1 %ueq.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> uno
+define i1 @ueq_neginfinity_and_uge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @ueq_neginfinity_and_uge_smallest_normal(
+; CHECK-NEXT:    [[UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[UEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %ueq.neg.infinity = fcmp ueq half %x, 0xHFC00
+  %cmp.smallest.normal = fcmp uge half %x, 0xH0400
+  %class = and i1 %ueq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ord
+define i1 @fabs_oeq_neginfinity_or_ord(half %x) #0 {
+; CHECK-LABEL: @fabs_oeq_neginfinity_or_ord(
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    ret i1 [[ORD]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.oeq.neg.infinity = fcmp oeq half %fabs, 0xHFC00
+  %ord = fcmp ord half %x, 0.0
+  %class = or i1 %fabs.oeq.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> true
+define i1 @fabs_une_neginfinity_or_ord(half %x) #0 {
+; CHECK-LABEL: @fabs_une_neginfinity_or_ord(
+; CHECK-NEXT:    ret i1 true
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.une.neg.infinity = fcmp une half %fabs, 0xHFC00
+  %ord = fcmp une half %x, 0.0
+  %class = or i1 %fabs.une.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> une
+define i1 @fabs_une_neginfinity_and_ord(half %x) #0 {
+; CHECK-LABEL: @fabs_une_neginfinity_and_ord(
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp une half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    ret i1 [[ORD]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.une.neg.infinity = fcmp une half %fabs, 0xHFC00
+  %ord = fcmp une half %x, 0.0
+  %class = and i1 %fabs.une.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> false
+define i1 @fabs_oeq_neginfinity_and_uge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @fabs_oeq_neginfinity_and_uge_smallest_normal(
+; CHECK-NEXT:    ret i1 false
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.oeq.neg.infinity = fcmp oeq half %fabs, 0xHFC00
+  %cmp.smallest.normal = fcmp oeq half %x, 0xH0400
+  %class = and i1 %fabs.oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> false
+define i1 @fabs_oeq_neginfinity_or_uge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @fabs_oeq_neginfinity_or_uge_smallest_normal(
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp oeq half [[X:%.*]], 0xH0400
+; CHECK-NEXT:    ret i1 [[CMP_SMALLEST_NORMAL]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.oeq.neg.infinity = fcmp oeq half %fabs, 0xHFC00
+  %cmp.smallest.normal = fcmp oeq half %x, 0xH0400
+  %class = or i1 %fabs.oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+;- > ord
+define i1 @fabs_oeq_neginfinity_and_ord(half %x) #0 {
+; CHECK-LABEL: @fabs_oeq_neginfinity_and_ord(
+; CHECK-NEXT:    ret i1 false
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.oeq.neg.infinity = fcmp oeq half %fabs, 0xHFC00
+  %ord = fcmp ord half %x, 0.0
+  %class = and i1 %fabs.oeq.neg.infinity, %ord
+  ret i1 %class
+}
+
+; -> false
+define i1 @fabs_ueq_neginfinity_and_olt_smallest_normal(half %x) #0 { ; WRONG
+; CHECK-LABEL: @fabs_ueq_neginfinity_and_olt_smallest_normal(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[FABS_UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[FABS]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[FABS_UEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.ueq.neg.infinity = fcmp ueq half %fabs, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = and i1 %fabs.ueq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> pinf|pnormal
+define i1 @fabs_one_neginfinity_and_uge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @fabs_one_neginfinity_and_uge_smallest_normal(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[FABS_ONE_NEG_INFINITY:%.*]] = fcmp one half [[FABS]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = and i1 [[FABS_ONE_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.one.neg.infinity = fcmp one half %fabs, 0xHFC00
+  %cmp.smallest.normal = fcmp uge half %x, 0xH0400
+  %class = and i1 %fabs.one.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ord
+define i1 @fabs_one_neginfinity_or_olt_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @fabs_one_neginfinity_or_olt_smallest_normal(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[FABS_ONE_NEG_INFINITY:%.*]] = fcmp one half [[FABS]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[X]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[FABS_ONE_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.one.neg.infinity = fcmp one half %fabs, 0xHFC00
+  %cmp.smallest.normal = fcmp olt half %x, 0xH0400
+  %class = or i1 %fabs.one.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+; -> ~(zero|subnormal)
+define i1 @fabs_ueq_neginfinity_or_fabs_uge_smallest_normal(half %x) #0 {
+; CHECK-LABEL: @fabs_ueq_neginfinity_or_fabs_uge_smallest_normal(
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    [[FABS_OEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[FABS]], 0xHFC00
+; CHECK-NEXT:    [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[FABS]], 0xH0400
+; CHECK-NEXT:    [[CLASS:%.*]] = or i1 [[FABS_OEQ_NEG_INFINITY]], [[CMP_SMALLEST_NORMAL]]
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %fabs = call half @llvm.fabs.f16(half %x)
+  %fabs.oeq.neg.infinity = fcmp ueq half %fabs, 0xHFC00
+  %cmp.smallest.normal = fcmp uge half %fabs, 0xH0400
+  %class = or i1 %fabs.oeq.neg.infinity, %cmp.smallest.normal
+  ret i1 %class
+}
+
+declare half @llvm.fabs.f16(half) #0
+declare half @llvm.canonicalize.f16(half) #0
+declare <2 x half> @llvm.fabs.v2f16(<2 x half>) #0
+
+attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }


        


More information about the llvm-commits mailing list