[llvm] expandIS_FPCLASS: Support fcNegative and fcPositive (PR #184788)

YunQiang Su via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 5 20:51:28 PST 2026


https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/184788

>From b40a2c2068cb8dd5f1bb3ca40dae514660322688 Mon Sep 17 00:00:00 2001
From: YunQiang Su <syq at debian.org>
Date: Thu, 5 Mar 2026 21:03:15 +0800
Subject: [PATCH 1/2] expandIS_FPCLASS: Support fcNegative and fcPositive

This can be used by expandFMINIMUM_FMAXIMUM in future patches.
For 32bit system with FP64 support, we use FP_ROUND to trunc
FP64 to FP32 and then get the sign. Without trunc, if IS_FPCLASS
is used in an expandF* function, LegalOps will assert fails on
assign a i64 value to an i32 variable.
---
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  57 ++
 llvm/test/CodeGen/Mips/is_fpclass.ll          | 668 ++++++++++++++----
 llvm/test/CodeGen/X86/is_fpclass.ll           | 231 ++++++
 3 files changed, 815 insertions(+), 141 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 088e6726fea58..89d4ae01ba3ea 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9306,6 +9306,63 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
   // Tests that involve more than one class should be processed first.
   SDValue PartialRes;
 
+  // Handle sign bit tests first (fcPositive/fcNegative).
+  // These test only the sign bit, if not NaN.
+  // On 32-bit platforms with 64-bit floats, we need to be careful about
+  // integer comparisons. We use FP_ROUND to convert to a smaller float type
+  // that matches ResultVT's size, then compare with 0.
+  if (Test == fcPositive || Test == fcNegative) {
+    SDValue SignBitResult;
+    unsigned MaxLegalIntBits = 32;
+    if (isTypeLegal(MVT::i64))
+      MaxLegalIntBits = 64;
+
+    unsigned IntVTBits = IntVT.getScalarSizeInBits();
+    bool NeedFPCompare = IntVTBits > MaxLegalIntBits;
+
+    if (NeedFPCompare) {
+      // Truncate to the largest legal float type.
+      EVT TruncFloatEltVT = (MaxLegalIntBits == 64) ? MVT::f64 : MVT::f32;
+
+      EVT TruncFloatVT = TruncFloatEltVT;
+      if (ResultVT.isVector() && TruncFloatEltVT != MVT::Other) {
+        TruncFloatVT = EVT::getVectorVT(*DAG.getContext(), TruncFloatEltVT,
+                                        ResultVT.getVectorElementCount());
+      }
+      if (TruncFloatVT != MVT::Other &&
+          isOperationLegalOrCustom(ISD::FP_ROUND, TruncFloatVT)) {
+        // Round to smaller float type, then bitcast to integer for sign check.
+        // Use TargetConstant for the truncation flag.
+        EVT PointerVT =
+            DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
+        SDValue OpTrunc = DAG.getNode(ISD::FP_ROUND, DL, TruncFloatVT, Op,
+                                      DAG.getTargetConstant(0, DL, PointerVT));
+        EVT TruncIntVT = TruncFloatVT.changeTypeToInteger();
+        SDValue OpTruncInt = DAG.getBitcast(TruncIntVT, OpTrunc);
+        SignBitResult =
+            DAG.getSetCC(DL, ResultVT, OpTruncInt,
+                         DAG.getConstant(0, DL, TruncIntVT), ISD::SETLT);
+      } else {
+        // Fall back to original integer comparison.
+        SignBitResult = SignV;
+      }
+    } else {
+      SignBitResult = SignV;
+    }
+
+    if (!DAG.isKnownNeverNaN(Op)) {
+      SDValue NotNaN = DAG.getSetCC(DL, ResultVT, Op, Op, ISD::SETO);
+      SignBitResult =
+          DAG.getNode(ISD::AND, DL, ResultVT, NotNaN, SignBitResult);
+    }
+
+    if (Test == fcNegative)
+      return SignBitResult;
+    else
+      return DAG.getNode(ISD::XOR, DL, ResultVT, SignBitResult,
+                         ResultInversionMask);
+  }
+
   if (IsF80)
     ; // Detect finite numbers of f80 by checking individual classes because
       // they have different settings of the explicit integer bit.
diff --git a/llvm/test/CodeGen/Mips/is_fpclass.ll b/llvm/test/CodeGen/Mips/is_fpclass.ll
index 9454a064c5312..44b706e5dcbac 100644
--- a/llvm/test/CodeGen/Mips/is_fpclass.ll
+++ b/llvm/test/CodeGen/Mips/is_fpclass.ll
@@ -1,246 +1,632 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=mipsisa32r6-unknown-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s
+; RUN: llc -mtriple=mipsisa32r6-unknown-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s --check-prefix=R6
+; RUN: llc -mtriple=mipsel-unknown-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s --check-prefix=R2
 
 
 define i1 @isnan_float(float %x) nounwind {
-; CHECK-LABEL: isnan_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 3
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnan_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 3
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnan_float:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $2, $zero, 1
+; R2-NEXT:    c.un.s $f12, $f12
+; R2-NEXT:    jr $ra
+; R2-NEXT:    movf $2, $zero, $fcc0
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3)  ; nan
   ret i1 %1
 }
 
 define i1 @isnan_double(double %x) nounwind {
-; CHECK-LABEL: isnan_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 3
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnan_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 3
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnan_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $2, $zero, 1
+; R2-NEXT:    c.un.d $f12, $f12
+; R2-NEXT:    jr $ra
+; R2-NEXT:    movf $2, $zero, $fcc0
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3)  ; nan
   ret i1 %1
 }
 
 define i1 @isnan_float_strictfp(float %x) strictfp nounwind {
-; CHECK-LABEL: isnan_float_strictfp:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 3
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnan_float_strictfp:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 3
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnan_float_strictfp:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32640
+; R2-NEXT:    jr $ra
+; R2-NEXT:    slt $2, $2, $1
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) strictfp ; nan
   ret i1 %1
 }
 
 define i1 @isnan_double_strictfp(double %x) strictfp nounwind {
-; CHECK-LABEL: isnan_double_strictfp:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 3
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnan_double_strictfp:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 3
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnan_double_strictfp:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $3, 32752
+; R2-NEXT:    slt $2, $3, $1
+; R2-NEXT:    xor $1, $1, $3
+; R2-NEXT:    lw $3, 0($sp)
+; R2-NEXT:    sltu $3, $zero, $3
+; R2-NEXT:    movz $2, $3, $1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) strictfp ; nan
   ret i1 %1
 }
 
 define i1 @isinf_float(float %x) nounwind {
-; CHECK-LABEL: isinf_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 68
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isinf_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 68
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isinf_float:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32640
+; R2-NEXT:    xor $1, $1, $2
+; R2-NEXT:    jr $ra
+; R2-NEXT:    sltiu $2, $1, 1
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 516)  ; 0x204 = "inf"
   ret i1 %1
 }
 
 define i1 @isfinite_float(float %x) nounwind {
-; CHECK-LABEL: isfinite_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 952
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isfinite_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 952
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isfinite_float:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32640
+; R2-NEXT:    jr $ra
+; R2-NEXT:    slt $2, $1, $2
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 504)  ; 0x1f8 = "finite"
   ret i1 %1
 }
 
 define i1 @isnormal_float(float %x) nounwind {
-; CHECK-LABEL: isnormal_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 136
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnormal_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 136
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnormal_float:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 65408
+; R2-NEXT:    addu $1, $1, $2
+; R2-NEXT:    srl $1, $1, 24
+; R2-NEXT:    jr $ra
+; R2-NEXT:    sltiu $2, $1, 127
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 264)  ; 0x108 = "normal"
   ret i1 %1
 }
 
 define i1 @issubnormal_float(float %x) nounwind {
-; CHECK-LABEL: issubnormal_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 272
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: issubnormal_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 272
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: issubnormal_float:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    addiu $1, $1, -1
+; R2-NEXT:    lui $2, 127
+; R2-NEXT:    ori $2, $2, 65535
+; R2-NEXT:    jr $ra
+; R2-NEXT:    sltu $2, $1, $2
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 144)  ; 0x90 = "subnormal"
   ret i1 %1
 }
 
 define i1 @iszero_float(float %x) nounwind {
-; CHECK-LABEL: iszero_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 544
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: iszero_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 544
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: iszero_float:
+; R2:       # %bb.0:
+; R2-NEXT:    mtc1 $zero, $f0
+; R2-NEXT:    addiu $2, $zero, 1
+; R2-NEXT:    c.eq.s $f12, $f0
+; R2-NEXT:    jr $ra
+; R2-NEXT:    movf $2, $zero, $fcc0
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 96)  ; 0x60 = "zero"
   ret i1 %1
 }
 
 define i1 @issnan_float(float %x) nounwind {
-; CHECK-LABEL: issnan_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 1
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: issnan_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 1
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: issnan_float:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32704
+; R2-NEXT:    slt $2, $1, $2
+; R2-NEXT:    lui $3, 32640
+; R2-NEXT:    slt $1, $3, $1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    and $2, $1, $2
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 1)
   ret i1 %1
 }
 
 define i1 @issnan_double(double %x) nounwind {
-; CHECK-LABEL: issnan_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 1
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: issnan_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 1
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: issnan_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32752
+; R2-NEXT:    slt $3, $2, $1
+; R2-NEXT:    xor $2, $1, $2
+; R2-NEXT:    lw $4, 0($sp)
+; R2-NEXT:    sltu $4, $zero, $4
+; R2-NEXT:    movz $3, $4, $2
+; R2-NEXT:    lui $2, 32760
+; R2-NEXT:    slt $1, $1, $2
+; R2-NEXT:    and $2, $3, $1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 1)
   ret i1 %1
 }
 
 define i1 @isqnan_float(float %x) nounwind {
-; CHECK-LABEL: isqnan_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 2
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isqnan_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 2
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isqnan_float:
+; R2:       # %bb.0:
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32703
+; R2-NEXT:    ori $2, $2, 65535
+; R2-NEXT:    jr $ra
+; R2-NEXT:    slt $2, $2, $1
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 2)
   ret i1 %1
 }
 
 define i1 @isqnan_double(double %x) nounwind {
-; CHECK-LABEL: isqnan_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 2
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isqnan_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 2
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isqnan_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 32759
+; R2-NEXT:    ori $2, $2, 65535
+; R2-NEXT:    slt $2, $2, $1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 2)
   ret i1 %1
 }
 
 define i1 @isposzero_double(double %x) nounwind {
-; CHECK-LABEL: isposzero_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 512
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isposzero_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 512
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isposzero_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lw $1, 4($sp)
+; R2-NEXT:    lw $2, 0($sp)
+; R2-NEXT:    or $1, $2, $1
+; R2-NEXT:    sltiu $2, $1, 1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 64)
   ret i1 %1
 }
 
 define i1 @isnegzero_double(double %x) nounwind {
-; CHECK-LABEL: isnegzero_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 32
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnegzero_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 32
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnegzero_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32768
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    xor $1, $2, $1
+; R2-NEXT:    lw $2, 0($sp)
+; R2-NEXT:    or $1, $2, $1
+; R2-NEXT:    sltiu $2, $1, 1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 32)
   ret i1 %1
 }
 
 define i1 @isposnormal_double(double %x) nounwind {
-; CHECK-LABEL: isposnormal_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 128
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isposnormal_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 128
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isposnormal_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    addiu $1, $zero, -1
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    slt $1, $1, $2
+; R2-NEXT:    lui $3, 32767
+; R2-NEXT:    ori $3, $3, 65535
+; R2-NEXT:    and $2, $2, $3
+; R2-NEXT:    lui $3, 65520
+; R2-NEXT:    addu $2, $2, $3
+; R2-NEXT:    srl $2, $2, 21
+; R2-NEXT:    sltiu $2, $2, 1023
+; R2-NEXT:    and $2, $2, $1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 256)
   ret i1 %1
 }
 
 define i1 @isnegnormal_double(double %x) nounwind {
-; CHECK-LABEL: isnegnormal_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 8
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnegnormal_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 8
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnegnormal_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $3, 65520
+; R2-NEXT:    addu $1, $1, $3
+; R2-NEXT:    srl $1, $1, 21
+; R2-NEXT:    sltiu $1, $1, 1023
+; R2-NEXT:    slti $2, $2, 0
+; R2-NEXT:    and $2, $1, $2
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 8)
   ret i1 %1
 }
 
 define i1 @isnormal_double(double %x) nounwind {
-; CHECK-LABEL: isnormal_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 136
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isnormal_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 136
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isnormal_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $2, 65520
+; R2-NEXT:    addu $1, $1, $2
+; R2-NEXT:    srl $1, $1, 21
+; R2-NEXT:    sltiu $2, $1, 1023
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 264)
   ret i1 %1
 }
 
 define i1 @isclass_00d_double(double %x) nounwind {
-; CHECK-LABEL: isclass_00d_double:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.d $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 13
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isclass_00d_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 13
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_00d_double:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $sp, $sp, -8
+; R2-NEXT:    sdc1 $f12, 0($sp)
+; R2-NEXT:    lui $1, 32767
+; R2-NEXT:    ori $1, $1, 65535
+; R2-NEXT:    lw $2, 4($sp)
+; R2-NEXT:    and $1, $2, $1
+; R2-NEXT:    lui $3, 32752
+; R2-NEXT:    slt $4, $3, $1
+; R2-NEXT:    xor $3, $1, $3
+; R2-NEXT:    lw $5, 0($sp)
+; R2-NEXT:    sltu $6, $zero, $5
+; R2-NEXT:    movz $4, $6, $3
+; R2-NEXT:    lui $3, 32760
+; R2-NEXT:    slt $3, $1, $3
+; R2-NEXT:    and $3, $4, $3
+; R2-NEXT:    lui $4, 65520
+; R2-NEXT:    xor $6, $2, $4
+; R2-NEXT:    or $5, $5, $6
+; R2-NEXT:    sltiu $5, $5, 1
+; R2-NEXT:    or $3, $5, $3
+; R2-NEXT:    addu $1, $1, $4
+; R2-NEXT:    srl $1, $1, 21
+; R2-NEXT:    sltiu $1, $1, 1023
+; R2-NEXT:    slti $2, $2, 0
+; R2-NEXT:    and $1, $1, $2
+; R2-NEXT:    or $2, $3, $1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    addiu $sp, $sp, 8
   %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 13)
   ret i1 %1
 }
 
 define i1 @isclass_1c0_float(float %x) nounwind {
-; CHECK-LABEL: isclass_1c0_float:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    class.s $f0, $f12
-; CHECK-NEXT:    mfc1 $1, $f0
-; CHECK-NEXT:    andi $1, $1, 896
-; CHECK-NEXT:    jr $ra
-; CHECK-NEXT:    sltu $2, $zero, $1
+; R6-LABEL: isclass_1c0_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 896
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_1c0_float:
+; R2:       # %bb.0:
+; R2-NEXT:    mfc1 $1, $f12
+; R2-NEXT:    srl $1, $1, 23
+; R2-NEXT:    jr $ra
+; R2-NEXT:    sltiu $2, $1, 255
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 448)
   ret i1 %1
 }
 
