[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