[PATCH] D137517: [TargetParser] Generate the defs for RISCV CPUs using llvm-tblgen.

Wang Pengcheng via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 22 00:11:27 PST 2022


pcwang-thead added a comment.

In D137517#4012307 <https://reviews.llvm.org/D137517#4012307>, @craig.topper wrote:

> In D137517#4012298 <https://reviews.llvm.org/D137517#4012298>, @pcwang-thead wrote:
>
>> In D137517#4009175 <https://reviews.llvm.org/D137517#4009175>, @fpetrogalli wrote:
>>
>>> @pcwang-thead, I addressed some of your comments.
>>>
>>> The value of `EnumFeatures` is now computed dynamicaly from the
>>> `Features` field of the `Processor` class.
>>
>> Thanks! That sounds great to me!
>>
>>> As for generating `MArch` out of the `Features` field, @craig.topper
>>> pointed me at
>>> https://github.com/riscv-non-isa/riscv-toolchain-conventions/issues/11. From
>>> the reading of it, it seems that the alphabetical order is enough to
>>> build the string that carries `MArch`. Am I missing something?
>>
>> Currently, I think the alphabetical order is OK. If we relax the checking of arch string someday, there is no doubt that we should change the implementation here too.
>
> The currently accepted order isn’t alphabetical. The single letter extensions have a specific order. The z extensions are ordered by looking up the second letter in the single letter order. If we alphabetize here i don’t think it will be accepted by the frontend.

Oops, my mistake.

Here is my PoC to generate march from Features:

  diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td
  index d1d0356179f5..b2520f25bfea 100644
  --- a/llvm/lib/Target/RISCV/RISCV.td
  +++ b/llvm/lib/Target/RISCV/RISCV.td
  @@ -556,8 +556,8 @@ include "RISCVSchedSyntacoreSCR1.td"
   class RISCVProcessorModelPROC<string n,
                                 SchedMachineModel m,
                                 list<SubtargetFeature> f,
  -                              string default_march = "",
  -                              list<SubtargetFeature> tunef = []> :  ProcessorModel<n, m, f, tunef> {
  +                              list<SubtargetFeature> tunef = [],
  +                              string default_march = ""> :  ProcessorModel<n, m, f, tunef> {
     string DefaultMarch = default_march;
   }
  diff --git a/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
  index b216e82cef6c..eea31e6ddea8 100644
  --- a/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
  +++ b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
  @@ -13,17 +13,33 @@
   
   #include "TableGenBackends.h"
   #include "llvm/TableGen/Record.h"
  +#include "llvm/Support/RISCVISAInfo.h"
   
   using namespace llvm;
   
  -static std::string getEnumFeatures(const Record &Rec) {
  +static int getXLen(const Record &Rec) {
     std::vector<Record *> Features = Rec.getValueAsListOfDefs("Features");
     if (find_if(Features, [](const Record *R) {
           return R->getName() == "Feature64Bit";
         }) != Features.end())
  -    return "FK_64BIT";
  +    return 64;
   
  -  return "FK_NONE";
  +  return 32;
  +}
  +
  +static std::string getMArch(int XLen, const Record &Rec) {
  +  std::vector<Record *> Features = Rec.getValueAsListOfDefs("Features");
  +  std::vector<std::string> FeatureVector;
  +  // Convert Features to FeatureVector.
  +  for (auto *Feature : Features) {
  +    StringRef FeatureName = Feature->getValueAsString("Name");
  +    if (llvm::RISCVISAInfo::isSupportedExtensionFeature(FeatureName))
  +      FeatureVector.push_back(std::string("+") + FeatureName.str());
  +  }
  +  auto ISAInfo = llvm::RISCVISAInfo::parseFeatures(XLen, FeatureVector);
  +  if (!ISAInfo)
  +    report_fatal_error("Invalid features: ");
  +  return (*ISAInfo)->toString();
   }
   
   void llvm::EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
  @@ -39,11 +55,17 @@ void llvm::EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
     // Iterate on all definition records.
     for (const MapTy &Def : Map) {
       const Record &Rec = *(Def.second);
  -    if (Rec.isSubClassOf("RISCVProcessorModelPROC"))
  +    if (Rec.isSubClassOf("RISCVProcessorModelPROC")) {
  +      int XLen = getXLen(Rec);
  +      std::string EnumFeatures = XLen == 64 ? "FK_64BIT" : "FK_NONE";
  +      std::string MArch = Rec.getValueAsString("DefaultMarch").str();
  +      if (MArch == "")
  +        MArch = getMArch(XLen, Rec);
         OS << "PROC(" << Rec.getName() << ", "
  -         << "{\"" << Rec.getValueAsString("Name") << "\"},"
  -         << getEnumFeatures(Rec) << ", "
  -         << "{\"" << Rec.getValueAsString("DefaultMarch") << "\"})\n";
  +         << "{\"" << Rec.getValueAsString("Name") << "\"}," << EnumFeatures
  +         << ", "
  +         << "{\"" << MArch << "\"})\n";
  +    }
     }
     OS << "\n#undef PROC\n";
     OS << "\n";

The generated file would be like below (the march strings are tedious but I think that would be OK):

  #ifndef PROC
  #define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH)
  #endif
  
  PROC(INVALID, {"invalid"}, FK_INVALID, {""})
  PROC(GENERIC_RV32, {"generic-rv32"},FK_NONE, {"rv32i2p0"})
  PROC(GENERIC_RV64, {"generic-rv64"},FK_64BIT, {"rv64i2p0"})
  PROC(ROCKET_RV32, {"rocket-rv32"},FK_NONE, {"rv32i2p0"})
  PROC(ROCKET_RV64, {"rocket-rv64"},FK_64BIT, {"rv64i2p0"})
  PROC(SIFIVE_E20, {"sifive-e20"},FK_NONE, {"rv32i2p0_m2p0_c2p0"})
  PROC(SIFIVE_E21, {"sifive-e21"},FK_NONE, {"rv32i2p0_m2p0_a2p0_c2p0"})
  PROC(SIFIVE_E24, {"sifive-e24"},FK_NONE, {"rv32i2p0_m2p0_a2p0_f2p0_c2p0"})
  PROC(SIFIVE_E31, {"sifive-e31"},FK_NONE, {"rv32i2p0_m2p0_a2p0_c2p0"})
  PROC(SIFIVE_E34, {"sifive-e34"},FK_NONE, {"rv32i2p0_m2p0_a2p0_f2p0_c2p0"})
  PROC(SIFIVE_E76, {"sifive-e76"},FK_NONE, {"rv32i2p0_m2p0_a2p0_f2p0_c2p0"})
  PROC(SIFIVE_S21, {"sifive-s21"},FK_64BIT, {"rv64i2p0_m2p0_a2p0_c2p0"})
  PROC(SIFIVE_S51, {"sifive-s51"},FK_64BIT, {"rv64i2p0_m2p0_a2p0_c2p0"})
  PROC(SIFIVE_S54, {"sifive-s54"},FK_64BIT, {"rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"})
  PROC(SIFIVE_S76, {"sifive-s76"},FK_64BIT, {"rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"})
  PROC(SIFIVE_U54, {"sifive-u54"},FK_64BIT, {"rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"})
  PROC(SIFIVE_U74, {"sifive-u74"},FK_64BIT, {"rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"})
  PROC(SYNTACORE_SCR1_BASE, {"syntacore-scr1-base"},FK_NONE, {"rv32i2p0_c2p0"})
  PROC(SYNTACORE_SCR1_MAX, {"syntacore-scr1-max"},FK_NONE, {"rv32i2p0_m2p0_c2p0"})
  
  #undef PROC
  
  #ifndef TUNE_PROC
  #define TUNE_PROC(ENUM, NAME)
  #endif
  
  TUNE_PROC(GENERIC, "generic")
  TUNE_PROC(ROCKET, "rocket")
  TUNE_PROC(SIFIVE_7, "sifive-7-series")
  
  #undef TUNE_PROC

The key point is building `RISCVISAInfo` from feature vectors and using `RISCVISAInfo::toString()` to construct the march string. If there is no default march string, then we can generate it from CPU's features.

This will cause a cyclic dependency: tablengen->TargetParser->tablengen, so I move `RISCVISAInfo.cpp` back to `Support` component in D140529 <https://reviews.llvm.org/D140529>.

Is it OK with you? @craig.topper


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137517/new/

https://reviews.llvm.org/D137517



More information about the cfe-commits mailing list