Skip to content

Commit 905bb5b

Browse files
authored
[RISCV][FPEnv] Lowering of fpmode intrinsics (llvm#148569)
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.
1 parent 828a867 commit 905bb5b

File tree

5 files changed

+159
-0
lines changed

5 files changed

+159
-0
lines changed

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,17 @@ inline static bool isValidRoundingMode(unsigned Mode) {
494494
}
495495
} // namespace RISCVVXRndMode
496496

497+
namespace RISCVExceptFlags {
498+
enum ExceptionFlag {
499+
NX = 0x01, // Inexact
500+
UF = 0x02, // Underflow
501+
OF = 0x04, // Overflow
502+
DZ = 0x08, // Divide by zero
503+
NV = 0x10, // Invalid operation
504+
ALL = 0x1F // Mask for all accrued exception flags
505+
};
506+
}
507+
497508
//===----------------------------------------------------------------------===//
498509
// Floating-point Immediates
499510
//

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
655655
setOperationAction(ISD::GET_FPENV, XLenVT, Custom);
656656
setOperationAction(ISD::SET_FPENV, XLenVT, Custom);
657657
setOperationAction(ISD::RESET_FPENV, MVT::Other, Custom);
658+
setOperationAction(ISD::GET_FPMODE, XLenVT, Custom);
659+
setOperationAction(ISD::SET_FPMODE, XLenVT, Custom);
660+
setOperationAction(ISD::RESET_FPMODE, MVT::Other, Custom);
658661
}
659662

660663
setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
@@ -8225,6 +8228,12 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
82258228
return lowerSET_FPENV(Op, DAG);
82268229
case ISD::RESET_FPENV:
82278230
return lowerRESET_FPENV(Op, DAG);
8231+
case ISD::GET_FPMODE:
8232+
return lowerGET_FPMODE(Op, DAG);
8233+
case ISD::SET_FPMODE:
8234+
return lowerSET_FPMODE(Op, DAG);
8235+
case ISD::RESET_FPMODE:
8236+
return lowerRESET_FPMODE(Op, DAG);
82288237
case ISD::EH_DWARF_CFA:
82298238
return lowerEH_DWARF_CFA(Op, DAG);
82308239
case ISD::VP_MERGE:
@@ -14002,6 +14011,54 @@ SDValue RISCVTargetLowering::lowerRESET_FPENV(SDValue Op,
1400214011
EnvValue);
1400314012
}
1400414013

14014+
const uint64_t ModeMask64 = ~RISCVExceptFlags::ALL;
14015+
const uint32_t ModeMask32 = ~RISCVExceptFlags::ALL;
14016+
14017+
SDValue RISCVTargetLowering::lowerGET_FPMODE(SDValue Op,
14018+
SelectionDAG &DAG) const {
14019+
const MVT XLenVT = Subtarget.getXLenVT();
14020+
const uint64_t ModeMaskValue = Subtarget.is64Bit() ? ModeMask64 : ModeMask32;
14021+
SDLoc DL(Op);
14022+
SDValue Chain = Op->getOperand(0);
14023+
SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT);
14024+
SDValue ModeMask = DAG.getConstant(ModeMaskValue, DL, XLenVT);
14025+
SDVTList VTs = DAG.getVTList(XLenVT, MVT::Other);
14026+
SDValue Result = DAG.getNode(RISCVISD::READ_CSR, DL, VTs, Chain, SysRegNo);
14027+
Chain = Result.getValue(1);
14028+
return DAG.getMergeValues({Result, Chain}, DL);
14029+
}
14030+
14031+
SDValue RISCVTargetLowering::lowerSET_FPMODE(SDValue Op,
14032+
SelectionDAG &DAG) const {
14033+
const MVT XLenVT = Subtarget.getXLenVT();
14034+
const uint64_t ModeMaskValue = Subtarget.is64Bit() ? ModeMask64 : ModeMask32;
14035+
SDLoc DL(Op);
14036+
SDValue Chain = Op->getOperand(0);
14037+
SDValue EnvValue = Op->getOperand(1);
14038+
SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT);
14039+
SDValue ModeMask = DAG.getConstant(ModeMaskValue, DL, XLenVT);
14040+
14041+
EnvValue = DAG.getNode(ISD::ZERO_EXTEND, DL, XLenVT, EnvValue);
14042+
EnvValue = DAG.getNode(ISD::AND, DL, XLenVT, EnvValue, ModeMask);
14043+
Chain = DAG.getNode(RISCVISD::CLEAR_CSR, DL, MVT::Other, Chain, SysRegNo,
14044+
ModeMask);
14045+
return DAG.getNode(RISCVISD::SET_CSR, DL, MVT::Other, Chain, SysRegNo,
14046+
EnvValue);
14047+
}
14048+
14049+
SDValue RISCVTargetLowering::lowerRESET_FPMODE(SDValue Op,
14050+
SelectionDAG &DAG) const {
14051+
const MVT XLenVT = Subtarget.getXLenVT();
14052+
const uint64_t ModeMaskValue = Subtarget.is64Bit() ? ModeMask64 : ModeMask32;
14053+
SDLoc DL(Op);
14054+
SDValue Chain = Op->getOperand(0);
14055+
SDValue SysRegNo = DAG.getTargetConstant(RISCVSysReg::fcsr, DL, XLenVT);
14056+
SDValue ModeMask = DAG.getConstant(ModeMaskValue, DL, XLenVT);
14057+
14058+
return DAG.getNode(RISCVISD::CLEAR_CSR, DL, MVT::Other, Chain, SysRegNo,
14059+
ModeMask);
14060+
}
14061+
1400514062
SDValue RISCVTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
1400614063
SelectionDAG &DAG) const {
1400714064
MachineFunction &MF = DAG.getMachineFunction();

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,9 @@ class RISCVTargetLowering : public TargetLowering {
563563
SDValue lowerGET_FPENV(SDValue Op, SelectionDAG &DAG) const;
564564
SDValue lowerSET_FPENV(SDValue Op, SelectionDAG &DAG) const;
565565
SDValue lowerRESET_FPENV(SDValue Op, SelectionDAG &DAG) const;
566+
SDValue lowerGET_FPMODE(SDValue Op, SelectionDAG &DAG) const;
567+
SDValue lowerSET_FPMODE(SDValue Op, SelectionDAG &DAG) const;
568+
SDValue lowerRESET_FPMODE(SDValue Op, SelectionDAG &DAG) const;
566569

567570
SDValue lowerEH_DWARF_CFA(SDValue Op, SelectionDAG &DAG) const;
568571
SDValue lowerCTLZ_CTTZ_ZERO_UNDEF(SDValue Op, SelectionDAG &DAG) const;

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ def riscv_swap_csr : RVSDNode<"SWAP_CSR",
120120
SDTCisInt<2>]>,
121121
[SDNPHasChain]>;
122122

123+
// Clear bits of CSR. The first operand is the address of the required CSR,
124+
// the second is the bitmask of cleared bits.
125+
def riscv_clear_csr : RVSDNode<"CLEAR_CSR",
126+
SDTypeProfile<0, 2, [SDTCisInt<0>,
127+
SDTCisInt<1>]>,
128+
[SDNPHasChain]>;
129+
130+
// Set bits of CSR. The first operand is the address of the required CSR,
131+
// the second is the bitmask of bits to set.
132+
def riscv_set_csr : RVSDNode<"SET_CSR",
133+
SDTypeProfile<0, 2, [SDTCisInt<0>,
134+
SDTCisInt<1>]>,
135+
[SDNPHasChain]>;
136+
123137
// A read of the 64-bit counter CSR on a 32-bit target (returns (Lo, Hi)).
124138
// It takes a chain operand and another two target constant operands (the
125139
// CSR numbers of the low and high parts of the counter).
@@ -2038,6 +2052,42 @@ class SwapSysRegImm<SysReg SR, list<Register> Regs>
20382052
let Defs = Regs;
20392053
}
20402054

2055+
class ClearSysReg<SysReg SR, list<Register> Regs>
2056+
: Pseudo<(outs), (ins GPR:$val),
2057+
[(riscv_clear_csr (XLenVT SR.Encoding), (XLenVT GPR:$val))]>,
2058+
PseudoInstExpansion<(CSRRC X0, SR.Encoding, GPR:$val)> {
2059+
let hasSideEffects = 0;
2060+
let Uses = Regs;
2061+
let Defs = Regs;
2062+
}
2063+
2064+
class ClearSysRegImm<SysReg SR, list<Register> Regs>
2065+
: Pseudo<(outs), (ins uimm5:$val),
2066+
[(riscv_clear_csr (XLenVT SR.Encoding), uimm5:$val)]>,
2067+
PseudoInstExpansion<(CSRRCI X0, SR.Encoding, uimm5:$val)> {
2068+
let hasSideEffects = 0;
2069+
let Uses = Regs;
2070+
let Defs = Regs;
2071+
}
2072+
2073+
class SetSysReg<SysReg SR, list<Register> Regs>
2074+
: Pseudo<(outs), (ins GPR:$val),
2075+
[(riscv_set_csr (XLenVT SR.Encoding), (XLenVT GPR:$val))]>,
2076+
PseudoInstExpansion<(CSRRS X0, SR.Encoding, GPR:$val)> {
2077+
let hasSideEffects = 0;
2078+
let Uses = Regs;
2079+
let Defs = Regs;
2080+
}
2081+
2082+
class SetSysRegImm<SysReg SR, list<Register> Regs>
2083+
: Pseudo<(outs), (ins uimm5:$val),
2084+
[(riscv_set_csr (XLenVT SR.Encoding), uimm5:$val)]>,
2085+
PseudoInstExpansion<(CSRRSI X0, SR.Encoding, uimm5:$val)> {
2086+
let hasSideEffects = 0;
2087+
let Uses = Regs;
2088+
let Defs = Regs;
2089+
}
2090+
20412091
def ReadFRM : ReadSysReg<SysRegFRM, [FRM]>;
20422092
let hasPostISelHook = 1 in {
20432093
def WriteFRM : WriteSysReg<SysRegFRM, [FRM]>;
@@ -2056,6 +2106,10 @@ let hasPostISelHook = 1 in {
20562106
def ReadFCSR : ReadSysReg<SysRegFCSR, [FRM, FFLAGS]>;
20572107
def WriteFCSR : WriteSysReg<SysRegFCSR, [FRM, FFLAGS]>;
20582108
def WriteFCSRImm : WriteSysRegImm<SysRegFCSR, [FRM, FFLAGS]>;
2109+
def ClearFCSR : ClearSysReg<SysRegFCSR, [FRM, FFLAGS]>;
2110+
def ClearFCSRImm : ClearSysRegImm<SysRegFCSR, [FRM, FFLAGS]>;
2111+
def SetFCSR : SetSysReg<SysRegFCSR, [FRM, FFLAGS]>;
2112+
def SetFCSRImm : SetSysRegImm<SysRegFCSR, [FRM, FFLAGS]>;
20592113
}
20602114

20612115
/// Other pseudo-instructions

llvm/test/CodeGen/RISCV/fpenv-xlen.ll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,37 @@ entry:
3535
call void @llvm.reset.fpenv()
3636
ret void
3737
}
38+
39+
define iXLen @func_get_fpmode() {
40+
; CHECK-LABEL: func_get_fpmode:
41+
; CHECK: # %bb.0: # %entry
42+
; CHECK-NEXT: frcsr a0
43+
; CHECK-NEXT: ret
44+
entry:
45+
%fpenv = call iXLen @llvm.get.fpmode.iXLen()
46+
ret iXLen %fpenv
47+
}
48+
49+
define void @func_set_fpmode(iXLen %fpmode) {
50+
; CHECK-LABEL: func_set_fpmode:
51+
; CHECK: # %bb.0: # %entry
52+
; CHECK-NEXT: li a1, -32
53+
; CHECK-NEXT: csrc fcsr, a1
54+
; CHECK-NEXT: andi a0, a0, -32
55+
; CHECK-NEXT: csrs fcsr, a0
56+
; CHECK-NEXT: ret
57+
entry:
58+
call void @llvm.set.fpmode.iXLen(iXLen %fpmode)
59+
ret void
60+
}
61+
62+
define void @func_reset_fpmode() {
63+
; CHECK-LABEL: func_reset_fpmode:
64+
; CHECK: # %bb.0: # %entry
65+
; CHECK-NEXT: li a0, -32
66+
; CHECK-NEXT: csrc fcsr, a0
67+
; CHECK-NEXT: ret
68+
entry:
69+
call void @llvm.reset.fpmode()
70+
ret void
71+
}

0 commit comments

Comments
 (0)