1 //===- RISCVTargetDefEmitter.cpp - Generate lists of RISC-V CPUs ----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This tablegen backend emits the include file needed by RISCVTargetParser.cpp 10 // and RISCVISAInfo.cpp to parse the RISC-V CPUs and extensions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/DenseSet.h" 15 #include "llvm/Support/RISCVISAUtils.h" 16 #include "llvm/TableGen/Record.h" 17 #include "llvm/TableGen/TableGenBackend.h" 18 19 using namespace llvm; 20 21 static StringRef getExtensionName(const Record *R) { 22 StringRef Name = R->getValueAsString("Name"); 23 Name.consume_front("experimental-"); 24 return Name; 25 } 26 27 static void printExtensionTable(raw_ostream &OS, 28 const std::vector<Record *> &Extensions, 29 bool Experimental) { 30 OS << "static const RISCVSupportedExtension Supported"; 31 if (Experimental) 32 OS << "Experimental"; 33 OS << "Extensions[] = {\n"; 34 35 for (Record *R : Extensions) { 36 if (R->getValueAsBit("Experimental") != Experimental) 37 continue; 38 39 OS << " {\"" << getExtensionName(R) << "\", {" 40 << R->getValueAsInt("MajorVersion") << ", " 41 << R->getValueAsInt("MinorVersion") << "}},\n"; 42 } 43 44 OS << "};\n\n"; 45 } 46 47 static void emitRISCVExtensions(RecordKeeper &Records, raw_ostream &OS) { 48 OS << "#ifdef GET_SUPPORTED_EXTENSIONS\n"; 49 OS << "#undef GET_SUPPORTED_EXTENSIONS\n\n"; 50 51 std::vector<Record *> Extensions = 52 Records.getAllDerivedDefinitionsIfDefined("RISCVExtension"); 53 llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) { 54 return getExtensionName(Rec1) < getExtensionName(Rec2); 55 }); 56 57 if (!Extensions.empty()) { 58 printExtensionTable(OS, Extensions, /*Experimental=*/false); 59 printExtensionTable(OS, Extensions, /*Experimental=*/true); 60 } 61 62 OS << "#endif // GET_SUPPORTED_EXTENSIONS\n\n"; 63 64 OS << "#ifdef GET_IMPLIED_EXTENSIONS\n"; 65 OS << "#undef GET_IMPLIED_EXTENSIONS\n\n"; 66 67 if (!Extensions.empty()) { 68 OS << "\nstatic constexpr ImpliedExtsEntry ImpliedExts[] = {\n"; 69 for (Record *Ext : Extensions) { 70 auto ImpliesList = Ext->getValueAsListOfDefs("Implies"); 71 if (ImpliesList.empty()) 72 continue; 73 74 StringRef Name = getExtensionName(Ext); 75 76 for (auto *ImpliedExt : ImpliesList) { 77 if (!ImpliedExt->isSubClassOf("RISCVExtension")) 78 continue; 79 80 OS << " { {\"" << Name << "\"}, \"" << getExtensionName(ImpliedExt) 81 << "\"},\n"; 82 } 83 } 84 85 OS << "};\n\n"; 86 } 87 88 OS << "#endif // GET_IMPLIED_EXTENSIONS\n\n"; 89 } 90 91 // We can generate march string from target features as what has been described 92 // in RISC-V ISA specification (version 20191213) 'Chapter 27. ISA Extension 93 // Naming Conventions'. 94 // 95 // This is almost the same as RISCVFeatures::parseFeatureBits, except that we 96 // get feature name from feature records instead of feature bits. 97 static void printMArch(raw_ostream &OS, const std::vector<Record *> &Features) { 98 RISCVISAUtils::OrderedExtensionMap Extensions; 99 unsigned XLen = 0; 100 101 // Convert features to FeatureVector. 102 for (auto *Feature : Features) { 103 StringRef FeatureName = getExtensionName(Feature); 104 if (Feature->isSubClassOf("RISCVExtension")) { 105 unsigned Major = Feature->getValueAsInt("MajorVersion"); 106 unsigned Minor = Feature->getValueAsInt("MinorVersion"); 107 Extensions[FeatureName.str()] = {Major, Minor}; 108 } else if (FeatureName == "64bit") { 109 assert(XLen == 0 && "Already determined XLen"); 110 XLen = 64; 111 } else if (FeatureName == "32bit") { 112 assert(XLen == 0 && "Already determined XLen"); 113 XLen = 32; 114 } 115 } 116 117 assert(XLen != 0 && "Unable to determine XLen"); 118 119 OS << "rv" << XLen; 120 121 ListSeparator LS("_"); 122 for (auto const &Ext : Extensions) 123 OS << LS << Ext.first << Ext.second.Major << 'p' << Ext.second.Minor; 124 } 125 126 static void printProfileTable(raw_ostream &OS, 127 const std::vector<Record *> &Profiles, 128 bool Experimental) { 129 OS << "static constexpr RISCVProfile Supported"; 130 if (Experimental) 131 OS << "Experimental"; 132 OS << "Profiles[] = {\n"; 133 134 for (const Record *Rec : Profiles) { 135 if (Rec->getValueAsBit("Experimental") != Experimental) 136 continue; 137 138 StringRef Name = Rec->getValueAsString("Name"); 139 Name.consume_front("experimental-"); 140 OS.indent(4) << "{\"" << Name << "\",\""; 141 printMArch(OS, Rec->getValueAsListOfDefs("Implies")); 142 OS << "\"},\n"; 143 } 144 145 OS << "};\n\n"; 146 } 147 148 static void emitRISCVProfiles(RecordKeeper &Records, raw_ostream &OS) { 149 OS << "#ifdef GET_SUPPORTED_PROFILES\n"; 150 OS << "#undef GET_SUPPORTED_PROFILES\n\n"; 151 152 auto Profiles = Records.getAllDerivedDefinitionsIfDefined("RISCVProfile"); 153 154 if (!Profiles.empty()) { 155 printProfileTable(OS, Profiles, /*Experimental=*/false); 156 bool HasExperimentalProfiles = any_of(Profiles, [&](auto &Rec) { 157 return Rec->getValueAsBit("Experimental"); 158 }); 159 if (HasExperimentalProfiles) 160 printProfileTable(OS, Profiles, /*Experimental=*/true); 161 } 162 163 OS << "#endif // GET_SUPPORTED_PROFILES\n\n"; 164 } 165 166 static void emitRISCVProcs(RecordKeeper &RK, raw_ostream &OS) { 167 OS << "#ifndef PROC\n" 168 << "#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN" 169 << ", FAST_VECTOR_UNALIGN)\n" 170 << "#endif\n\n"; 171 172 // Iterate on all definition records. 173 for (const Record *Rec : 174 RK.getAllDerivedDefinitionsIfDefined("RISCVProcessorModel")) { 175 const std::vector<Record *> &Features = 176 Rec->getValueAsListOfDefs("Features"); 177 bool FastScalarUnalignedAccess = any_of(Features, [&](auto &Feature) { 178 return Feature->getValueAsString("Name") == "unaligned-scalar-mem"; 179 }); 180 181 bool FastVectorUnalignedAccess = any_of(Features, [&](auto &Feature) { 182 return Feature->getValueAsString("Name") == "unaligned-vector-mem"; 183 }); 184 185 OS << "PROC(" << Rec->getName() << ", {\"" << Rec->getValueAsString("Name") 186 << "\"}, {\""; 187 188 StringRef MArch = Rec->getValueAsString("DefaultMarch"); 189 190 // Compute MArch from features if we don't specify it. 191 if (MArch.empty()) 192 printMArch(OS, Features); 193 else 194 OS << MArch; 195 OS << "\"}, " << FastScalarUnalignedAccess << ", " 196 << FastVectorUnalignedAccess << ")\n"; 197 } 198 OS << "\n#undef PROC\n"; 199 OS << "\n"; 200 OS << "#ifndef TUNE_PROC\n" 201 << "#define TUNE_PROC(ENUM, NAME)\n" 202 << "#endif\n\n"; 203 204 for (const Record *Rec : 205 RK.getAllDerivedDefinitionsIfDefined("RISCVTuneProcessorModel")) { 206 OS << "TUNE_PROC(" << Rec->getName() << ", " 207 << "\"" << Rec->getValueAsString("Name") << "\")\n"; 208 } 209 210 OS << "\n#undef TUNE_PROC\n"; 211 } 212 213 static void emitRISCVExtensionBitmask(RecordKeeper &RK, raw_ostream &OS) { 214 215 std::vector<Record *> Extensions = 216 RK.getAllDerivedDefinitionsIfDefined("RISCVExtensionBitmask"); 217 llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) { 218 return getExtensionName(Rec1) < getExtensionName(Rec2); 219 }); 220 221 #ifndef NDEBUG 222 llvm::DenseSet<std::pair<uint64_t, uint64_t>> Seen; 223 #endif 224 225 OS << "#ifdef GET_RISCVExtensionBitmaskTable_IMPL\n"; 226 OS << "static const RISCVExtensionBitmask ExtensionBitmask[]={\n"; 227 for (const Record *Rec : Extensions) { 228 unsigned GroupIDVal = Rec->getValueAsInt("GroupID"); 229 unsigned BitPosVal = Rec->getValueAsInt("BitPos"); 230 231 StringRef ExtName = Rec->getValueAsString("Name"); 232 ExtName.consume_front("experimental-"); 233 234 #ifndef NDEBUG 235 assert(Seen.insert(std::make_pair(GroupIDVal, BitPosVal)).second && 236 "duplicated bitmask"); 237 #endif 238 239 OS << " {" 240 << "\"" << ExtName << "\"" 241 << ", " << GroupIDVal << ", " << BitPosVal << "ULL" 242 << "},\n"; 243 } 244 OS << "};\n"; 245 OS << "#endif\n"; 246 } 247 248 static void EmitRISCVTargetDef(RecordKeeper &RK, raw_ostream &OS) { 249 emitRISCVExtensions(RK, OS); 250 emitRISCVProfiles(RK, OS); 251 emitRISCVProcs(RK, OS); 252 emitRISCVExtensionBitmask(RK, OS); 253 } 254 255 static TableGen::Emitter::Opt X("gen-riscv-target-def", EmitRISCVTargetDef, 256 "Generate the list of CPUs and extensions for " 257 "RISC-V"); 258