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. + MODIFY_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 @@ -6590,6 +6590,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(MODIFY_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_ModifyCSR : 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_modify_csr: SDNode<"RISCVISD::MODIFY_CSR", SDT_ModifyCSR, + [SDNPHasChain]>; def riscv_read_cycle_wide : SDNode<"RISCVISD::READ_CYCLE_WIDE", SDT_RISCVReadCycleWide, @@ -1146,6 +1155,26 @@ // 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 + +let hasSideEffects = 0, isCodeGenOnly = 1 in +def PseudoReadCSR : Pseudo<(outs GPR:$rd), (ins csr_sysreg:$reg), + [(set GPR:$rd, (riscv_read_csr simm12:$reg))], + "csrr", "$rd, $reg">, + PseudoInstExpansion<(CSRRC GPR:$rd, csr_sysreg:$reg, X0)>; + +let hasSideEffects = 1, isCodeGenOnly = 1 in +def PseudoWriteCSR : Pseudo<(outs), (ins csr_sysreg:$reg, GPR:$val), + [(riscv_write_csr simm12:$reg, GPR:$val)], + "csrw", "$reg, $val">, + PseudoInstExpansion<(CSRRW X0, csr_sysreg:$reg, GPR:$val)>; + +let hasSideEffects = 1, isCodeGenOnly = 1 in +def PseudoModifyCSR : Pseudo<(outs GPR:$rd), (ins csr_sysreg:$reg, GPR:$val), + [(set GPR:$rd, (riscv_modify_csr simm12:$reg, GPR:$val))], + "csrrw", "$rd, $reg, $val">, + PseudoInstExpansion<(CSRRW GPR:$rd, csr_sysreg:$reg, GPR:$val)>; + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered