diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -119,6 +119,7 @@ // inserter. FROUND, + FPCLASS, // READ_CYCLE_WIDE - A read of the 64-bit cycle CSR on a 32-bit target // (returns (Lo, Hi)). It takes a chain operand. READ_CYCLE_WIDE, diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -417,6 +417,7 @@ setOperationAction(FPOpToExpand, MVT::f32, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand); setTruncStoreAction(MVT::f32, MVT::f16, Expand); + setOperationAction(ISD::IS_FPCLASS, MVT::f32, Custom); if (Subtarget.hasStdExtZfa()) setOperationAction(ISD::FNEARBYINT, MVT::f32, Legal); @@ -4165,6 +4166,40 @@ switch (Op.getOpcode()) { default: report_fatal_error("unimplemented operand"); + case ISD::IS_FPCLASS: { + SDLoc DL(Op); + MVT VT = Op.getSimpleValueType(); + MVT XLenVT = Subtarget.getXLenVT(); + auto CNode = cast(Op.getOperand(1)); + unsigned Check = CNode->getZExtValue(); + unsigned TDCMask = 0; + if (Check & fcSNan) + TDCMask |= RISCV::FPMASK_Signaling_NaN; + if (Check & fcQNan) + TDCMask |= RISCV::FPMASK_Quiet_NaN; + if (Check & fcPosInf) + TDCMask |= RISCV::FPMASK_Positive_Infinity; + if (Check & fcNegInf) + TDCMask |= RISCV::FPMASK_Negative_Infinity; + if (Check & fcPosNormal) + TDCMask |= RISCV::FPMASK_Positive_Normal; + if (Check & fcNegNormal) + TDCMask |= RISCV::FPMASK_Negative_Normal; + if (Check & fcPosSubnormal) + TDCMask |= RISCV::FPMASK_Positive_Subnormal; + if (Check & fcNegSubnormal) + TDCMask |= RISCV::FPMASK_Negative_Subnormal; + if (Check & fcPosZero) + TDCMask |= RISCV::FPMASK_Positive_Zero; + if (Check & fcNegZero) + TDCMask |= RISCV::FPMASK_Negative_Zero; + + SDValue TDCMaskV = DAG.getConstant(TDCMask, DL, XLenVT); + SDValue FPCLASS = DAG.getNode(RISCVISD::FPCLASS, DL, VT, Op.getOperand(0)); + SDValue AND = DAG.getNode(ISD::AND, DL, VT, FPCLASS, TDCMaskV); + return DAG.getSetCC(DL, VT, AND, DAG.getConstant(0, DL, XLenVT), + ISD::CondCode::SETNE); + } case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG, Subtarget); case ISD::GlobalAddress: @@ -14581,6 +14616,7 @@ NODE_NAME_CASE(STRICT_FCVT_W_RV64) NODE_NAME_CASE(STRICT_FCVT_WU_RV64) NODE_NAME_CASE(FROUND) + NODE_NAME_CASE(FPCLASS) NODE_NAME_CASE(READ_CYCLE_WIDE) NODE_NAME_CASE(BREV8) NODE_NAME_CASE(ORC_B) diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h @@ -257,6 +257,17 @@ // Special immediate for AVL operand of V pseudo instructions to indicate VLMax. static constexpr int64_t VLMaxSentinel = -1LL; +// Mask assignments for floating-point +const unsigned FPMASK_Quiet_NaN = 0x200; +const unsigned FPMASK_Signaling_NaN = 0x100; +const unsigned FPMASK_Positive_Infinity = 0x080; +const unsigned FPMASK_Positive_Normal = 0x040; +const unsigned FPMASK_Positive_Subnormal = 0x020; +const unsigned FPMASK_Positive_Zero = 0x010; +const unsigned FPMASK_Negative_Zero = 0x008; +const unsigned FPMASK_Negative_Subnormal = 0x004; +const unsigned FPMASK_Negative_Normal = 0x002; +const unsigned FPMASK_Negative_Infinity = 0x001; } // namespace RISCV namespace RISCVVPseudosTable { diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -29,6 +29,11 @@ def SDT_RISCVFROUND : SDTypeProfile<1, 3, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<3, XLenVT>]>; +def SDT_RISCVFPCLASS + : SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisVT<1, f32>]>; + +def riscv_fpclass + : SDNode<"RISCVISD::FPCLASS", SDT_RISCVFPCLASS>; def riscv_fround : SDNode<"RISCVISD::FROUND", SDT_RISCVFROUND>; @@ -475,6 +480,8 @@ def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>; def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>; +def : Pat<(riscv_fpclass FPR32:$rs1), (FCLASS_S $rs1)>; + def : PatFprFpr; def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>; diff --git a/llvm/test/CodeGen/RISCV/float-intrinsics.ll b/llvm/test/CodeGen/RISCV/float-intrinsics.ll --- a/llvm/test/CodeGen/RISCV/float-intrinsics.ll +++ b/llvm/test/CodeGen/RISCV/float-intrinsics.ll @@ -1157,3 +1157,75 @@ %1 = call i64 @llvm.llround.i64.f32(float %a) ret i64 %1 } + +declare i1 @llvm.is.fpclass.f32(float, i32) +define i1 @fpclass(float %x) { +; RV32IF-LABEL: fpclass: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fclass.s a0, fa0 +; RV32IF-NEXT: andi a0, a0, 927 +; RV32IF-NEXT: snez a0, a0 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: fpclass: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fclass.s a0, fa0 +; RV64IF-NEXT: andi a0, a0, 927 +; RV64IF-NEXT: snez a0, a0 +; RV64IF-NEXT: ret +; +; RV32I-LABEL: fpclass: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a1, a0, 1 +; RV32I-NEXT: srli a1, a1, 1 +; RV32I-NEXT: addi a2, a1, -1 +; RV32I-NEXT: lui a3, 2048 +; RV32I-NEXT: addi a3, a3, -1 +; RV32I-NEXT: sltu a2, a2, a3 +; RV32I-NEXT: slti a0, a0, 0 +; RV32I-NEXT: and a2, a2, a0 +; RV32I-NEXT: seqz a3, a1 +; RV32I-NEXT: lui a4, 522240 +; RV32I-NEXT: xor a5, a1, a4 +; RV32I-NEXT: seqz a5, a5 +; RV32I-NEXT: or a3, a3, a5 +; RV32I-NEXT: or a2, a3, a2 +; RV32I-NEXT: slt a3, a4, a1 +; RV32I-NEXT: or a2, a2, a3 +; RV32I-NEXT: lui a3, 1046528 +; RV32I-NEXT: add a1, a1, a3 +; RV32I-NEXT: srli a1, a1, 24 +; RV32I-NEXT: sltiu a1, a1, 127 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: or a0, a2, a0 +; RV32I-NEXT: ret +; +; RV64I-LABEL: fpclass: +; RV64I: # %bb.0: +; RV64I-NEXT: sext.w a1, a0 +; RV64I-NEXT: slli a0, a0, 33 +; RV64I-NEXT: srli a0, a0, 33 +; RV64I-NEXT: addi a2, a0, -1 +; RV64I-NEXT: lui a3, 2048 +; RV64I-NEXT: addiw a3, a3, -1 +; RV64I-NEXT: sltu a2, a2, a3 +; RV64I-NEXT: slti a1, a1, 0 +; RV64I-NEXT: and a2, a2, a1 +; RV64I-NEXT: seqz a3, a0 +; RV64I-NEXT: lui a4, 522240 +; RV64I-NEXT: xor a5, a0, a4 +; RV64I-NEXT: seqz a5, a5 +; RV64I-NEXT: or a3, a3, a5 +; RV64I-NEXT: or a2, a3, a2 +; RV64I-NEXT: slt a3, a4, a0 +; RV64I-NEXT: or a2, a2, a3 +; RV64I-NEXT: lui a3, 1046528 +; RV64I-NEXT: add a0, a0, a3 +; RV64I-NEXT: srliw a0, a0, 24 +; RV64I-NEXT: sltiu a0, a0, 127 +; RV64I-NEXT: and a0, a0, a1 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ret + %cmp = call i1 @llvm.is.fpclass.f32(float %x, i32 639) + ret i1 %cmp +}