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 @@ -1803,18 +1803,57 @@ if (getParser().parseIdentifier(Identifier)) return ParseStatus::Failure; + // Check for CSR names conflicts. + // Custom CSR names might conflict with CSR names in privileged spec. + // E.g. - SiFive mnscratch(0x350) and privileged spec mnscratch(0x740). + auto CheckCSRNameConflict = [&]() { + if (!(RISCVSysReg::lookupSysRegByName(Identifier))) { + Error(S, "system register use requires an option to be enabled"); + return true; + } + return false; + }; + + // First check for vendor specific CSRs. + auto SiFiveReg = RISCVSysReg::lookupSiFiveRegByName(Identifier); + if (SiFiveReg) { + if (SiFiveReg->haveVendorRequiredFeatures(getSTI().getFeatureBits())) { + Operands.push_back( + RISCVOperand::createSysReg(Identifier, S, SiFiveReg->Encoding)); + return ParseStatus::Success; + } + if (CheckCSRNameConflict()) + return ParseStatus::Failure; + } + auto SysReg = RISCVSysReg::lookupSysRegByName(Identifier); - if (!SysReg) - SysReg = RISCVSysReg::lookupSysRegByAltName(Identifier); if (!SysReg) if ((SysReg = RISCVSysReg::lookupSysRegByDeprecatedName(Identifier))) Warning(S, "'" + Identifier + "' is a deprecated alias for '" + SysReg->Name + "'"); - // Accept a named Sys Reg if the required features are present. + // Check for CSR encoding conflicts. + // Custom CSR encoding might conflict with CSR encoding in privileged spec. + // E.g. - SiFive mnscratch(0x350) and privileged spec miselect(0x350). + auto CheckCSREncodingConflict = [&]() { + auto Reg = RISCVSysReg::lookupSiFiveRegByEncoding(SysReg->Encoding); + if (Reg && Reg->haveVendorRequiredFeatures(getSTI().getFeatureBits())) { + Warning(S, "'" + Identifier + "' CSR is not available on the current " + + "subtarget. Instead '" + Reg->Name + + "' CSR will be used."); + Operands.push_back( + RISCVOperand::createSysReg(Reg->Name, S, Reg->Encoding)); + return true; + } + return false; + }; + + // Accept a named SysReg if the required features are present. if (SysReg) { if (!SysReg->haveRequiredFeatures(getSTI().getFeatureBits())) return Error(S, "system register use requires an option to be enabled"); + if (CheckCSREncodingConflict()) + return ParseStatus::Success; Operands.push_back( RISCVOperand::createSysReg(Identifier, S, SysReg->Encoding)); return ParseStatus::Success; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -363,7 +363,6 @@ namespace RISCVSysReg { struct SysReg { const char *Name; - const char *AltName; const char *DeprecatedName; unsigned Encoding; // FIXME: add these additional fields when needed. @@ -387,9 +386,22 @@ return true; return (FeaturesRequired & ActiveFeatures) == FeaturesRequired; } + + bool haveVendorRequiredFeatures(const FeatureBitset &ActiveFeatures) const { + // Not in 32-bit mode. + if (isRV32Only && ActiveFeatures[RISCV::Feature64Bit]) + return false; + // No required feature associated with the system register. + if (FeaturesRequired.none()) + return false; + return (FeaturesRequired & ActiveFeatures) == FeaturesRequired; + } }; +struct SiFiveReg : SysReg {}; + #define GET_SysRegsList_DECL +#define GET_SiFiveRegsList_DECL #include "RISCVGenSearchableTables.inc" } // end namespace RISCVSysReg diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp @@ -27,6 +27,7 @@ namespace RISCVSysReg { #define GET_SysRegsList_IMPL +#define GET_SiFiveRegsList_IMPL #include "RISCVGenSearchableTables.inc" } // namespace RISCVSysReg diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp @@ -120,8 +120,11 @@ const MCSubtargetInfo &STI, raw_ostream &O) { unsigned Imm = MI->getOperand(OpNo).getImm(); + auto SiFiveReg = RISCVSysReg::lookupSiFiveRegByEncoding(Imm); auto SysReg = RISCVSysReg::lookupSysRegByEncoding(Imm); - if (SysReg && SysReg->haveRequiredFeatures(STI.getFeatureBits())) + if (SiFiveReg && SiFiveReg->haveVendorRequiredFeatures(STI.getFeatureBits())) + O << SiFiveReg->Name; + else if (SysReg && SysReg->haveRequiredFeatures(STI.getFeatureBits())) O << SysReg->Name; else O << Imm; diff --git a/llvm/lib/Target/RISCV/RISCVSystemOperands.td b/llvm/lib/Target/RISCV/RISCVSystemOperands.td --- a/llvm/lib/Target/RISCV/RISCVSystemOperands.td +++ b/llvm/lib/Target/RISCV/RISCVSystemOperands.td @@ -19,11 +19,9 @@ class SysReg op> { string Name = name; - // A maximum of one alias is supported right now. - string AltName = name; - // A maximum of one deprecated name is supported right now. Unlike the - // `AltName` alias, a `DeprecatedName` generates a diagnostic when the name is - // used to encourage software to migrate away from the name. + // A maximum of one deprecated name is supported right now. It generates a + // diagnostic when the name is used to encourage software to migrate away from + // the name. string DeprecatedName = ""; bits<12> Encoding = op; // FIXME: add these additional fields when needed. @@ -43,7 +41,7 @@ let FilterClass = "SysReg"; // FIXME: add "ReadWrite", "Mode", "Extra", "Number" fields when needed. let Fields = [ - "Name", "AltName", "DeprecatedName", "Encoding", "FeaturesRequired", + "Name", "DeprecatedName", "Encoding", "FeaturesRequired", "isRV32Only", ]; @@ -56,13 +54,32 @@ let Key = [ "Name" ]; } -def lookupSysRegByAltName : SearchIndex { +def lookupSysRegByDeprecatedName : SearchIndex { let Table = SysRegsList; - let Key = [ "AltName" ]; + let Key = [ "DeprecatedName" ]; } -def lookupSysRegByDeprecatedName : SearchIndex { - let Table = SysRegsList; +class SiFiveReg op> : SysReg; + +def SiFiveRegsList : GenericTable { + let FilterClass = "SiFiveReg"; + // FIXME: add "ReadWrite", "Mode", "Extra", "Number" fields when needed. + let Fields = [ + "Name", "DeprecatedName", "Encoding", "FeaturesRequired", + "isRV32Only", + ]; + + let PrimaryKey = [ "Encoding" ]; + let PrimaryKeyName = "lookupSiFiveRegByEncoding"; +} + +def lookupSiFiveRegByName : SearchIndex { + let Table = SiFiveRegsList; + let Key = [ "Name" ]; +} + +def lookupSiFiveRegByDeprecatedName : SearchIndex { + let Table = SiFiveRegsList; let Key = [ "DeprecatedName" ]; } @@ -292,7 +309,7 @@ //===----------------------------------------------------------------------===// // Machine Counter Setup //===----------------------------------------------------------------------===// -let AltName = "mucounteren" in // Privileged spec v1.9.1 Name +let DeprecatedName = "mucounteren" in // Privileged spec v1.9.1 Name def : SysReg<"mcountinhibit", 0x320>; // mhpmevent3-mhpmevent31 at 0x323-0x33F. @@ -305,6 +322,20 @@ def : SysReg<"mhpmevent"#i#"h", !add(0x723, !sub(i, 3))>; } +//===----------------------------------------------------------------------===// +// SiFive Custom Machine Mode Registers +//===----------------------------------------------------------------------===// + +let FeaturesRequired = [{ {RISCV::FeatureVendorXSfcie} }] in { +def : SiFiveReg<"mnscratch", 0x350>; +def : SiFiveReg<"mnepc", 0x351>; +def : SiFiveReg<"mncause", 0x352>; +def : SiFiveReg<"mnstatus", 0x353>; +def : SiFiveReg<"mbpm", 0x7C0>; +def : SiFiveReg<"mfd", 0x7C1>; +def : SiFiveReg<"mpd", 0x7C8>; +} + //===----------------------------------------------------------------------===// // Debug/ Trace Registers (shared with Debug Mode) //===----------------------------------------------------------------------===// @@ -322,7 +353,7 @@ // "dscratch" is an alternative name for "dscratch0" which appeared in earlier // drafts of the RISC-V debug spec -let AltName = "dscratch" in +let DeprecatedName = "dscratch" in def : SysReg<"dscratch0", 0x7B2>; def : SysReg<"dscratch1", 0x7B3>; diff --git a/llvm/test/MC/RISCV/machine-csr-names.s b/llvm/test/MC/RISCV/machine-csr-names.s --- a/llvm/test/MC/RISCV/machine-csr-names.s +++ b/llvm/test/MC/RISCV/machine-csr-names.s @@ -9,6 +9,9 @@ # RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ # RUN: | llvm-objdump -d - \ # RUN: | FileCheck -check-prefix=CHECK-INST-ALIAS %s +# +# RUN: llvm-mc -triple riscv32 %s 2>&1 | FileCheck -check-prefix CHECK-WARN %s +# RUN: llvm-mc -triple riscv64 %s 2>&1 | FileCheck -check-prefix CHECK-WARN %s ################################## # Machine Information Registers @@ -1492,6 +1495,8 @@ # uimm12 csrrs t2, 0x7B2, zero +# CHECK-WARN: warning: 'dscratch' is a deprecated alias for 'dscratch0' + # dscratch1 # name # CHECK-INST: csrrs t1, dscratch1, zero @@ -1944,6 +1949,8 @@ # uimm12 csrrs t2, 0x320, zero +# CHECK-WARN: warning: 'mucounteren' is a deprecated alias for 'mcountinhibit' + # mhpmevent3 # name # CHECK-INST: csrrs t1, mhpmevent3, zero diff --git a/llvm/test/MC/RISCV/xsfcie-invalid.s b/llvm/test/MC/RISCV/xsfcie-invalid.s --- a/llvm/test/MC/RISCV/xsfcie-invalid.s +++ b/llvm/test/MC/RISCV/xsfcie-invalid.s @@ -23,3 +23,17 @@ cease 0x10 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction cease # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'XSfcie' (SiFive Custom Instruction Extension SCIE.) + +csrr t1, mbpm # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled + +csrr t1, mfd # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled + +csrr t1, mpd # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled + +csrr t1, mnscratch # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled + +csrr t1, mnepc # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled + +csrr t1, mncause # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled + +csrr t1, mnstatus # CHECK: :[[@LINE]]:10: error: system register use requires an option to be enabled diff --git a/llvm/test/MC/RISCV/xsfcie-valid.s b/llvm/test/MC/RISCV/xsfcie-valid.s --- a/llvm/test/MC/RISCV/xsfcie-valid.s +++ b/llvm/test/MC/RISCV/xsfcie-valid.s @@ -3,6 +3,10 @@ # RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s # RUN: llvm-mc %s -triple=riscv64 -mattr=+xsfcie -riscv-no-aliases -show-encoding \ # RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s +# RUN: llvm-mc %s -triple=riscv32 -mattr=+xsfcie -riscv-no-aliases -show-encoding 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-WARN %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+xsfcie -riscv-no-aliases -show-encoding 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-WARN %s # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+xsfcie < %s \ # RUN: | llvm-objdump --mattr=+xsfcie -M no-aliases -d - \ # RUN: | FileCheck -check-prefix=CHECK-INST %s @@ -11,6 +15,8 @@ # RUN: | FileCheck -check-prefix=CHECK-INST %s # RUN: llvm-mc %s -triple=riscv64 -mcpu=sifive-s76 -riscv-no-aliases -show-encoding \ # RUN: | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s +# RUN: llvm-mc %s -triple=riscv64 -mcpu=sifive-s76 -riscv-no-aliases -show-encoding 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-WARN %s # RUN: llvm-mc -filetype=obj -triple riscv64 -mcpu=sifive-s76 < %s \ # RUN: | llvm-objdump --mcpu=sifive-s76 -M no-aliases -d - \ # RUN: | FileCheck -check-prefix=CHECK-INST %s @@ -40,3 +46,91 @@ # CHECK-INST: cease # CHECK-ENC: encoding: [0x73,0x00,0x50,0x30] cease + +# mbpm +# name +# CHECK-INST: csrrs t2, mbpm, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x00,0x7c] +# uimm12 +# CHECK-INST: csrrs t2, mbpm, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x00,0x7c] +# name +csrrs t2, mbpm, zero +# uimm12 +csrrs t2, 0x7C0, zero + +# mfd +# name +# CHECK-INST: csrrs t2, mfd, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x10,0x7c] +# uimm12 +# CHECK-INST: csrrs t2, mfd, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x10,0x7c] +# name +csrrs t2, mfd, zero +# uimm12 +csrrs t2, 0x7C1, zero + +# mpd +# name +# CHECK-INST: csrrs t2, mpd, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x80,0x7c] +# uimm12 +# CHECK-INST: csrrs t2, mpd, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x80,0x7c] +# name +csrrs t2, mpd, zero +# uimm12 +csrrs t2, 0x7C8, zero + +# mnscratch +# name +# CHECK-INST: csrrs t1, mnscratch, zero +# CHECK-ENC: encoding: [0x73,0x23,0x00,0x35] +# CHECK-WARN: warning: 'miselect' CSR is not available on the current subtarget. Instead 'mnscratch' CSR will be used. +# uimm12 +# CHECK-INST: csrrs t2, mnscratch, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x00,0x35] +# name +csrrs t1, mnscratch, zero +csrrs t1, miselect, zero +# uimm12 +csrrs t2, 0x350, zero + +# mnepc +# name +# CHECK-INST: csrrs t1, mnepc, zero +# CHECK-ENC: encoding: [0x73,0x23,0x10,0x35] +# CHECK-WARN: warning: 'mireg' CSR is not available on the current subtarget. Instead 'mnepc' CSR will be used. +# uimm12 +# CHECK-INST: csrrs t2, mnepc, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x10,0x35] +# name +csrrs t1, mnepc, zero +csrrs t1, mireg, zero +# uimm12 +csrrs t2, 0x351, zero + +# mncause +# name +# CHECK-INST: csrrs t1, mncause, zero +# CHECK-ENC: encoding: [0x73,0x23,0x20,0x35] +# uimm12 +# CHECK-INST: csrrs t2, mncause, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x20,0x35] +# name +csrrs t1, mncause, zero +# uimm12 +csrrs t2, 0x352, zero + +# mnstatus +# name +# CHECK-INST: csrrs t1, mnstatus, zero +# CHECK-ENC: encoding: [0x73,0x23,0x30,0x35] +# uimm12 +# CHECK-INST: csrrs t2, mnstatus, zero +# CHECK-ENC: encoding: [0xf3,0x23,0x30,0x35] +# name +csrrs t1, mnstatus, zero +# uimm12 +csrrs t2, 0x353, zero