-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[RISCV][FPEnv] Lowering of fpmode intrinsics #148569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The change implements custom lowering of `get_fpmode`, `set_fpmode` and `reset_fpmode` for RISCV target. The implementation is aligned with the functions `fegetmode` and `fesetmode` in GLIBC.
|
@llvm/pr-subscribers-backend-risc-v Author: Serge Pavlov (spavloff) ChangesThe change implements custom lowering of Full diff: https://github.com/llvm/llvm-project/pull/148569.diff 5 Files Affected:
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index f41ad419db1a7..29261ccb39848 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..dbc6d684f997d 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,55 @@ 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);
+ Result = DAG.getNode(ISD::AND, DL, XLenVT, Result, ModeMask);
+ 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<SysReg SR, list<Register> Regs>
let Defs = Regs;
}
+class ClearSysReg<SysReg SR, list<Register> 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<SysReg SR, list<Register> 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<SysReg SR, list<Register> 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<SysReg SR, list<Register> 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<SysRegFRM, [FRM]>;
let hasPostISelHook = 1 in {
def WriteFRM : WriteSysReg<SysRegFRM, [FRM]>;
@@ -2056,6 +2106,10 @@ let hasPostISelHook = 1 in {
def ReadFCSR : ReadSysReg<SysRegFCSR, [FRM, FFLAGS]>;
def WriteFCSR : WriteSysReg<SysRegFCSR, [FRM, FFLAGS]>;
def WriteFCSRImm : WriteSysRegImm<SysRegFCSR, [FRM, FFLAGS]>;
+def ClearFCSR : ClearSysReg<SysRegFCSR, [FRM, FFLAGS]>;
+def ClearFCSRImm : ClearSysRegImm<SysRegFCSR, [FRM, FFLAGS]>;
+def SetFCSR : SetSysReg<SysRegFCSR, [FRM, FFLAGS]>;
+def SetFCSRImm : SetSysRegImm<SysRegFCSR, [FRM, FFLAGS]>;
}
/// Other pseudo-instructions
diff --git a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll
index 148186b21c125..c762f2ba41043 100644
--- a/llvm/test/CodeGen/RISCV/fpenv-xlen.ll
+++ b/llvm/test/CodeGen/RISCV/fpenv-xlen.ll
@@ -35,3 +35,38 @@ 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: andi a0, a0, -32
+; 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
+}
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
Can you point to where the glibc sources are masking out the exception bits? |
|
Ok, so the set masks, but |
|
Yes, you are right. The value returned by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Please sort the clang-format before you land this.
It was added by me in 905bb5b, which committed PR llvm#148569.
It was added by me in 905bb5b, which committed PR llvm/llvm-project#148569.
The change implements custom lowering of
get_fpmode,set_fpmodeandreset_fpmodefor RISCV target. The implementation is aligned with the functionsfegetmodeandfesetmodein GLIBC.