+define i1 @isclass_positive_float(float %x) nounwind {
+; R6-LABEL: isclass_positive_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 960
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_positive_float:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $1, $zero, 1
+; R2-NEXT:    c.un.s $f12, $f12
+; R2-NEXT:    movf $1, $zero, $fcc0
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    addiu $3, $zero, -1
+; R2-NEXT:    slt $2, $3, $2
+; R2-NEXT:    jr $ra
+; R2-NEXT:    or $2, $1, $2
+  %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 960)
+  ret i1 %1
+}
+
+define i1 @isclass_positive_nnan_float(float nofpclass(nan) %x) nounwind {
+; R6-LABEL: isclass_positive_nnan_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 960
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_positive_nnan_float:
+; R2:       # %bb.0:
+; R2-NEXT:    mfc1 $1, $f12
+; R2-NEXT:    addiu $2, $zero, -1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    slt $2, $2, $1
+  %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 960)
+  ret i1 %1
+}
+
+define i1 @isclass_positive_nnan_double(double nofpclass(nan) %x) nounwind {
+; R6-LABEL: isclass_positive_nnan_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 960
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_positive_nnan_double:
+; R2:       # %bb.0:
+; R2-NEXT:    cvt.s.d $f0, $f12
+; R2-NEXT:    mfc1 $1, $f0
+; R2-NEXT:    addiu $2, $zero, -1
+; R2-NEXT:    jr $ra
+; R2-NEXT:    slt $2, $2, $1
+  %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 960)
+  ret i1 %1
+}
+
+define i1 @isclass_negative_float(float %x) nounwind {
+; R6-LABEL: isclass_negative_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 60
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_negative_float:
+; R2:       # %bb.0:
+; R2-NEXT:    addiu $1, $zero, 1
+; R2-NEXT:    c.un.s $f12, $f12
+; R2-NEXT:    movt $1, $zero, $fcc0
+; R2-NEXT:    mfc1 $2, $f12
+; R2-NEXT:    slti $2, $2, 0
+; R2-NEXT:    jr $ra
+; R2-NEXT:    and $2, $1, $2
+  %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 60)
+  ret i1 %1
+}
+
+define i1 @isclass_negative_nnan_float(float nofpclass(nan) %x) nounwind {
+; R6-LABEL: isclass_negative_nnan_float:
+; R6:       # %bb.0:
+; R6-NEXT:    class.s $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 60
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_negative_nnan_float:
+; R2:       # %bb.0:
+; R2-NEXT:    mfc1 $1, $f12
+; R2-NEXT:    jr $ra
+; R2-NEXT:    srl $2, $1, 31
+  %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 60)
+  ret i1 %1
+}
+
+define i1 @isclass_negative_nnan_double(double nofpclass(nan) %x) nounwind {
+; R6-LABEL: isclass_negative_nnan_double:
+; R6:       # %bb.0:
+; R6-NEXT:    class.d $f0, $f12
+; R6-NEXT:    mfc1 $1, $f0
+; R6-NEXT:    andi $1, $1, 60
+; R6-NEXT:    jr $ra
+; R6-NEXT:    sltu $2, $zero, $1
+;
+; R2-LABEL: isclass_negative_nnan_double:
+; R2:       # %bb.0:
+; R2-NEXT:    cvt.s.d $f0, $f12
+; R2-NEXT:    mfc1 $1, $f0
+; R2-NEXT:    jr $ra
+; R2-NEXT:    srl $2, $1, 31
+  %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 60)
+  ret i1 %1
+}
+
 declare i1 @llvm.is.fpclass.f32(float, i32)
 declare i1 @llvm.is.fpclass.f64(double, i32)
