diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -227,6 +227,22 @@ VSEXT_VL, VZEXT_VL, + // Reads value of CSR. + // The first operand is a chain pointer. The second specifies address of the + // required CSR. Two results are produced, the read value and the new chain + // pointer. + READ_CSR, + // Write value to CSR. + // The first operand is a chain pointer, the second specifies address of the + // required CSR and the third is the value to write. The result is the new + // chain pointer. + WRITE_CSR, + // Read and write value of CSR. + // The first operand is a chain pointer, the second specifies address of the + // required CSR and the third is the value to write. Two results are produced, + // the value read before the modification and the new chain pointer. + SWAP_CSR, + // Memory opcodes start here. VLE_VL = ISD::FIRST_TARGET_MEMORY_OPCODE, VSE_VL, diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -7121,6 +7121,9 @@ NODE_NAME_CASE(VZEXT_VL) NODE_NAME_CASE(VLE_VL) NODE_NAME_CASE(VSE_VL) + NODE_NAME_CASE(READ_CSR) + NODE_NAME_CASE(WRITE_CSR) + NODE_NAME_CASE(SWAP_CSR) } // clang-format on return nullptr; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -28,6 +28,10 @@ def SDT_RISCVBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>, SDTCisVT<2, OtherVT>, SDTCisVT<3, OtherVT>]>; +def SDT_RISCVReadCSR : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisInt<1>]>; +def SDT_RISCVWriteCSR : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisInt<1>]>; +def SDT_RISCVSwapCSR : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisInt<1>, + SDTCisInt<2>]>; def SDT_RISCVReadCycleWide : SDTypeProfile<2, 0, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_RISCVIntBinOpW : SDTypeProfile<1, 2, [ @@ -61,6 +65,12 @@ def riscv_sllw : SDNode<"RISCVISD::SLLW", SDT_RISCVIntBinOpW>; def riscv_sraw : SDNode<"RISCVISD::SRAW", SDT_RISCVIntBinOpW>; def riscv_srlw : SDNode<"RISCVISD::SRLW", SDT_RISCVIntBinOpW>; +def riscv_read_csr : SDNode<"RISCVISD::READ_CSR", SDT_RISCVReadCSR, + [SDNPHasChain]>; +def riscv_write_csr : SDNode<"RISCVISD::WRITE_CSR", SDT_RISCVWriteCSR, + [SDNPHasChain]>; +def riscv_swap_csr : SDNode<"RISCVISD::SWAP_CSR", SDT_RISCVSwapCSR, + [SDNPHasChain]>; def riscv_read_cycle_wide : SDNode<"RISCVISD::READ_CYCLE_WIDE", SDT_RISCVReadCycleWide, @@ -1115,6 +1125,54 @@ // present. This is necessary as it isn't valid to mix __atomic_* libcalls // with inline atomic operations for the same object. +/// Access to system registers + +// Helpers for defining specific operations. They are defined for each system +// register separately. Side effect is not used because dependencies are +// expressed via use-def properties. + +class ReadSysReg Regs> + : Pseudo<(outs GPR:$rd), (ins), + [(set GPR:$rd, (riscv_read_csr (XLenVT SR.Encoding)))]>, + PseudoInstExpansion<(CSRRS GPR:$rd, SR.Encoding, X0)> { + let hasSideEffects = 0; + let Uses = Regs; +} + +class WriteSysReg Regs> + : Pseudo<(outs), (ins GPR:$val), + [(riscv_write_csr (XLenVT SR.Encoding), GPR:$val)]>, + PseudoInstExpansion<(CSRRW X0, SR.Encoding, GPR:$val)> { + let hasSideEffects = 0; + let Defs = Regs; +} + +class WriteSysRegImm Regs> + : Pseudo<(outs), (ins uimm5:$val), + [(riscv_write_csr (XLenVT SR.Encoding), uimm5:$val)]>, + PseudoInstExpansion<(CSRRWI X0, SR.Encoding, uimm5:$val)> { + let hasSideEffects = 0; + let Defs = Regs; +} + +class SwapSysReg Regs> + : Pseudo<(outs GPR:$rd), (ins GPR:$val), + [(set GPR:$rd, (riscv_swap_csr (XLenVT SR.Encoding), GPR:$val))]>, + PseudoInstExpansion<(CSRRW GPR:$rd, SR.Encoding, GPR:$val)> { + let hasSideEffects = 0; + let Uses = Regs; + let Defs = Regs; +} + +class SwapSysRegImm Regs> + : Pseudo<(outs GPR:$rd), (ins uimm5:$val), + [(set GPR:$rd, (riscv_swap_csr (XLenVT SR.Encoding), uimm5:$val))]>, + PseudoInstExpansion<(CSRRWI GPR:$rd, SR.Encoding, uimm5:$val)> { + let hasSideEffects = 0; + let Uses = Regs; + let Defs = Regs; +} + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered