Skip to content

Commit d2eb527

Browse files
committed
[RISCV][FPEnv] Lowering of fpmode intrinsics
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 21491ed commit d2eb527

File tree

5 files changed

+161
-0
lines changed

5 files changed

+161
-0
lines changed

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

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

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

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

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

661664
setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
@@ -8226,6 +8229,12 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
82268229
return lowerSET_FPENV(Op, DAG);
82278230
case ISD::RESET_FPENV:
82288231
return lowerRESET_FPENV(Op, DAG);
8232+
case ISD::GET_FPMODE:
8233+
return lowerGET_FPMODE(Op, DAG);
8234+
case ISD::SET_FPMODE:
8235+
return lowerSET_FPMODE(Op, DAG);
8236+
case ISD::RESET_FPMODE:
8237+
return lowerRESET_FPMODE(Op, DAG);
82298238
case ISD::EH_DWARF_CFA:
82308239
return lowerEH_DWARF_CFA(Op, DAG);
82318240
case ISD::VP_MERGE:
@@ -13998,6 +14007,55 @@ SDValue RISCVTargetLowering::lowerRESET_FPENV(SDValue Op,
1399814007
EnvValue);
1399914008
}
1400014009

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

llvm/lib/Target/RISCV/RISCVISelLowering.h

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

566569
SDValue lowerEH_DWARF_CFA(SDValue Op, SelectionDAG &DAG) const;
567570
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: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,38 @@ 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: andi a0, a0, -32
44+
; CHECK-NEXT: ret
45+
entry:
46+
%fpenv = call iXLen @llvm.get.fpmode.iXLen()
47+
ret iXLen %fpenv
48+
}
49+
50+
define void @func_set_fpmode(iXLen %fpmode) {
51+
; CHECK-LABEL: func_set_fpmode:
52+
; CHECK: # %bb.0: # %entry
53+
; CHECK-NEXT: li a1, -32
54+
; CHECK-NEXT: csrc fcsr, a1
55+
; CHECK-NEXT: andi a0, a0, -32
56+
; CHECK-NEXT: csrs fcsr, a0
57+
; CHECK-NEXT: ret
58+
entry:
59+
call void @llvm.set.fpmode.iXLen(iXLen %fpmode)
60+
ret void
61+
}
62+
63+
define void @func_reset_fpmode() {
64+
; CHECK-LABEL: func_reset_fpmode:
65+
; CHECK: # %bb.0: # %entry
66+
; CHECK-NEXT: li a0, -32
67+
; CHECK-NEXT: csrc fcsr, a0
68+
; CHECK-NEXT: ret
69+
entry:
70+
call void @llvm.reset.fpmode()
71+
ret void
72+
}

0 commit comments

Comments
 (0)