diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h index f41ad419db1a7..18b28f5521034 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -495,6 +495,17 @@ inline static bool isValidRoundingMode(unsigned Mode) { } } // namespace RISCVVXRndMode +namespace RISCVExceptFlags { +enum ExceptionFlag { + NX = 0x01, // Inexact + UF = 0x02, // Underflow + OF = 0x04, // Overflow + DZ = 0x08, // Divide by zero + NV = 0x10, // Invalid operation + ALL = 0x1F // Mask for all accrued exception flags +}; +} + //===----------------------------------------------------------------------===// // Floating-point Immediates // diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 7c72d074a35b6..d26eb5eac3b70 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -656,6 +656,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::GET_FPENV, XLenVT, Custom); setOperationAction(ISD::SET_FPENV, XLenVT, Custom); setOperationAction(ISD::RESET_FPENV, MVT::Other, Custom); + setOperationAction(ISD::GET_FPMODE, XLenVT, Custom); + setOperationAction(ISD::SET_FPMODE, XLenVT, Custom); + setOperationAction(ISD::RESET_FPMODE, MVT::Other, Custom); } setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, @@ -8226,6 +8229,12 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, return lowerSET_FPENV(Op, DAG); case ISD::RESET_FPENV: return lowerRESET_FPENV(Op, DAG); + case ISD::GET_FPMODE: + return lowerGET_FPMODE(Op, DAG); + case ISD::SET_FPMODE: + return lowerSET_FPMODE(Op, DAG); + case ISD::RESET_FPMODE: + return lowerRESET_FPMODE(Op, DAG); case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG); case ISD::VP_MERGE: @@ -13998,6 +14007,54 @@ SDValue RISCVTargetLowering::lowerRESET_FPENV(SDValue Op, EnvValue); } +const uint64_t ModeMask64 = ~RISCVExceptFlags::ALL; +const uint32_t ModeMask32 = ~RISCVExceptFlags::ALL; + +SDValue RISCVTargetLowering::lowerGET_FPMODE(SDValue Op, + SelectionDAG &DAG) const { + const MVT XLenVT = Subtarget.getXLenVT(); + const uint64_t ModeMaskValue = Subtarget.is64Bit() ? ModeMask64 : ModeMask32; + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT); + SDValue ModeMask = DAG.getConstant(ModeMaskValue, DL, XLenVT); + SDVTList VTs = DAG.getVTList(XLenVT, MVT::Other); + SDValue Result = DAG.getNode(RISCVISD::READ_CSR, DL, VTs, Chain, SysRegNo); + Chain = Result.getValue(1); + return DAG.getMergeValues({Result, Chain}, DL); +} + +SDValue RISCVTargetLowering::lowerSET_FPMODE(SDValue Op, + SelectionDAG &DAG) const { + const MVT XLenVT = Subtarget.getXLenVT(); + const uint64_t ModeMaskValue = Subtarget.is64Bit() ? ModeMask64 : ModeMask32; + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue EnvValue = Op->getOperand(1); + SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT); + SDValue ModeMask = DAG.getConstant(ModeMaskValue, DL, XLenVT); + + EnvValue = DAG.getNode(ISD::ZERO_EXTEND, DL, XLenVT, EnvValue); + EnvValue = DAG.getNode(ISD::AND, DL, XLenVT, EnvValue, ModeMask); + Chain = DAG.getNode(RISCVISD::CLEAR_CSR, DL, MVT::Other, Chain, SysRegNo, + ModeMask); + return DAG.getNode(RISCVISD::SET_CSR, DL, MVT::Other, Chain, SysRegNo, + EnvValue); +} + +SDValue RISCVTargetLowering::lowerRESET_FPMODE(SDValue Op, + SelectionDAG &DAG) const { + const MVT XLenVT = Subtarget.getXLenVT(); + const uint64_t ModeMaskValue = Subtarget.is64Bit() ? ModeMask64 : ModeMask32; + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT); + SDValue ModeMask = DAG.getConstant(ModeMaskValue, DL, XLenVT); + + return DAG.getNode(RISCVISD::CLEAR_CSR, DL, MVT::Other, Chain, SysRegNo, + ModeMask); +} + SDValue RISCVTargetLowering::lowerEH_DWARF_CFA(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 00e969056df7d..1963cfeca59c8 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -562,6 +562,9 @@ class RISCVTargetLowering : public TargetLowering { SDValue lowerGET_FPENV(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSET_FPENV(SDValue Op, SelectionDAG &DAG) const; SDValue lowerRESET_FPENV(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGET_FPMODE(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSET_FPMODE(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerRESET_FPMODE(SDValue Op, SelectionDAG &DAG) const; SDValue lowerEH_DWARF_CFA(SDValue Op, SelectionDAG &DAG) const; SDValue lowerCTLZ_CTTZ_ZERO_UNDEF(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index f63531a0109b0..653607827282e 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -120,6 +120,20 @@ def riscv_swap_csr : RVSDNode<"SWAP_CSR", SDTCisInt<2>]>, [SDNPHasChain]>; +// Clear bits of CSR. The first operand is the address of the required CSR, +// the second is the bitmask of cleared bits. +def riscv_clear_csr : RVSDNode<"CLEAR_CSR", + SDTypeProfile<0, 2, [SDTCisInt<0>, + SDTCisInt<1>]>, + [SDNPHasChain]>; + +// Set bits of CSR. The first operand is the address of the required CSR, +// the second is the bitmask of bits to set. +def riscv_set_csr : RVSDNode<"SET_CSR", + SDTypeProfile<0, 2, [SDTCisInt<0>, + SDTCisInt<1>]>, + [SDNPHasChain]>; + // A read of the 64-bit counter CSR on a 32-bit target (returns (Lo, Hi)). // It takes a chain operand and another two target constant operands (the // CSR numbers of the low and high parts of the counter). @@ -2038,6 +2052,42 @@ class SwapSysRegImm Regs> let Defs = Regs; } +class ClearSysReg Regs> + : Pseudo<(outs), (ins GPR:$val), + [(riscv_clear_csr (XLenVT SR.Encoding), (XLenVT GPR:$val))]>, + PseudoInstExpansion<(CSRRC X0, SR.Encoding, GPR:$val)> { + let hasSideEffects = 0; + let Uses = Regs; + let Defs = Regs; +} + +class ClearSysRegImm Regs> + : Pseudo<(outs), (ins uimm5:$val), + [(riscv_clear_csr (XLenVT SR.Encoding), uimm5:$val)]>, + PseudoInstExpansion<(CSRRCI X0, SR.Encoding, uimm5:$val)> { + let hasSideEffects = 0; + let Uses = Regs; + let Defs = Regs; +} + +class SetSysReg Regs> + : Pseudo<(outs), (ins GPR:$val), + [(riscv_set_csr (XLenVT SR.Encoding), (XLenVT GPR:$val))]>, + PseudoInstExpansion<(CSRRS X0, SR.Encoding, GPR:$val)> { + let hasSideEffects = 0; + let Uses = Regs; + let Defs = Regs; +} + +class SetSysRegImm Regs> + : Pseudo<(outs), (ins uimm5:$val), + [(riscv_set_csr (XLenVT SR.Encoding), uimm5:$val)]>, + PseudoInstExpansion<(CSRRSI X0, SR.Encoding, uimm5:$val)> { + let hasSideEffects = 0; + let Uses = Regs; + let Defs = Regs; +} + def ReadFRM : ReadSysReg; let hasPostISelHook = 1 in { def WriteFRM : WriteSysReg; @@ -2056,6 +2106,10 @@ let hasPostISelHook = 1 in { def ReadFCSR : ReadSysReg; def WriteFCSR : WriteSysReg; def WriteFCSRImm : WriteSysRegImm; +def ClearFCSR : ClearSysReg; +def ClearFCSRImm : ClearSysRegImm; +def SetFCSR : SetSysReg; +def SetFCSRImm : SetSysRegImm; } /// Other pseudo-instructions diff --git a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll index 148186b21c125..255c120434f34 100644 --- a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll +++ b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll @@ -35,3 +35,37 @@ entry: call void @llvm.reset.fpenv() ret void } + +define iXLen @func_get_fpmode() { +; CHECK-LABEL: func_get_fpmode: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: frcsr a0 +; CHECK-NEXT: ret +entry: + %fpenv = call iXLen @llvm.get.fpmode.iXLen() + ret iXLen %fpenv +} + +define void @func_set_fpmode(iXLen %fpmode) { +; CHECK-LABEL: func_set_fpmode: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li a1, -32 +; CHECK-NEXT: csrc fcsr, a1 +; CHECK-NEXT: andi a0, a0, -32 +; CHECK-NEXT: csrs fcsr, a0 +; CHECK-NEXT: ret +entry: + call void @llvm.set.fpmode.iXLen(iXLen %fpmode) + ret void +} + +define void @func_reset_fpmode() { +; CHECK-LABEL: func_reset_fpmode: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li a0, -32 +; CHECK-NEXT: csrc fcsr, a0 +; CHECK-NEXT: ret +entry: + call void @llvm.reset.fpmode() + ret void +}