diff --git a/llvm/test/CodeGen/X86/is_fpclass.ll b/llvm/test/CodeGen/X86/is_fpclass.ll
index 70062b245f36d..c2d6b7ac9b2d7 100644
--- a/llvm/test/CodeGen/X86/is_fpclass.ll
+++ b/llvm/test/CodeGen/X86/is_fpclass.ll
@@ -2901,6 +2901,237 @@ define i1 @not_issubnormal_or_zero_or_qnan_f(float %x) {
   ret i1 %class
 }
 
+define <4 x i1> @isclass_positive_nnan(<4 x float> nofpclass(nan) %x) nounwind {
+; X86-LABEL: isclass_positive_nnan:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps (%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps {{[0-9]+}}(%esp)
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    setns %cl
+; X86-NEXT:    shlb $2, %cl
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    setns %dl
+; X86-NEXT:    shlb $3, %dl
+; X86-NEXT:    orb %cl, %dl
+; X86-NEXT:    cmpl $0, (%esp)
+; X86-NEXT:    setns %cl
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    setns %ch
+; X86-NEXT:    addb %ch, %ch
+; X86-NEXT:    orb %cl, %ch
+; X86-NEXT:    orb %dl, %ch
+; X86-NEXT:    movb %ch, (%eax)
+; X86-NEXT:    addl $16, %esp
+; X86-NEXT:    retl $4
+;
+; X64-LABEL: isclass_positive_nnan:
+; X64:       # %bb.0:
+; X64-NEXT:    pxor %xmm1, %xmm1
+; X64-NEXT:    pcmpgtd %xmm0, %xmm1
+; X64-NEXT:    pcmpeqd %xmm0, %xmm0
+; X64-NEXT:    pxor %xmm1, %xmm0
+; X64-NEXT:    retq
+  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 960)
+  ret <4 x i1> %1
+}
+
+define <4 x i1> @isclass_positive(<4 x float> %x) nounwind {
+; X86-LABEL: isclass_positive:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts (%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts {{[0-9]+}}(%esp)
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %dl
+; X86-NEXT:    fxch %st(3)
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %dh
+; X86-NEXT:    andb %dl, %dh
+; X86-NEXT:    xorb $1, %dh
+; X86-NEXT:    shlb $2, %dh
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %bl
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %dl
+; X86-NEXT:    andb %bl, %dl
+; X86-NEXT:    notb %dl
+; X86-NEXT:    shlb $3, %dl
+; X86-NEXT:    orb %dh, %dl
+; X86-NEXT:    cmpl $0, (%esp)
+; X86-NEXT:    sets %bl
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %dh
+; X86-NEXT:    andb %bl, %dh
+; X86-NEXT:    xorb $1, %dh
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %bl
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %al
+; X86-NEXT:    andb %bl, %al
+; X86-NEXT:    xorb $1, %al
+; X86-NEXT:    addb %al, %al
+; X86-NEXT:    orb %dh, %al
+; X86-NEXT:    orb %dl, %al
+; X86-NEXT:    andb $15, %al
+; X86-NEXT:    movb %al, (%ecx)
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    addl $16, %esp
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    retl $4
+;
+; X64-LABEL: isclass_positive:
+; X64:       # %bb.0:
+; X64-NEXT:    pxor %xmm1, %xmm1
+; X64-NEXT:    pcmpgtd %xmm0, %xmm1
+; X64-NEXT:    cmpordps %xmm0, %xmm0
+; X64-NEXT:    andps %xmm1, %xmm0
+; X64-NEXT:    xorps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    retq
+  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 960)
+  ret <4 x i1> %1
+}
+
+define <4 x i1> @isclass_negative_nnan(<4 x float> nofpclass(nan) %x) nounwind {
+; X86-LABEL: isclass_negative_nnan:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps (%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps {{[0-9]+}}(%esp)
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %cl
+; X86-NEXT:    shlb $2, %cl
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %dl
+; X86-NEXT:    shlb $3, %dl
+; X86-NEXT:    orb %cl, %dl
+; X86-NEXT:    cmpl $0, (%esp)
+; X86-NEXT:    sets %cl
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %ch
+; X86-NEXT:    addb %ch, %ch
+; X86-NEXT:    orb %cl, %ch
+; X86-NEXT:    orb %dl, %ch
+; X86-NEXT:    movb %ch, (%eax)
+; X86-NEXT:    addl $16, %esp
+; X86-NEXT:    retl $4
+;
+; X64-LABEL: isclass_negative_nnan:
+; X64:       # %bb.0:
+; X64-NEXT:    pxor %xmm1, %xmm1
+; X64-NEXT:    pcmpgtd %xmm0, %xmm1
+; X64-NEXT:    movdqa %xmm1, %xmm0
+; X64-NEXT:    retq
+  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 60)
+  ret <4 x i1> %1
+}
+
+define <4 x i1> @isclass_negative(<4 x float> %x) nounwind {
+; X86-LABEL: isclass_negative:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts (%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts {{[0-9]+}}(%esp)
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %dl
+; X86-NEXT:    fxch %st(3)
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %dh
+; X86-NEXT:    andb %dl, %dh
+; X86-NEXT:    shlb $2, %dh
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %bl
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %dl
+; X86-NEXT:    andb %bl, %dl
+; X86-NEXT:    shlb $3, %dl
+; X86-NEXT:    orb %dh, %dl
+; X86-NEXT:    cmpl $0, (%esp)
+; X86-NEXT:    sets %bl
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %dh
+; X86-NEXT:    andb %bl, %dh
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    sets %bl
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %al
+; X86-NEXT:    andb %bl, %al
+; X86-NEXT:    addb %al, %al
+; X86-NEXT:    orb %dh, %al
+; X86-NEXT:    orb %dl, %al
+; X86-NEXT:    movb %al, (%ecx)
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    addl $16, %esp
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    retl $4
+;
+; X64-LABEL: isclass_negative:
+; X64:       # %bb.0:
+; X64-NEXT:    pxor %xmm1, %xmm1
+; X64-NEXT:    pcmpgtd %xmm0, %xmm1
+; X64-NEXT:    cmpordps %xmm0, %xmm0
+; X64-NEXT:    andps %xmm1, %xmm0
+; X64-NEXT:    retq
+  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 60)
+  ret <4 x i1> %1
+}
+
 declare i1 @llvm.is.fpclass.f32(float, i32)
 declare i1 @llvm.is.fpclass.f64(double, i32)
 declare <1 x i1> @llvm.is.fpclass.v1f32(<1 x float>, i32)

