[llvm] c641b61 - MIPSr6: Add llvm.is.fpclasss intrinsic support (#107857)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 10 18:37:15 PDT 2024


Author: YunQiang Su
Date: 2024-09-11T09:37:12+08:00
New Revision: c641b611f86a846a51763a54a196375aba3e6e4e

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

LOG: MIPSr6: Add llvm.is.fpclasss intrinsic support (#107857)

MIPSr6 has class.s/class.d instructions.
Let's use them for llvm.is.fpclass intrinsic.

Added: 
    llvm/test/CodeGen/Mips/is_fpclass.ll

Modified: 
    llvm/lib/Target/Mips/Mips32r6InstrInfo.td
    llvm/lib/Target/Mips/MipsISelLowering.cpp
    llvm/lib/Target/Mips/MipsInstrInfo.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
index 91ffbc4eb77dda..27b9ce60ba8261 100644
--- a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
+++ b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
@@ -1139,6 +1139,43 @@ let AdditionalPredicates = [NotInMicroMips] in {
                 ISA_MIPS32R6;
 }
 
+// llvm.is_fpclass operations.
+def to_fclass_mask: SDNodeXForm<imm, [{
+  unsigned Check = N->getZExtValue();
+  unsigned Mask = 0;
+  if (Check & fcSNan)
+    Mask |= Mips::FClassMaskSignalingNaN;
+  if (Check & fcQNan)
+    Mask |= Mips::FClassMaskQuietNaN;
+  if (Check & fcPosInf)
+    Mask |= Mips::FClassMaskPositiveInfinity;
+  if (Check & fcNegInf)
+    Mask |= Mips::FClassMaskNegativeInfinity;
+  if (Check & fcPosNormal)
+    Mask |= Mips::FClassMaskPositiveNormal;
+  if (Check & fcNegNormal)
+    Mask |= Mips::FClassMaskNegativeNormal;
+  if (Check & fcPosSubnormal)
+    Mask |= Mips::FClassMaskPositiveSubnormal;
+  if (Check & fcNegSubnormal)
+    Mask |= Mips::FClassMaskNegativeSubnormal;
+  if (Check & fcPosZero)
+    Mask |= Mips::FClassMaskPositiveZero;
+  if (Check & fcNegZero)
+    Mask |= Mips::FClassMaskNegativeZero;
+  return CurDAG->getTargetConstant(Mask, SDLoc(N), MVT::i32);
+}]>;
+let AdditionalPredicates = [NotInMicroMips] in {
+  def : MipsPat<(is_fpclass f32:$lhs, i32:$imm),
+                (SLTu ZERO, (ANDi (MFC1 (CLASS_S f32:$lhs)),
+                          (to_fclass_mask imm:$imm)))>,
+                ISA_MIPS32R6;
+  def : MipsPat<(is_fpclass f64:$lhs, i32:$imm),
+                (SLTu ZERO, (ANDi (MFC1_D64 (CLASS_D f64:$lhs)),
+                          (to_fclass_mask imm:$imm)))>,
+                ISA_MIPS32R6;
+}
+
 // Pseudo instructions
 let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
     hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT], hasPostISelHook = 1 in {

diff  --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index fa57a3fa9b1557..59f78a8ca306c5 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -359,8 +359,7 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
   setOperationAction(ISD::FCOPYSIGN,          MVT::f64,   Custom);
   setOperationAction(ISD::FP_TO_SINT,         MVT::i32,   Custom);
 
-  // Lower fmin and fmax operations for MIPS R6.
-  // Instructions are defined but never used.
+  // Lower fmin/fmax/fclass operations for MIPS R6.
   if (Subtarget.hasMips32r6()) {
     setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
@@ -370,6 +369,8 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
     setOperationAction(ISD::FMINNUM, MVT::f64, Expand);
     setOperationAction(ISD::FMAXNUM, MVT::f64, Expand);
+    setOperationAction(ISD::IS_FPCLASS, MVT::f32, Legal);
+    setOperationAction(ISD::IS_FPCLASS, MVT::f64, Legal);
   } else {
     setOperationAction(ISD::FCANONICALIZE, MVT::f32, Custom);
     setOperationAction(ISD::FCANONICALIZE, MVT::f64, Custom);

diff  --git a/llvm/lib/Target/Mips/MipsInstrInfo.h b/llvm/lib/Target/Mips/MipsInstrInfo.h
index dc4b9d99b39d2a..4e039e0e32aba6 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.h
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.h
@@ -213,6 +213,23 @@ class MipsInstrInfo : public MipsGenInstrInfo {
 const MipsInstrInfo *createMips16InstrInfo(const MipsSubtarget &STI);
 const MipsInstrInfo *createMipsSEInstrInfo(const MipsSubtarget &STI);
 
+namespace Mips {
+// Mask assignments for floating-point.
+enum FClassMask {
+  FClassMaskSignalingNaN = 1 << 0,
+  FClassMaskQuietNaN = 1 << 1,
+  FClassMaskNegativeInfinity = 1 << 2,
+  FClassMaskNegativeNormal = 1 << 3,
+  FClassMaskNegativeSubnormal = 1 << 4,
+  FClassMaskNegativeZero = 1 << 5,
+  FClassMaskPositiveInfinity = 1 << 6,
+  FClassMaskPositiveNormal = 1 << 7,
+  FClassMaskPositiveSubnormal = 1 << 8,
+  FClassMaskPositiveZero = 1 << 9
+};
+
+} // namespace Mips
+
 } // end namespace llvm
 
 #endif // LLVM_LIB_TARGET_MIPS_MIPSINSTRINFO_H

diff  --git a/llvm/test/CodeGen/Mips/is_fpclass.ll b/llvm/test/CodeGen/Mips/is_fpclass.ll
new file mode 100644
index 00000000000000..9454a064c5312e
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/is_fpclass.ll
@@ -0,0 +1,246 @@
+; 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
+
+
+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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %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
+  %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 448)
+  ret i1 %1
+}
+
+declare i1 @llvm.is.fpclass.f32(float, i32)
+declare i1 @llvm.is.fpclass.f64(double, i32)


        


More information about the llvm-commits mailing list