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 @@ -219,6 +219,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-Modify-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 @@ -6610,6 +6610,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,9 @@ def SDT_RISCVBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>, SDTCisVT<2, OtherVT>, SDTCisVT<3, OtherVT>]>; +def SDT_ReadCSR : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisInt<1>]>; +def SDT_WriteCSR : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisInt<1>]>; +def SDT_SwapCSR : 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 +64,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_ReadCSR, + [SDNPHasChain]>; +def riscv_write_csr : SDNode<"RISCVISD::WRITE_CSR", SDT_WriteCSR, + [SDNPHasChain]>; +def riscv_swap_csr : SDNode<"RISCVISD::SWAP_CSR", SDT_SwapCSR, + [SDNPHasChain]>; def riscv_read_cycle_wide : SDNode<"RISCVISD::READ_CYCLE_WIDE", SDT_RISCVReadCycleWide, @@ -297,6 +306,7 @@ // Standalone (codegen-only) immleaf patterns. def simm32 : ImmLeaf(Imm);}]>; def simm32hi20 : ImmLeaf(Imm);}]>; +def uimm12 : ImmLeaf(Imm);}]>; // A 6-bit constant greater than 32. def uimm6gt32 : ImmLeaf, + PseudoInstExpansion<(CSRRC GPR:$rd, csr_sysreg:$reg, X0)>; + +let hasSideEffects = 1, isCodeGenOnly = 1 in +def Write_CSR : Pseudo<(outs), (ins csr_sysreg:$reg, GPR:$val), + [(riscv_write_csr uimm12:$reg, GPR:$val)]>, + PseudoInstExpansion<(CSRRW X0, csr_sysreg:$reg, GPR:$val)>; + +let hasSideEffects = 1, isCodeGenOnly = 1 in +def Swap_CSR : Pseudo<(outs GPR:$rd), (ins csr_sysreg:$reg, GPR:$val), + [(set GPR:$rd, (riscv_swap_csr uimm12:$reg, GPR:$val))]>, + PseudoInstExpansion<(CSRRW GPR:$rd, csr_sysreg:$reg, GPR:$val)>; + +// 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<(CSRRC 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 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; +} + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered