diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 0a849f49116ee..4abbb1329bff7 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -649,6 +649,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::GET_ROUNDING, XLenVT, Custom); setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom); + setOperationAction(ISD::GET_FPENV, XLenVT, Custom); + setOperationAction(ISD::SET_FPENV, XLenVT, Custom); + setOperationAction(ISD::RESET_FPENV, MVT::Other, Custom); } setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, @@ -8091,6 +8094,12 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, return lowerGET_ROUNDING(Op, DAG); case ISD::SET_ROUNDING: return lowerSET_ROUNDING(Op, DAG); + case ISD::GET_FPENV: + return lowerGET_FPENV(Op, DAG); + case ISD::SET_FPENV: + return lowerSET_FPENV(Op, DAG); + case ISD::RESET_FPENV: + return lowerRESET_FPENV(Op, DAG); case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG); case ISD::VP_MERGE: @@ -13665,6 +13674,41 @@ SDValue RISCVTargetLowering::lowerSET_ROUNDING(SDValue Op, RMValue); } +SDValue RISCVTargetLowering::lowerGET_FPENV(SDValue Op, + SelectionDAG &DAG) const { + const MVT XLenVT = Subtarget.getXLenVT(); + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT); + SDVTList VTs = DAG.getVTList(XLenVT, MVT::Other); + return DAG.getNode(RISCVISD::READ_CSR, DL, VTs, Chain, SysRegNo); +} + +SDValue RISCVTargetLowering::lowerSET_FPENV(SDValue Op, + SelectionDAG &DAG) const { + const MVT XLenVT = Subtarget.getXLenVT(); + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue EnvValue = Op->getOperand(1); + SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT); + + EnvValue = DAG.getNode(ISD::ZERO_EXTEND, DL, XLenVT, EnvValue); + return DAG.getNode(RISCVISD::WRITE_CSR, DL, MVT::Other, Chain, SysRegNo, + EnvValue); +} + +SDValue RISCVTargetLowering::lowerRESET_FPENV(SDValue Op, + SelectionDAG &DAG) const { + const MVT XLenVT = Subtarget.getXLenVT(); + SDLoc DL(Op); + SDValue Chain = Op->getOperand(0); + SDValue EnvValue = DAG.getRegister(RISCV::X0, XLenVT); + SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT); + + return DAG.getNode(RISCVISD::WRITE_CSR, DL, MVT::Other, Chain, SysRegNo, + EnvValue); +} + 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 78f2044ba83a7..771f1a7ec5ae1 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -537,6 +537,9 @@ class RISCVTargetLowering : public TargetLowering { unsigned ExtendOpc) const; SDValue lowerGET_ROUNDING(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSET_ROUNDING(SDValue Op, SelectionDAG &DAG) const; + 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 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 9058934557b54..6a51961557dbc 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -2028,6 +2028,13 @@ let hasSideEffects = true in { def ReadFFLAGS : ReadSysReg; def WriteFFLAGS : WriteSysReg; } + +let hasPostISelHook = 1 in { +def ReadFCSR : ReadSysReg; +def WriteFCSR : WriteSysReg; +def WriteFCSRImm : WriteSysRegImm; +} + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td index 80213e1503b0a..e87f4523a84f9 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -846,6 +846,7 @@ foreach m = LMULList in { def FFLAGS : RISCVReg<0, "fflags">; def FRM : RISCVReg<0, "frm">; +def FCSR : RISCVReg<0, "fcsr">; // Shadow Stack register def SSP : RISCVReg<0, "ssp">; diff --git a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll new file mode 100644 index 0000000000000..148186b21c125 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll @@ -0,0 +1,37 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs | FileCheck %s +; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs | FileCheck %s +; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zfinx -verify-machineinstrs | FileCheck %s +; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zfinx -verify-machineinstrs | FileCheck %s +; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs -O0 | FileCheck %s +; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs -O0 | FileCheck %s + +define iXLen @func_get_fpenv() { +; CHECK-LABEL: func_get_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: frcsr a0 +; CHECK-NEXT: ret +entry: + %fpenv = call iXLen @llvm.get.fpenv.iXLen() + ret iXLen %fpenv +} + +define void @func_set_fpenv(iXLen %fpenv) { +; CHECK-LABEL: func_set_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fscsr a0 +; CHECK-NEXT: ret +entry: + call void @llvm.set.fpenv.iXLen(iXLen %fpenv) + ret void +} + +define void @func_reset_fpenv() { +; CHECK-LABEL: func_reset_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fscsr zero +; CHECK-NEXT: ret +entry: + call void @llvm.reset.fpenv() + ret void +} diff --git a/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll b/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll index 4f435067343b7..72c5951178276 100644 --- a/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll +++ b/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll @@ -90,3 +90,34 @@ loop: exit: ret double %f2 } + +define double @foo2(double %0, double %1, i64 %n, i64 %fcsr) strictfp { +; CHECK-LABEL: foo2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fmv.d.x fa5, zero +; CHECK-NEXT: .LBB2_1: # %loop +; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: csrwi fcsr, 0 +; CHECK-NEXT: fadd.d fa5, fa5, fa0 +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: fscsr a1 +; CHECK-NEXT: fadd.d fa5, fa5, fa1 +; CHECK-NEXT: beqz a0, .LBB2_1 +; CHECK-NEXT: # %bb.2: # %exit +; CHECK-NEXT: fmv.d fa0, fa5 +; CHECK-NEXT: ret +entry: + br label %loop +loop: + %cnt = phi i64 [0, %entry], [%cnt_inc, %loop] + %acc = phi double [0.0, %entry], [%f2, %loop] + call void @llvm.set.fpenv(i64 0) strictfp + %f1 = call double @llvm.experimental.constrained.fadd.f64(double %acc, double %0, metadata !"round.dynamic", metadata !"fpexcept.ignore") strictfp + call void @llvm.set.fpenv(i64 %fcsr) strictfp + %f2 = call double @llvm.experimental.constrained.fadd.f64(double %f1, double %1, metadata !"round.dynamic", metadata !"fpexcept.ignore") strictfp + %cnt_inc = add i64 %cnt, 1 + %cond = icmp eq i64 %cnt_inc, %n + br i1 %cond, label %loop, label %exit +exit: + ret double %f2 +}