diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -605,6 +605,15 @@ VK == RISCVMCExpr::VK_RISCV_None; } + bool isUImm12() const { + if (!isImm()) + return false; + int64_t Imm; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && isUInt<12>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; + } + bool isSImm12() const { RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; int64_t Imm; 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 @@ -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(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, @@ -143,6 +152,20 @@ let OperandNamespace = "RISCVOp"; } +def uimm12 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<12>; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmOperand<12>"; + let MCOperandPredicate = [{ + int64_t Imm; + if (MCOp.evaluateAsConstantImm(Imm)) + return isUInt<12>(Imm); + return MCOp.isBareSymbolRef(); + }]; + let OperandType = "OPERAND_UIMM12"; + let OperandNamespace = "RISCVOp"; +} + def simm12 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<12>; let EncoderMethod = "getImmOpValue"; @@ -1146,6 +1169,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 Read_CSR : Pseudo<(outs GPR:$rd), (ins csr_sysreg:$reg), + [(set GPR:$rd, (riscv_read_csr uimm12:$reg))], + "csrr", "$rd, $reg">, + 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)], + "csrw", "$reg, $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))], + "csrrw", "$rd, $reg, $val">, + PseudoInstExpansion<(CSRRW GPR:$rd, csr_sysreg:$reg, GPR:$val)>; + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered