From 178b8bb2e8f438e4fedcc7b490b9e0dcdb85d99b Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Mon, 26 May 2025 15:09:58 +0700 Subject: [PATCH 1/5] [RISCV][FPEnv] Lowering of fpenv intrinsics The change implements custom lowering of `get_fpenv`, `set_fpenv` and `reset_fpenv` for RISCV target. --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 3 ++ llvm/lib/Target/RISCV/RISCVInstrInfoF.td | 11 +++++++ llvm/test/CodeGen/RISCV/fpenv32.ll | 33 +++++++++++++++++++++ llvm/test/CodeGen/RISCV/fpenv64.ll | 33 +++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/fpenv32.ll create mode 100644 llvm/test/CodeGen/RISCV/fpenv64.ll diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 0a849f49116ee..b4f8038041e78 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, Legal); + setOperationAction(ISD::SET_FPENV, XLenVT, Legal); + setOperationAction(ISD::RESET_FPENV, MVT::Other, Legal); } setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td index 84a75666e5f36..9edfe34e0b67b 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -736,6 +736,17 @@ def : LdPat; def : StPat; } // Predicates = [HasStdExtZfinx] +/// Floating-point environment +multiclass FPEnvironmentOps { + let Predicates = [HasFloatExt] in { + def : Pat<(XLenVT (get_fpenv)), (CSRRS SysRegFCSR.Encoding, (XLenVT X0))>; + def : Pat<(set_fpenv (XLenVT GPR:$rs)), (CSRRW SysRegFCSR.Encoding, GPR:$rs)>; + def : Pat<(reset_fpenv), (CSRRW SysRegFCSR.Encoding, (XLenVT X0))>; + } +} +defm : FPEnvironmentOps; +defm : FPEnvironmentOps; + let Predicates = [HasStdExtF, IsRV32] in { // Moves (no conversion) def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>; diff --git a/llvm/test/CodeGen/RISCV/fpenv32.ll b/llvm/test/CodeGen/RISCV/fpenv32.ll new file mode 100644 index 0000000000000..4d4976d391f80 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/fpenv32.ll @@ -0,0 +1,33 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=riscv32 -mattr=+zfinx -verify-machineinstrs < %s | FileCheck %s + +define i32 @func_get_fpenv() { +; CHECK-LABEL: func_get_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: frcsr a0 +; CHECK-NEXT: ret +entry: + %fpenv = call i32 @llvm.get.fpenv.i32() + ret i32 %fpenv +} + +define void @func_set_fpenv(i32 %fpenv) { +; CHECK-LABEL: func_set_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fscsr a0 +; CHECK-NEXT: ret +entry: + call void @llvm.set.fpenv.i32(i32 %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/fpenv64.ll b/llvm/test/CodeGen/RISCV/fpenv64.ll new file mode 100644 index 0000000000000..3a7a455c3eed1 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/fpenv64.ll @@ -0,0 +1,33 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=riscv64 -mattr=+zfinx -verify-machineinstrs < %s | FileCheck %s + +define i64 @func_get_fpenv() { +; CHECK-LABEL: func_get_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: frcsr a0 +; CHECK-NEXT: ret +entry: + %fpenv = call i64 @llvm.get.fpenv.i64() + ret i64 %fpenv +} + +define void @func_set_fpenv(i64 %fpenv) { +; CHECK-LABEL: func_set_fpenv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fscsr a0 +; CHECK-NEXT: ret +entry: + call void @llvm.set.fpenv.i64(i64 %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 +} From f3cc23e9b08d9869f7de5c33c9a64521727e4ec0 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Tue, 27 May 2025 18:29:58 +0700 Subject: [PATCH 2/5] Address review comments --- llvm/lib/Target/RISCV/RISCVInstrInfoF.td | 12 +++----- llvm/test/CodeGen/RISCV/fpenv.ll | 37 ++++++++++++++++++++++-- llvm/test/CodeGen/RISCV/fpenv32.ll | 33 --------------------- llvm/test/CodeGen/RISCV/fpenv64.ll | 33 --------------------- 4 files changed, 38 insertions(+), 77 deletions(-) delete mode 100644 llvm/test/CodeGen/RISCV/fpenv32.ll delete mode 100644 llvm/test/CodeGen/RISCV/fpenv64.ll diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td index 9edfe34e0b67b..b4b77b639080b 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -737,15 +737,11 @@ def : StPat; } // Predicates = [HasStdExtZfinx] /// Floating-point environment -multiclass FPEnvironmentOps { - let Predicates = [HasFloatExt] in { - def : Pat<(XLenVT (get_fpenv)), (CSRRS SysRegFCSR.Encoding, (XLenVT X0))>; - def : Pat<(set_fpenv (XLenVT GPR:$rs)), (CSRRW SysRegFCSR.Encoding, GPR:$rs)>; - def : Pat<(reset_fpenv), (CSRRW SysRegFCSR.Encoding, (XLenVT X0))>; - } +let Predicates = [HasStdExtFOrZfinx] in { +def : Pat<(XLenVT (get_fpenv)), (CSRRS SysRegFCSR.Encoding, (XLenVT X0))>; +def : Pat<(set_fpenv (XLenVT GPR:$rs)), (CSRRW SysRegFCSR.Encoding, GPR:$rs)>; +def : Pat<(reset_fpenv), (CSRRW SysRegFCSR.Encoding, (XLenVT X0))>; } -defm : FPEnvironmentOps; -defm : FPEnvironmentOps; let Predicates = [HasStdExtF, IsRV32] in { // Moves (no conversion) diff --git a/llvm/test/CodeGen/RISCV/fpenv.ll b/llvm/test/CodeGen/RISCV/fpenv.ll index 11e104a290e1b..28efcad4d03b6 100644 --- a/llvm/test/CodeGen/RISCV/fpenv.ll +++ b/llvm/test/CodeGen/RISCV/fpenv.ll @@ -1,6 +1,7 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s | FileCheck -check-prefix=RV32IF %s -; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s | FileCheck -check-prefix=RV64IF %s +; 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 define i32 @func_01() { ; RV32IF-LABEL: func_01: @@ -212,6 +213,36 @@ define void @func_07() { ret void } +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 +} + attributes #0 = { strictfp } declare void @llvm.set.rounding(i32) diff --git a/llvm/test/CodeGen/RISCV/fpenv32.ll b/llvm/test/CodeGen/RISCV/fpenv32.ll deleted file mode 100644 index 4d4976d391f80..0000000000000 --- a/llvm/test/CodeGen/RISCV/fpenv32.ll +++ /dev/null @@ -1,33 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 -; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s | FileCheck %s -; RUN: llc -mtriple=riscv32 -mattr=+zfinx -verify-machineinstrs < %s | FileCheck %s - -define i32 @func_get_fpenv() { -; CHECK-LABEL: func_get_fpenv: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: frcsr a0 -; CHECK-NEXT: ret -entry: - %fpenv = call i32 @llvm.get.fpenv.i32() - ret i32 %fpenv -} - -define void @func_set_fpenv(i32 %fpenv) { -; CHECK-LABEL: func_set_fpenv: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: fscsr a0 -; CHECK-NEXT: ret -entry: - call void @llvm.set.fpenv.i32(i32 %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/fpenv64.ll b/llvm/test/CodeGen/RISCV/fpenv64.ll deleted file mode 100644 index 3a7a455c3eed1..0000000000000 --- a/llvm/test/CodeGen/RISCV/fpenv64.ll +++ /dev/null @@ -1,33 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 -; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s | FileCheck %s -; RUN: llc -mtriple=riscv64 -mattr=+zfinx -verify-machineinstrs < %s | FileCheck %s - -define i64 @func_get_fpenv() { -; CHECK-LABEL: func_get_fpenv: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: frcsr a0 -; CHECK-NEXT: ret -entry: - %fpenv = call i64 @llvm.get.fpenv.i64() - ret i64 %fpenv -} - -define void @func_set_fpenv(i64 %fpenv) { -; CHECK-LABEL: func_set_fpenv: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: fscsr a0 -; CHECK-NEXT: ret -entry: - call void @llvm.set.fpenv.i64(i64 %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 -} From 31f476c7be64ca65c83c576472c5bedd62b6a624 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Tue, 27 May 2025 16:12:28 +0000 Subject: [PATCH 3/5] Move tests to a separate file to avoid bloating fpenv.ll --- llvm/test/CodeGen/RISCV/fpenv-xlen.ll | 35 +++++++++++++++++++++++++ llvm/test/CodeGen/RISCV/fpenv.ll | 37 +++------------------------ 2 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 llvm/test/CodeGen/RISCV/fpenv-xlen.ll diff --git a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll new file mode 100644 index 0000000000000..90d6ace923c3d --- /dev/null +++ b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll @@ -0,0 +1,35 @@ +; 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 + +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/fpenv.ll b/llvm/test/CodeGen/RISCV/fpenv.ll index 28efcad4d03b6..11e104a290e1b 100644 --- a/llvm/test/CodeGen/RISCV/fpenv.ll +++ b/llvm/test/CodeGen/RISCV/fpenv.ll @@ -1,7 +1,6 @@ -; 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 +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s | FileCheck -check-prefix=RV32IF %s +; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s | FileCheck -check-prefix=RV64IF %s define i32 @func_01() { ; RV32IF-LABEL: func_01: @@ -213,36 +212,6 @@ define void @func_07() { ret void } -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 -} - attributes #0 = { strictfp } declare void @llvm.set.rounding(i32) From 64ad9c7289de12888ad371d202c4a51caab19103 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 29 May 2025 11:13:03 +0700 Subject: [PATCH 4/5] Fix O0 codegen and def/uses --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 47 +++++++++++++++++++-- llvm/lib/Target/RISCV/RISCVISelLowering.h | 3 ++ llvm/lib/Target/RISCV/RISCVInstrInfo.td | 5 +++ llvm/lib/Target/RISCV/RISCVInstrInfoF.td | 7 --- llvm/lib/Target/RISCV/RISCVRegisterInfo.td | 1 + llvm/test/CodeGen/RISCV/fpenv-xlen.ll | 2 + 6 files changed, 55 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index b4f8038041e78..4abbb1329bff7 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -649,9 +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, Legal); - setOperationAction(ISD::SET_FPENV, XLenVT, Legal); - setOperationAction(ISD::RESET_FPENV, MVT::Other, Legal); + 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, @@ -8094,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: @@ -13668,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..26147ff52acd4 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -2028,6 +2028,11 @@ let hasSideEffects = true in { def ReadFFLAGS : ReadSysReg; def WriteFFLAGS : WriteSysReg; } + +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/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td index b4b77b639080b..84a75666e5f36 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -736,13 +736,6 @@ def : LdPat; def : StPat; } // Predicates = [HasStdExtZfinx] -/// Floating-point environment -let Predicates = [HasStdExtFOrZfinx] in { -def : Pat<(XLenVT (get_fpenv)), (CSRRS SysRegFCSR.Encoding, (XLenVT X0))>; -def : Pat<(set_fpenv (XLenVT GPR:$rs)), (CSRRW SysRegFCSR.Encoding, GPR:$rs)>; -def : Pat<(reset_fpenv), (CSRRW SysRegFCSR.Encoding, (XLenVT X0))>; -} - let Predicates = [HasStdExtF, IsRV32] in { // Moves (no conversion) def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>; 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 index 90d6ace923c3d..148186b21c125 100644 --- a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll +++ b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll @@ -3,6 +3,8 @@ ; 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: From 719234fdd05e2001cd72b7bda5c3f3e860db49de Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Sat, 7 Jun 2025 11:23:10 +0700 Subject: [PATCH 5/5] Avoid setting flag Dead on the writes to FCSR --- llvm/lib/Target/RISCV/RISCVInstrInfo.td | 2 ++ llvm/test/CodeGen/RISCV/frm-write-in-loop.ll | 31 ++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index 26147ff52acd4..6a51961557dbc 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -2029,9 +2029,11 @@ def ReadFFLAGS : ReadSysReg; def WriteFFLAGS : WriteSysReg; } +let hasPostISelHook = 1 in { def ReadFCSR : ReadSysReg; def WriteFCSR : WriteSysReg; def WriteFCSRImm : WriteSysRegImm; +} /// Other pseudo-instructions 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 +}