>From cdcbb4331d83582a82d2f1de78009a932c890ea8 Mon Sep 17 00:00:00 2001
From: YunQiang Su <syq at debian.org>
Date: Fri, 6 Mar 2026 12:46:22 +0800
Subject: [PATCH 2/2] some fixes

---
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  12 +-
 .../CodeGen/AMDGPU/llvm.is.fpclass.bf16.ll    |  50 ++--
 .../CodeGen/AMDGPU/llvm.is.fpclass.f16.ll     |  13 +-
 llvm/test/CodeGen/Mips/is_fpclass.ll          |  13 +-
 llvm/test/CodeGen/X86/is_fpclass.ll           | 213 +++++++++++-------
 5 files changed, 163 insertions(+), 138 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 89d4ae01ba3ea..71275d61e7fc1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9322,7 +9322,7 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
 
     if (NeedFPCompare) {
       // Truncate to the largest legal float type.
-      EVT TruncFloatEltVT = (MaxLegalIntBits == 64) ? MVT::f64 : MVT::f32;
+      EVT TruncFloatEltVT = EVT::getFloatingPointVT(MaxLegalIntBits);
 
       EVT TruncFloatVT = TruncFloatEltVT;
       if (ResultVT.isVector() && TruncFloatEltVT != MVT::Other) {
@@ -9333,8 +9333,7 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
           isOperationLegalOrCustom(ISD::FP_ROUND, TruncFloatVT)) {
         // Round to smaller float type, then bitcast to integer for sign check.
         // Use TargetConstant for the truncation flag.
-        EVT PointerVT =
-            DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
+        EVT PointerVT = getPointerTy(DAG.getDataLayout());
         SDValue OpTrunc = DAG.getNode(ISD::FP_ROUND, DL, TruncFloatVT, Op,
                                       DAG.getTargetConstant(0, DL, PointerVT));
         EVT TruncIntVT = TruncFloatVT.changeTypeToInteger();
@@ -9356,7 +9355,12 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
           DAG.getNode(ISD::AND, DL, ResultVT, NotNaN, SignBitResult);
     }
 
-    if (Test == fcNegative)
+    bool IsICmpImmLegal =
+        isLegalICmpImmediate(APInt::getAllOnes(IntVTBits).getZExtValue());
+    if (!NeedFPCompare && (!DAG.isKnownNeverNaN(Op) || IsICmpImmLegal) &&
+        Test == fcPositive) {
+      ; // (fcPosInf | fcFinite) has better performance.
+    } else if (Test == fcNegative)
       return SignBitResult;
     else
       return DAG.getNode(ISD::XOR, DL, ResultVT, SignBitResult,
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.bf16.ll b/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.bf16.ll
index d80fb6d8ea108..80ec6fa104b31 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.bf16.ll
@@ -2123,80 +2123,62 @@ define i1 @isnegative_bf16(bfloat %x) {
 ; GFX7CHECK-LABEL: isnegative_bf16:
 ; GFX7CHECK:       ; %bb.0:
 ; GFX7CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7CHECK-NEXT:    v_and_b32_e32 v1, 0xffff, v0
-; GFX7CHECK-NEXT:    v_lshlrev_b32_e32 v2, 16, v0
-; GFX7CHECK-NEXT:    v_and_b32_e32 v0, 0x7fff, v0
-; GFX7CHECK-NEXT:    s_movk_i32 s4, 0x7f80
-; GFX7CHECK-NEXT:    v_cmp_gt_i32_e32 vcc, 0, v2
-; GFX7CHECK-NEXT:    v_cmp_gt_i32_e64 s[4:5], s4, v0
-; GFX7CHECK-NEXT:    s_mov_b32 s6, 0xff80
+; GFX7CHECK-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
+; GFX7CHECK-NEXT:    v_cmp_gt_i32_e32 vcc, 0, v0
+; GFX7CHECK-NEXT:    v_cmp_o_f32_e64 s[4:5], v0, v0
 ; GFX7CHECK-NEXT:    s_and_b64 s[4:5], s[4:5], vcc
-; GFX7CHECK-NEXT:    v_cmp_eq_u32_e32 vcc, s6, v1
-; GFX7CHECK-NEXT:    s_or_b64 s[4:5], s[4:5], vcc
 ; GFX7CHECK-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s[4:5]
 ; GFX7CHECK-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX8CHECK-LABEL: isnegative_bf16:
 ; GFX8CHECK:       ; %bb.0:
 ; GFX8CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8CHECK-NEXT:    v_and_b32_e32 v1, 0x7fff, v0
-; GFX8CHECK-NEXT:    s_movk_i32 s4, 0x7f80
 ; GFX8CHECK-NEXT:    v_cmp_gt_i16_e32 vcc, 0, v0
-; GFX8CHECK-NEXT:    v_cmp_gt_i16_e64 s[4:5], s4, v1
-; GFX8CHECK-NEXT:    s_movk_i32 s6, 0xff80
+; GFX8CHECK-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
+; GFX8CHECK-NEXT:    v_cmp_o_f32_e64 s[4:5], v0, v0
 ; GFX8CHECK-NEXT:    s_and_b64 s[4:5], s[4:5], vcc
-; GFX8CHECK-NEXT:    v_cmp_eq_u16_e32 vcc, s6, v0
-; GFX8CHECK-NEXT:    s_or_b64 s[4:5], s[4:5], vcc
 ; GFX8CHECK-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s[4:5]
 ; GFX8CHECK-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9CHECK-LABEL: isnegative_bf16:
 ; GFX9CHECK:       ; %bb.0:
 ; GFX9CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9CHECK-NEXT:    v_and_b32_e32 v1, 0x7fff, v0
-; GFX9CHECK-NEXT:    s_movk_i32 s4, 0x7f80
 ; GFX9CHECK-NEXT:    v_cmp_gt_i16_e32 vcc, 0, v0
-; GFX9CHECK-NEXT:    v_cmp_gt_i16_e64 s[4:5], s4, v1
-; GFX9CHECK-NEXT:    s_movk_i32 s6, 0xff80
+; GFX9CHECK-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
+; GFX9CHECK-NEXT:    v_cmp_o_f32_e64 s[4:5], v0, v0
 ; GFX9CHECK-NEXT:    s_and_b64 s[4:5], s[4:5], vcc
-; GFX9CHECK-NEXT:    v_cmp_eq_u16_e32 vcc, s6, v0
-; GFX9CHECK-NEXT:    s_or_b64 s[4:5], s[4:5], vcc
 ; GFX9CHECK-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s[4:5]
 ; GFX9CHECK-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10CHECK-LABEL: isnegative_bf16:
 ; GFX10CHECK:       ; %bb.0:
 ; GFX10CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10CHECK-NEXT:    v_and_b32_e32 v1, 0x7fff, v0
+; GFX10CHECK-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
 ; GFX10CHECK-NEXT:    v_cmp_gt_i16_e32 vcc_lo, 0, v0
-; GFX10CHECK-NEXT:    v_cmp_eq_u16_e64 s5, 0xff80, v0
-; GFX10CHECK-NEXT:    v_cmp_gt_i16_e64 s4, 0x7f80, v1
+; GFX10CHECK-NEXT:    v_cmp_o_f32_e64 s4, v1, v1
 ; GFX10CHECK-NEXT:    s_and_b32 s4, s4, vcc_lo
-; GFX10CHECK-NEXT:    s_or_b32 s4, s4, s5
 ; GFX10CHECK-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s4
 ; GFX10CHECK-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11SELDAG-TRUE16-LABEL: isnegative_bf16:
 ; GFX11SELDAG-TRUE16:       ; %bb.0:
 ; GFX11SELDAG-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11SELDAG-TRUE16-NEXT:    v_and_b16 v0.h, 0x7fff, v0.l
-; GFX11SELDAG-TRUE16-NEXT:    v_cmp_gt_i16_e32 vcc_lo, 0, v0.l
-; GFX11SELDAG-TRUE16-NEXT:    v_cmp_eq_u16_e64 s1, 0xff80, v0.l
-; GFX11SELDAG-TRUE16-NEXT:    v_cmp_gt_i16_e64 s0, 0x7f80, v0.h
+; GFX11SELDAG-TRUE16-NEXT:    v_mov_b16_e32 v2.l, 0
+; GFX11SELDAG-TRUE16-NEXT:    v_mov_b16_e32 v1.l, v0.l
+; GFX11SELDAG-TRUE16-NEXT:    v_mov_b16_e32 v2.h, v0.l
+; GFX11SELDAG-TRUE16-NEXT:    v_cmp_gt_i16_e32 vcc_lo, 0, v1.l
+; GFX11SELDAG-TRUE16-NEXT:    v_cmp_o_f32_e64 s0, v2, v2
 ; GFX11SELDAG-TRUE16-NEXT:    s_and_b32 s0, s0, vcc_lo
-; GFX11SELDAG-TRUE16-NEXT:    s_or_b32 s0, s0, s1
 ; GFX11SELDAG-TRUE16-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s0
 ; GFX11SELDAG-TRUE16-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11SELDAG-FAKE16-LABEL: isnegative_bf16:
 ; GFX11SELDAG-FAKE16:       ; %bb.0:
 ; GFX11SELDAG-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11SELDAG-FAKE16-NEXT:    v_and_b32_e32 v1, 0x7fff, v0
+; GFX11SELDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
 ; GFX11SELDAG-FAKE16-NEXT:    v_cmp_gt_i16_e32 vcc_lo, 0, v0
-; GFX11SELDAG-FAKE16-NEXT:    v_cmp_eq_u16_e64 s1, 0xff80, v0
-; GFX11SELDAG-FAKE16-NEXT:    v_cmp_gt_i16_e64 s0, 0x7f80, v1
+; GFX11SELDAG-FAKE16-NEXT:    v_cmp_o_f32_e64 s0, v1, v1
 ; GFX11SELDAG-FAKE16-NEXT:    s_and_b32 s0, s0, vcc_lo
-; GFX11SELDAG-FAKE16-NEXT:    s_or_b32 s0, s0, s1
 ; GFX11SELDAG-FAKE16-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s0
 ; GFX11SELDAG-FAKE16-NEXT:    s_setpc_b64 s[30:31]
   %class = tail call i1 @llvm.is.fpclass.bf16(bfloat %x, i32 60)  ; fcNegative
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.f16.ll b/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.f16.ll
index 76958e63d36c9..1b3527a0b5d49 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.f16.ll
@@ -3053,16 +3053,11 @@ define i1 @isnegative_f16(half %x) {
 ; GFX7SELDAG-LABEL: isnegative_f16:
 ; GFX7SELDAG:       ; %bb.0:
 ; GFX7SELDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7SELDAG-NEXT:    v_and_b32_e32 v1, 0xffff, v0
-; GFX7SELDAG-NEXT:    v_lshlrev_b32_e32 v2, 16, v0
-; GFX7SELDAG-NEXT:    v_and_b32_e32 v0, 0x7fff, v0
-; GFX7SELDAG-NEXT:    s_movk_i32 s4, 0x7c00
-; GFX7SELDAG-NEXT:    v_cmp_gt_i32_e32 vcc, 0, v2
-; GFX7SELDAG-NEXT:    v_cmp_gt_i32_e64 s[4:5], s4, v0
-; GFX7SELDAG-NEXT:    s_mov_b32 s6, 0xfc00
+; GFX7SELDAG-NEXT:    v_cvt_f32_f16_e32 v1, v0
+; GFX7SELDAG-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
+; GFX7SELDAG-NEXT:    v_cmp_gt_i32_e32 vcc, 0, v0
+; GFX7SELDAG-NEXT:    v_cmp_o_f32_e64 s[4:5], v1, v1
 ; GFX7SELDAG-NEXT:    s_and_b64 s[4:5], s[4:5], vcc
-; GFX7SELDAG-NEXT:    v_cmp_eq_u32_e32 vcc, s6, v1
-; GFX7SELDAG-NEXT:    s_or_b64 s[4:5], s[4:5], vcc
 ; GFX7SELDAG-NEXT:    v_cndmask_b32_e64 v0, 0, 1, s[4:5]
 ; GFX7SELDAG-NEXT:    s_setpc_b64 s[30:31]
 ;
diff --git a/llvm/test/CodeGen/Mips/is_fpclass.ll b/llvm/test/CodeGen/Mips/is_fpclass.ll
index 44b706e5dcbac..66c3e3bee09a2 100644
--- a/llvm/test/CodeGen/Mips/is_fpclass.ll
+++ b/llvm/test/CodeGen/Mips/is_fpclass.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=mipsisa32r6-unknown-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s --check-prefix=R6
-; RUN: llc -mtriple=mipsel-unknown-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s --check-prefix=R2
+; RUN: llc -mtriple=mipsisa32r6-unknown-linux-gnu -o - %s | FileCheck %s --check-prefix=R6
+; RUN: llc -mtriple=mipsel-unknown-linux-gnu -o - %s | FileCheck %s --check-prefix=R2
 
 
 define i1 @isnan_float(float %x) nounwind {
@@ -518,14 +518,11 @@ define i1 @isclass_positive_float(float %x) nounwind {
 ;
 ; R2-LABEL: isclass_positive_float:
 ; R2:       # %bb.0:
-; R2-NEXT:    addiu $1, $zero, 1
-; R2-NEXT:    c.un.s $f12, $f12
-; R2-NEXT:    movf $1, $zero, $fcc0
+; R2-NEXT:    lui $1, 32640
+; R2-NEXT:    ori $1, $1, 1
 ; R2-NEXT:    mfc1 $2, $f12
-; R2-NEXT:    addiu $3, $zero, -1
-; R2-NEXT:    slt $2, $3, $2
 ; R2-NEXT:    jr $ra
-; R2-NEXT:    or $2, $1, $2
+; R2-NEXT:    sltu $2, $2, $1
   %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 960)
   ret i1 %1
 }
diff --git a/llvm/test/CodeGen/X86/is_fpclass.ll b/llvm/test/CodeGen/X86/is_fpclass.ll
index c2d6b7ac9b2d7..c933bba790954 100644
--- a/llvm/test/CodeGen/X86/is_fpclass.ll
+++ b/llvm/test/CodeGen/X86/is_fpclass.ll
@@ -2901,9 +2901,101 @@ define i1 @not_issubnormal_or_zero_or_qnan_f(float %x) {
   ret i1 %class
 }
 
-define <4 x i1> @isclass_positive_nnan(<4 x float> nofpclass(nan) %x) nounwind {
+define i1 @isclass_positive_nnan(float nofpclass(nan) %x) nounwind {
 ; X86-LABEL: isclass_positive_nnan:
 ; X86:       # %bb.0:
+; X86-NEXT:    pushl %eax
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps (%esp)
+; X86-NEXT:    cmpl $0, (%esp)
+; X86-NEXT:    setns %al
+; X86-NEXT:    popl %ecx
+; X86-NEXT:    retl
+;
+; X64-LABEL: isclass_positive_nnan:
+; X64:       # %bb.0:
+; X64-NEXT:    movmskps %xmm0, %eax
+; X64-NEXT:    testb $1, %al
+; X64-NEXT:    sete %al
+; X64-NEXT:    retq
+  %ispos = call i1 @llvm.is.fpclass.f32(float %x, i32 960)
+  ret i1 %ispos
+}
+
+define i1 @isclass_positive(float %x) nounwind {
+; X86-LABEL: isclass_positive:
+; X86:       # %bb.0:
+; X86-NEXT:    cmpl $2139095041, {{[0-9]+}}(%esp) # imm = 0x7F800001
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+;
+; X64-LABEL: isclass_positive:
+; X64:       # %bb.0:
+; X64-NEXT:    movd %xmm0, %eax
+; X64-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+  %ispos = call i1 @llvm.is.fpclass.f32(float %x, i32 960)
+  ret i1 %ispos
+}
+
+define i1 @isclass_negative_nnan(float nofpclass(nan) %x) nounwind {
+; X86-LABEL: isclass_negative_nnan:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %eax
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fstps (%esp)
+; X86-NEXT:    movl (%esp), %eax
+; X86-NEXT:    shrl $31, %eax
+; X86-NEXT:    # kill: def $al killed $al killed $eax
+; X86-NEXT:    popl %ecx
+; X86-NEXT:    retl
+;
+; X64-LABEL: isclass_negative_nnan:
+; X64:       # %bb.0:
+; X64-NEXT:    movmskps %xmm0, %eax
+; X64-NEXT:    andl $1, %eax
+; X64-NEXT:    # kill: def $al killed $al killed $eax
+; X64-NEXT:    retq
+  %isneg = call i1 @llvm.is.fpclass.f32(float %x, i32 60)
+  ret i1 %isneg
+}
+
+define i1 @isclass_negative(float %x) nounwind {
+; X86-LABEL: isclass_negative:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %eax
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fsts (%esp)
+; X86-NEXT:    cmpl $0, (%esp)
+; X86-NEXT:    sets %cl
+; X86-NEXT:    fucomp %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    setnp %al
+; X86-NEXT:    andb %cl, %al
+; X86-NEXT:    popl %ecx
+; X86-NEXT:    retl
+;
+; X64-LABEL: isclass_negative:
+; X64:       # %bb.0:
+; X64-NEXT:    movmskps %xmm0, %eax
+; X64-NEXT:    ucomiss %xmm0, %xmm0
+; X64-NEXT:    setnp %cl
+; X64-NEXT:    testb $1, %al
+; X64-NEXT:    setne %al
+; X64-NEXT:    andb %cl, %al
+; X64-NEXT:    retq
+  %isneg = call i1 @llvm.is.fpclass.f32(float %x, i32 60)
+  ret i1 %isneg
+}
+
+
+
+define <4 x i1> @isclass_positive_nnan_v4f32(<4 x float> nofpclass(nan) %x) nounwind {
+; X86-LABEL: isclass_positive_nnan_v4f32:
+; X86:       # %bb.0:
 ; X86-NEXT:    subl $16, %esp
 ; X86-NEXT:    flds {{[0-9]+}}(%esp)
 ; X86-NEXT:    fstps {{[0-9]+}}(%esp)
@@ -2932,96 +3024,51 @@ define <4 x i1> @isclass_positive_nnan(<4 x float> nofpclass(nan) %x) nounwind {
 ; X86-NEXT:    addl $16, %esp
 ; X86-NEXT:    retl $4
 ;
-; X64-LABEL: isclass_positive_nnan:
+; X64-LABEL: isclass_positive_nnan_v4f32:
 ; X64:       # %bb.0:
 ; X64-NEXT:    pxor %xmm1, %xmm1
 ; X64-NEXT:    pcmpgtd %xmm0, %xmm1
 ; X64-NEXT:    pcmpeqd %xmm0, %xmm0
 ; X64-NEXT:    pxor %xmm1, %xmm0
 ; X64-NEXT:    retq
-  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 960)
-  ret <4 x i1> %1
+  %ispos = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 960)
+  ret <4 x i1> %ispos
 }
 
-define <4 x i1> @isclass_positive(<4 x float> %x) nounwind {
-; X86-LABEL: isclass_positive:
+define <4 x i1> @isclass_positive_v4f32(<4 x float> %x) nounwind {
+; X86-LABEL: isclass_positive_v4f32:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %ebx
-; X86-NEXT:    subl $16, %esp
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fsts {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fsts {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fsts (%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fsts {{[0-9]+}}(%esp)
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
-; X86-NEXT:    sets %dl
-; X86-NEXT:    fxch %st(3)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %dh
-; X86-NEXT:    andb %dl, %dh
-; X86-NEXT:    xorb $1, %dh
-; X86-NEXT:    shlb $2, %dh
-; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
-; X86-NEXT:    sets %bl
-; X86-NEXT:    fxch %st(1)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %dl
-; X86-NEXT:    andb %bl, %dl
-; X86-NEXT:    notb %dl
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl $2139095041, {{[0-9]+}}(%esp) # imm = 0x7F800001
+; X86-NEXT:    setb %cl
+; X86-NEXT:    shlb $2, %cl
+; X86-NEXT:    cmpl $2139095041, {{[0-9]+}}(%esp) # imm = 0x7F800001
+; X86-NEXT:    setb %dl
 ; X86-NEXT:    shlb $3, %dl
-; X86-NEXT:    orb %dh, %dl
-; X86-NEXT:    cmpl $0, (%esp)
-; X86-NEXT:    sets %bl
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %dh
-; X86-NEXT:    andb %bl, %dh
-; X86-NEXT:    xorb $1, %dh
-; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
-; X86-NEXT:    sets %bl
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %al
-; X86-NEXT:    andb %bl, %al
-; X86-NEXT:    xorb $1, %al
-; X86-NEXT:    addb %al, %al
-; X86-NEXT:    orb %dh, %al
-; X86-NEXT:    orb %dl, %al
-; X86-NEXT:    andb $15, %al
-; X86-NEXT:    movb %al, (%ecx)
-; X86-NEXT:    movl %ecx, %eax
-; X86-NEXT:    addl $16, %esp
-; X86-NEXT:    popl %ebx
+; X86-NEXT:    orb %cl, %dl
+; X86-NEXT:    cmpl $2139095041, {{[0-9]+}}(%esp) # imm = 0x7F800001
+; X86-NEXT:    setb %cl
+; X86-NEXT:    cmpl $2139095041, {{[0-9]+}}(%esp) # imm = 0x7F800001
+; X86-NEXT:    setb %ch
+; X86-NEXT:    addb %ch, %ch
+; X86-NEXT:    orb %cl, %ch
+; X86-NEXT:    orb %dl, %ch
+; X86-NEXT:    movb %ch, (%eax)
 ; X86-NEXT:    retl $4
 ;
-; X64-LABEL: isclass_positive:
+; X64-LABEL: isclass_positive_v4f32:
 ; X64:       # %bb.0:
-; X64-NEXT:    pxor %xmm1, %xmm1
-; X64-NEXT:    pcmpgtd %xmm0, %xmm1
-; X64-NEXT:    cmpordps %xmm0, %xmm0
-; X64-NEXT:    andps %xmm1, %xmm0
-; X64-NEXT:    xorps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    pxor {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    pcmpgtd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    pcmpeqd %xmm1, %xmm1
+; X64-NEXT:    pxor %xmm1, %xmm0
 ; X64-NEXT:    retq
-  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 960)
-  ret <4 x i1> %1
+  %ispos = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 960)
+  ret <4 x i1> %ispos
 }
 
-define <4 x i1> @isclass_negative_nnan(<4 x float> nofpclass(nan) %x) nounwind {
-; X86-LABEL: isclass_negative_nnan:
+define <4 x i1> @isclass_negative_nnan_v4f32(<4 x float> nofpclass(nan) %x) nounwind {
+; X86-LABEL: isclass_negative_nnan_v4f32:
 ; X86:       # %bb.0:
 ; X86-NEXT:    subl $16, %esp
 ; X86-NEXT:    flds {{[0-9]+}}(%esp)
@@ -3051,18 +3098,18 @@ define <4 x i1> @isclass_negative_nnan(<4 x float> nofpclass(nan) %x) nounwind {
 ; X86-NEXT:    addl $16, %esp
 ; X86-NEXT:    retl $4
 ;
-; X64-LABEL: isclass_negative_nnan:
+; X64-LABEL: isclass_negative_nnan_v4f32:
 ; X64:       # %bb.0:
 ; X64-NEXT:    pxor %xmm1, %xmm1
 ; X64-NEXT:    pcmpgtd %xmm0, %xmm1
 ; X64-NEXT:    movdqa %xmm1, %xmm0
 ; X64-NEXT:    retq
-  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 60)
-  ret <4 x i1> %1
+  %isneg = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 60)
+  ret <4 x i1> %isneg
 }
 
-define <4 x i1> @isclass_negative(<4 x float> %x) nounwind {
-; X86-LABEL: isclass_negative:
+define <4 x i1> @isclass_negative_v4f32(<4 x float> %x) nounwind {
+; X86-LABEL: isclass_negative_v4f32:
 ; X86:       # %bb.0:
 ; X86-NEXT:    pushl %ebx
 ; X86-NEXT:    subl $16, %esp
@@ -3121,15 +3168,15 @@ define <4 x i1> @isclass_negative(<4 x float> %x) nounwind {
 ; X86-NEXT:    popl %ebx
 ; X86-NEXT:    retl $4
 ;
-; X64-LABEL: isclass_negative:
+; X64-LABEL: isclass_negative_v4f32:
 ; X64:       # %bb.0:
 ; X64-NEXT:    pxor %xmm1, %xmm1
 ; X64-NEXT:    pcmpgtd %xmm0, %xmm1
 ; X64-NEXT:    cmpordps %xmm0, %xmm0
 ; X64-NEXT:    andps %xmm1, %xmm0
 ; X64-NEXT:    retq
-  %1 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 60)
-  ret <4 x i1> %1
+  %isneg = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 60)
+  ret <4 x i1> %isneg
 }
 
 declare i1 @llvm.is.fpclass.f32(float, i32)



More information about the llvm-commits mailing list