1 //===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===// 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 subtarget enumerations. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "Basic/TargetFeaturesEmitter.h" 14 #include "Common/CodeGenHwModes.h" 15 #include "Common/CodeGenSchedule.h" 16 #include "Common/CodeGenTarget.h" 17 #include "Common/PredicateExpander.h" 18 #include "Common/Utils.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/ADT/SmallPtrSet.h" 21 #include "llvm/ADT/StringExtras.h" 22 #include "llvm/ADT/StringMap.h" 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/MC/MCInstrItineraries.h" 25 #include "llvm/MC/MCSchedule.h" 26 #include "llvm/Support/Debug.h" 27 #include "llvm/Support/Format.h" 28 #include "llvm/Support/raw_ostream.h" 29 #include "llvm/TableGen/Error.h" 30 #include "llvm/TableGen/Record.h" 31 #include "llvm/TableGen/StringToOffsetTable.h" 32 #include "llvm/TableGen/TableGenBackend.h" 33 #include <algorithm> 34 #include <cassert> 35 #include <cstdint> 36 #include <iterator> 37 #include <string> 38 #include <vector> 39 40 using namespace llvm; 41 42 #define DEBUG_TYPE "subtarget-emitter" 43 44 namespace { 45 46 class SubtargetEmitter : TargetFeaturesEmitter { 47 // Each processor has a SchedClassDesc table with an entry for each 48 // SchedClass. The SchedClassDesc table indexes into a global write resource 49 // table, write latency table, and read advance table. 50 struct SchedClassTables { 51 std::vector<std::vector<MCSchedClassDesc>> ProcSchedClasses; 52 std::vector<MCWriteProcResEntry> WriteProcResources; 53 std::vector<MCWriteLatencyEntry> WriteLatencies; 54 std::vector<std::string> WriterNames; 55 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 56 57 // Reserve an invalid entry at index 0 58 SchedClassTables() { 59 ProcSchedClasses.resize(1); 60 WriteProcResources.resize(1); 61 WriteLatencies.resize(1); 62 WriterNames.push_back("InvalidWrite"); 63 ReadAdvanceEntries.resize(1); 64 } 65 }; 66 67 struct LessWriteProcResources { 68 bool operator()(const MCWriteProcResEntry &LHS, 69 const MCWriteProcResEntry &RHS) { 70 return LHS.ProcResourceIdx < RHS.ProcResourceIdx; 71 } 72 }; 73 74 CodeGenTarget TGT; 75 CodeGenSchedModels &SchedModels; 76 77 void emitSubtargetInfoMacroCalls(raw_ostream &OS); 78 unsigned featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap); 79 unsigned cpuKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap); 80 unsigned cpuNames(raw_ostream &OS); 81 void formItineraryStageString(const std::string &Names, 82 const Record *ItinData, std::string &ItinString, 83 unsigned &NStages); 84 void formItineraryOperandCycleString(const Record *ItinData, 85 std::string &ItinString, 86 unsigned &NOperandCycles); 87 void formItineraryBypassString(const std::string &Names, 88 const Record *ItinData, 89 std::string &ItinString, 90 unsigned NOperandCycles); 91 void emitStageAndOperandCycleData( 92 raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists); 93 void emitItineraries(raw_ostream &OS, 94 ArrayRef<std::vector<InstrItinerary>> ProcItinLists); 95 unsigned emitRegisterFileTables(const CodeGenProcModel &ProcModel, 96 raw_ostream &OS); 97 void emitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, 98 raw_ostream &OS); 99 void emitExtraProcessorInfo(const CodeGenProcModel &ProcModel, 100 raw_ostream &OS); 101 void emitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name, 102 char Separator); 103 void emitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel, 104 raw_ostream &OS); 105 void emitProcessorResources(const CodeGenProcModel &ProcModel, 106 raw_ostream &OS); 107 const Record *findWriteResources(const CodeGenSchedRW &SchedWrite, 108 const CodeGenProcModel &ProcModel); 109 const Record *findReadAdvance(const CodeGenSchedRW &SchedRead, 110 const CodeGenProcModel &ProcModel); 111 void expandProcResources(ConstRecVec &PRVec, 112 std::vector<int64_t> &ReleaseAtCycles, 113 std::vector<int64_t> &AcquireAtCycles, 114 const CodeGenProcModel &ProcModel); 115 void genSchedClassTables(const CodeGenProcModel &ProcModel, 116 SchedClassTables &SchedTables); 117 void emitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); 118 void emitProcessorModels(raw_ostream &OS); 119 void emitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); 120 void emitSchedModelHelpersImpl(raw_ostream &OS, 121 bool OnlyExpandMCInstPredicates = false); 122 void emitGenMCSubtargetInfo(raw_ostream &OS); 123 void emitMcInstrAnalysisPredicateFunctions(raw_ostream &OS); 124 125 void emitSchedModel(raw_ostream &OS); 126 void emitGetMacroFusions(const std::string &ClassName, raw_ostream &OS); 127 void emitHwModeCheck(const std::string &ClassName, raw_ostream &OS); 128 void parseFeaturesFunction(raw_ostream &OS); 129 130 public: 131 SubtargetEmitter(const RecordKeeper &R) 132 : TargetFeaturesEmitter(R), TGT(R), SchedModels(TGT.getSchedModels()) {} 133 134 void run(raw_ostream &O) override; 135 }; 136 137 } // end anonymous namespace 138 139 /// Emit some information about the SubtargetFeature as calls to a macro so 140 /// that they can be used from C++. 141 void SubtargetEmitter::emitSubtargetInfoMacroCalls(raw_ostream &OS) { 142 OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n"; 143 144 std::vector<const Record *> FeatureList = 145 Records.getAllDerivedDefinitions("SubtargetFeature"); 146 llvm::sort(FeatureList, LessRecordFieldFieldName()); 147 148 for (const Record *Feature : FeatureList) { 149 const StringRef FieldName = Feature->getValueAsString("FieldName"); 150 const StringRef Value = Feature->getValueAsString("Value"); 151 152 // Only handle boolean features for now, excluding BitVectors and enums. 153 const bool IsBool = (Value == "false" || Value == "true") && 154 !StringRef(FieldName).contains('['); 155 if (!IsBool) 156 continue; 157 158 // Some features default to true, with values set to false if enabled. 159 const char *Default = Value == "false" ? "true" : "false"; 160 161 // Define the getter with lowercased first char: xxxYyy() { return XxxYyy; } 162 const std::string Getter = 163 FieldName.substr(0, 1).lower() + FieldName.substr(1).str(); 164 165 OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", " 166 << Getter << ")\n"; 167 } 168 OS << "#undef GET_SUBTARGETINFO_MACRO\n"; 169 OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n"; 170 171 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; 172 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; 173 174 if (Target == "AArch64") 175 OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n"; 176 } 177 178 // 179 // FeatureKeyValues - Emit data of all the subtarget features. Used by the 180 // command line. 181 // 182 unsigned SubtargetEmitter::featureKeyValues(raw_ostream &OS, 183 const FeatureMapTy &FeatureMap) { 184 std::vector<const Record *> FeatureList = 185 Records.getAllDerivedDefinitions("SubtargetFeature"); 186 187 // Remove features with empty name. 188 llvm::erase_if(FeatureList, [](const Record *Rec) { 189 return Rec->getValueAsString("Name").empty(); 190 }); 191 if (FeatureList.empty()) 192 return 0; 193 194 // Sort and check duplicate Feature name. 195 sortAndReportDuplicates(FeatureList, "Feature"); 196 197 // Begin feature table. 198 OS << "// Sorted (by key) array of values for CPU features.\n" 199 << "extern const llvm::SubtargetFeatureKV " << Target 200 << "FeatureKV[] = {\n"; 201 202 for (const Record *Feature : FeatureList) { 203 // Next feature 204 StringRef Name = Feature->getName(); 205 StringRef CommandLineName = Feature->getValueAsString("Name"); 206 StringRef Desc = Feature->getValueAsString("Desc"); 207 208 // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in 209 // } } 210 OS << " { " 211 << "\"" << CommandLineName << "\", " 212 << "\"" << Desc << "\", " << Target << "::" << Name << ", "; 213 214 ConstRecVec ImpliesList = Feature->getValueAsListOfDefs("Implies"); 215 216 printFeatureMask(OS, ImpliesList, FeatureMap); 217 218 OS << " },\n"; 219 } 220 221 // End feature table. 222 OS << "};\n"; 223 224 return FeatureList.size(); 225 } 226 227 unsigned SubtargetEmitter::cpuNames(raw_ostream &OS) { 228 // Begin processor name table. 229 OS << "// Sorted array of names of CPU subtypes, including aliases.\n" 230 << "extern const llvm::StringRef " << Target << "Names[] = {\n"; 231 232 std::vector<const Record *> ProcessorList = 233 Records.getAllDerivedDefinitions("Processor"); 234 235 std::vector<const Record *> ProcessorAliasList = 236 Records.getAllDerivedDefinitionsIfDefined("ProcessorAlias"); 237 238 SmallVector<StringRef> Names; 239 Names.reserve(ProcessorList.size() + ProcessorAliasList.size()); 240 241 for (const Record *Processor : ProcessorList) { 242 StringRef Name = Processor->getValueAsString("Name"); 243 Names.push_back(Name); 244 } 245 246 for (const Record *Rec : ProcessorAliasList) { 247 auto Name = Rec->getValueAsString("Name"); 248 Names.push_back(Name); 249 } 250 251 llvm::sort(Names); 252 llvm::interleave( 253 Names, OS, [&](StringRef Name) { OS << '"' << Name << '"'; }, ",\n"); 254 255 // End processor name table. 256 OS << "};\n"; 257 258 return Names.size(); 259 } 260 261 static void checkDuplicateCPUFeatures(StringRef CPUName, 262 ArrayRef<const Record *> Features, 263 ArrayRef<const Record *> TuneFeatures) { 264 // We have made sure each SubtargetFeature Record has a unique name, so we can 265 // simply use pointer sets here. 266 SmallPtrSet<const Record *, 8> FeatureSet, TuneFeatureSet; 267 for (const auto *FeatureRec : Features) { 268 if (!FeatureSet.insert(FeatureRec).second) 269 PrintWarning("Processor " + CPUName + " contains duplicate feature '" + 270 FeatureRec->getValueAsString("Name") + "'"); 271 } 272 273 for (const auto *TuneFeatureRec : TuneFeatures) { 274 if (!TuneFeatureSet.insert(TuneFeatureRec).second) 275 PrintWarning("Processor " + CPUName + 276 " contains duplicate tune feature '" + 277 TuneFeatureRec->getValueAsString("Name") + "'"); 278 if (FeatureSet.contains(TuneFeatureRec)) 279 PrintWarning("Processor " + CPUName + " has '" + 280 TuneFeatureRec->getValueAsString("Name") + 281 "' in both feature and tune feature sets"); 282 } 283 } 284 285 // 286 // CPUKeyValues - Emit data of all the subtarget processors. Used by command 287 // line. 288 // 289 unsigned SubtargetEmitter::cpuKeyValues(raw_ostream &OS, 290 const FeatureMapTy &FeatureMap) { 291 // Gather and sort processor information 292 std::vector<const Record *> ProcessorList = 293 Records.getAllDerivedDefinitions("Processor"); 294 llvm::sort(ProcessorList, LessRecordFieldName()); 295 296 // Note that unlike `FeatureKeyValues`, here we do not need to check for 297 // duplicate processors, since that is already done when the SubtargetEmitter 298 // constructor calls `getSchedModels` to build a `CodeGenSchedModels` object, 299 // which does the duplicate processor check. 300 301 // Begin processor table. 302 OS << "// Sorted (by key) array of values for CPU subtype.\n" 303 << "extern const llvm::SubtargetSubTypeKV " << Target 304 << "SubTypeKV[] = {\n"; 305 306 for (const Record *Processor : ProcessorList) { 307 StringRef Name = Processor->getValueAsString("Name"); 308 ConstRecVec FeatureList = Processor->getValueAsListOfDefs("Features"); 309 ConstRecVec TuneFeatureList = 310 Processor->getValueAsListOfDefs("TuneFeatures"); 311 312 // Warn the user if there are duplicate processor features or tune 313 // features. 314 checkDuplicateCPUFeatures(Name, FeatureList, TuneFeatureList); 315 316 // Emit as "{ "cpu", "description", 0, { f1 , f2 , ... fn } },". 317 OS << " { " 318 << "\"" << Name << "\", "; 319 320 printFeatureMask(OS, FeatureList, FeatureMap); 321 OS << ", "; 322 printFeatureMask(OS, TuneFeatureList, FeatureMap); 323 324 // Emit the scheduler model pointer. 325 const std::string &ProcModelName = 326 SchedModels.getModelForProc(Processor).ModelName; 327 OS << ", &" << ProcModelName << " },\n"; 328 } 329 330 // End processor table. 331 OS << "};\n"; 332 333 return ProcessorList.size(); 334 } 335 336 // 337 // FormItineraryStageString - Compose a string containing the stage 338 // data initialization for the specified itinerary. N is the number 339 // of stages. 340 // 341 void SubtargetEmitter::formItineraryStageString(const std::string &Name, 342 const Record *ItinData, 343 std::string &ItinString, 344 unsigned &NStages) { 345 // Get states list 346 ConstRecVec StageList = ItinData->getValueAsListOfDefs("Stages"); 347 348 // For each stage 349 unsigned N = NStages = StageList.size(); 350 for (unsigned I = 0; I < N;) { 351 // Next stage 352 const Record *Stage = StageList[I]; 353 354 // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind } 355 int Cycles = Stage->getValueAsInt("Cycles"); 356 ItinString += " { " + itostr(Cycles) + ", "; 357 358 // Get unit list 359 ConstRecVec UnitList = Stage->getValueAsListOfDefs("Units"); 360 361 // For each unit 362 for (unsigned J = 0, M = UnitList.size(); J < M;) { 363 // Add name and bitwise or 364 ItinString += Name + "FU::" + UnitList[J]->getName().str(); 365 if (++J < M) 366 ItinString += " | "; 367 } 368 369 int TimeInc = Stage->getValueAsInt("TimeInc"); 370 ItinString += ", " + itostr(TimeInc); 371 372 int Kind = Stage->getValueAsInt("Kind"); 373 ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind); 374 375 // Close off stage 376 ItinString += " }"; 377 if (++I < N) 378 ItinString += ", "; 379 } 380 } 381 382 // 383 // FormItineraryOperandCycleString - Compose a string containing the 384 // operand cycle initialization for the specified itinerary. N is the 385 // number of operands that has cycles specified. 386 // 387 void SubtargetEmitter::formItineraryOperandCycleString( 388 const Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) { 389 // Get operand cycle list 390 std::vector<int64_t> OperandCycleList = 391 ItinData->getValueAsListOfInts("OperandCycles"); 392 393 // For each operand cycle 394 NOperandCycles = OperandCycleList.size(); 395 ListSeparator LS; 396 for (int OCycle : OperandCycleList) { 397 // Next operand cycle 398 ItinString += LS; 399 ItinString += " " + itostr(OCycle); 400 } 401 } 402 403 void SubtargetEmitter::formItineraryBypassString(const std::string &Name, 404 const Record *ItinData, 405 std::string &ItinString, 406 unsigned NOperandCycles) { 407 ConstRecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses"); 408 unsigned N = BypassList.size(); 409 unsigned I = 0; 410 ListSeparator LS; 411 for (; I < N; ++I) { 412 ItinString += LS; 413 ItinString += Name + "Bypass::" + BypassList[I]->getName().str(); 414 } 415 for (; I < NOperandCycles; ++I) { 416 ItinString += LS; 417 ItinString += " 0"; 418 } 419 } 420 421 // 422 // EmitStageAndOperandCycleData - Generate unique itinerary stages and operand 423 // cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed 424 // by CodeGenSchedClass::Index. 425 // 426 void SubtargetEmitter::emitStageAndOperandCycleData( 427 raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) { 428 // Multiple processor models may share an itinerary record. Emit it once. 429 SmallPtrSet<const Record *, 8> ItinsDefSet; 430 431 // Emit functional units for all the itineraries. 432 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { 433 if (!ItinsDefSet.insert(ProcModel.ItinsDef).second) 434 continue; 435 436 ConstRecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); 437 if (FUs.empty()) 438 continue; 439 440 StringRef Name = ProcModel.ItinsDef->getName(); 441 OS << "\n// Functional units for \"" << Name << "\"\n" 442 << "namespace " << Name << "FU {\n"; 443 444 for (const auto &[Idx, FU] : enumerate(FUs)) 445 OS << " const InstrStage::FuncUnits " << FU->getName() << " = 1ULL << " 446 << Idx << ";\n"; 447 448 OS << "} // end namespace " << Name << "FU\n"; 449 450 ConstRecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); 451 if (BPs.empty()) 452 continue; 453 OS << "\n// Pipeline forwarding paths for itineraries \"" << Name << "\"\n" 454 << "namespace " << Name << "Bypass {\n"; 455 456 OS << " const unsigned NoBypass = 0;\n"; 457 for (const auto &[Idx, BP] : enumerate(BPs)) 458 OS << " const unsigned " << BP->getName() << " = 1 << " << Idx << ";\n"; 459 460 OS << "} // end namespace " << Name << "Bypass\n"; 461 } 462 463 // Begin stages table 464 std::string StageTable = 465 "\nextern const llvm::InstrStage " + Target + "Stages[] = {\n"; 466 StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n"; 467 468 // Begin operand cycle table 469 std::string OperandCycleTable = 470 "extern const unsigned " + Target + "OperandCycles[] = {\n"; 471 OperandCycleTable += " 0, // No itinerary\n"; 472 473 // Begin pipeline bypass table 474 std::string BypassTable = 475 "extern const unsigned " + Target + "ForwardingPaths[] = {\n"; 476 BypassTable += " 0, // No itinerary\n"; 477 478 // For each Itinerary across all processors, add a unique entry to the stages, 479 // operand cycles, and pipeline bypass tables. Then add the new Itinerary 480 // object with computed offsets to the ProcItinLists result. 481 unsigned StageCount = 1, OperandCycleCount = 1; 482 StringMap<unsigned> ItinStageMap, ItinOperandMap; 483 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { 484 // Add process itinerary to the list. 485 std::vector<InstrItinerary> &ItinList = ProcItinLists.emplace_back(); 486 487 // If this processor defines no itineraries, then leave the itinerary list 488 // empty. 489 if (!ProcModel.hasItineraries()) 490 continue; 491 492 StringRef Name = ProcModel.ItinsDef->getName(); 493 494 ItinList.resize(SchedModels.numInstrSchedClasses()); 495 assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); 496 497 for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size(); 498 SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { 499 500 // Next itinerary data 501 const Record *ItinData = ProcModel.ItinDefList[SchedClassIdx]; 502 503 // Get string and stage count 504 std::string ItinStageString; 505 unsigned NStages = 0; 506 if (ItinData) 507 formItineraryStageString(Name.str(), ItinData, ItinStageString, 508 NStages); 509 510 // Get string and operand cycle count 511 std::string ItinOperandCycleString; 512 unsigned NOperandCycles = 0; 513 std::string ItinBypassString; 514 if (ItinData) { 515 formItineraryOperandCycleString(ItinData, ItinOperandCycleString, 516 NOperandCycles); 517 518 formItineraryBypassString(Name.str(), ItinData, ItinBypassString, 519 NOperandCycles); 520 } 521 522 // Check to see if stage already exists and create if it doesn't 523 uint16_t FindStage = 0; 524 if (NStages > 0) { 525 FindStage = ItinStageMap[ItinStageString]; 526 if (FindStage == 0) { 527 // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices 528 StageTable += ItinStageString + ", // " + itostr(StageCount); 529 if (NStages > 1) 530 StageTable += "-" + itostr(StageCount + NStages - 1); 531 StageTable += "\n"; 532 // Record Itin class number. 533 ItinStageMap[ItinStageString] = FindStage = StageCount; 534 StageCount += NStages; 535 } 536 } 537 538 // Check to see if operand cycle already exists and create if it doesn't 539 uint16_t FindOperandCycle = 0; 540 if (NOperandCycles > 0) { 541 std::string ItinOperandString = 542 ItinOperandCycleString + ItinBypassString; 543 FindOperandCycle = ItinOperandMap[ItinOperandString]; 544 if (FindOperandCycle == 0) { 545 // Emit as cycle, // index 546 OperandCycleTable += ItinOperandCycleString + ", // "; 547 std::string OperandIdxComment = itostr(OperandCycleCount); 548 if (NOperandCycles > 1) 549 OperandIdxComment += 550 "-" + itostr(OperandCycleCount + NOperandCycles - 1); 551 OperandCycleTable += OperandIdxComment + "\n"; 552 // Record Itin class number. 553 ItinOperandMap[ItinOperandCycleString] = FindOperandCycle = 554 OperandCycleCount; 555 // Emit as bypass, // index 556 BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n"; 557 OperandCycleCount += NOperandCycles; 558 } 559 } 560 561 // Set up itinerary as location and location + stage count 562 int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; 563 InstrItinerary Intinerary = { 564 NumUOps, 565 FindStage, 566 uint16_t(FindStage + NStages), 567 FindOperandCycle, 568 uint16_t(FindOperandCycle + NOperandCycles), 569 }; 570 571 // Inject - empty slots will be 0, 0 572 ItinList[SchedClassIdx] = Intinerary; 573 } 574 } 575 576 // Closing stage 577 StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n"; 578 StageTable += "};\n"; 579 580 // Closing operand cycles 581 OperandCycleTable += " 0 // End operand cycles\n"; 582 OperandCycleTable += "};\n"; 583 584 BypassTable += " 0 // End bypass tables\n"; 585 BypassTable += "};\n"; 586 587 // Emit tables. 588 OS << StageTable; 589 OS << OperandCycleTable; 590 OS << BypassTable; 591 } 592 593 // 594 // EmitProcessorData - Generate data for processor itineraries that were 595 // computed during EmitStageAndOperandCycleData(). ProcItinLists lists all 596 // Itineraries for each processor. The Itinerary lists are indexed on 597 // CodeGenSchedClass::Index. 598 // 599 void SubtargetEmitter::emitItineraries( 600 raw_ostream &OS, ArrayRef<std::vector<InstrItinerary>> ProcItinLists) { 601 // Multiple processor models may share an itinerary record. Emit it once. 602 SmallPtrSet<const Record *, 8> ItinsDefSet; 603 604 for (const auto &[Proc, ItinList] : 605 zip_equal(SchedModels.procModels(), ProcItinLists)) { 606 const Record *ItinsDef = Proc.ItinsDef; 607 if (!ItinsDefSet.insert(ItinsDef).second) 608 continue; 609 610 // Empty itineraries aren't referenced anywhere in the tablegen output 611 // so don't emit them. 612 if (ItinList.empty()) 613 continue; 614 615 // Begin processor itinerary table 616 OS << "\n"; 617 OS << "static constexpr llvm::InstrItinerary " << ItinsDef->getName() 618 << "[] = {\n"; 619 620 ArrayRef<CodeGenSchedClass> ItinSchedClasses = 621 SchedModels.schedClasses().take_front(ItinList.size()); 622 623 // For each itinerary class in CodeGenSchedClass::Index order. 624 for (const auto &[Idx, Intinerary, SchedClass] : 625 enumerate(ItinList, ItinSchedClasses)) { 626 // Emit Itinerary in the form of 627 // { NumMicroOps, FirstStage, LastStage, FirstOperandCycle, 628 // LastOperandCycle } // index class name 629 OS << " { " << Intinerary.NumMicroOps << ", " << Intinerary.FirstStage 630 << ", " << Intinerary.LastStage << ", " << Intinerary.FirstOperandCycle 631 << ", " << Intinerary.LastOperandCycle << " }" << ", // " << Idx << " " 632 << SchedClass.Name << "\n"; 633 } 634 // End processor itinerary table 635 OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }" 636 "// end marker\n"; 637 OS << "};\n"; 638 } 639 } 640 641 // Emit either the value defined in the TableGen Record, or the default 642 // value defined in the C++ header. The Record is null if the processor does not 643 // define a model. 644 void SubtargetEmitter::emitProcessorProp(raw_ostream &OS, const Record *R, 645 StringRef Name, char Separator) { 646 OS << " "; 647 int V = R ? R->getValueAsInt(Name) : -1; 648 if (V >= 0) 649 OS << V << Separator << " // " << Name; 650 else 651 OS << "MCSchedModel::Default" << Name << Separator; 652 OS << '\n'; 653 } 654 655 void SubtargetEmitter::emitProcessorResourceSubUnits( 656 const CodeGenProcModel &ProcModel, raw_ostream &OS) { 657 OS << "\nstatic const unsigned " << ProcModel.ModelName 658 << "ProcResourceSubUnits[] = {\n" 659 << " 0, // Invalid\n"; 660 661 for (unsigned I = 0, E = ProcModel.ProcResourceDefs.size(); I < E; ++I) { 662 const Record *PRDef = ProcModel.ProcResourceDefs[I]; 663 if (!PRDef->isSubClassOf("ProcResGroup")) 664 continue; 665 for (const Record *RUDef : PRDef->getValueAsListOfDefs("Resources")) { 666 const Record *RU = 667 SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc()); 668 for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) { 669 OS << " " << ProcModel.getProcResourceIdx(RU) << ", "; 670 } 671 } 672 OS << " // " << PRDef->getName() << "\n"; 673 } 674 OS << "};\n"; 675 } 676 677 static void emitRetireControlUnitInfo(const CodeGenProcModel &ProcModel, 678 raw_ostream &OS) { 679 int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0; 680 if (const Record *RCU = ProcModel.RetireControlUnit) { 681 ReorderBufferSize = 682 std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize")); 683 MaxRetirePerCycle = 684 std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle")); 685 } 686 687 OS << ReorderBufferSize << ", // ReorderBufferSize\n "; 688 OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n "; 689 } 690 691 static void emitRegisterFileInfo(const CodeGenProcModel &ProcModel, 692 unsigned NumRegisterFiles, 693 unsigned NumCostEntries, raw_ostream &OS) { 694 if (NumRegisterFiles) 695 OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles); 696 else 697 OS << "nullptr,\n 0"; 698 699 OS << ", // Number of register files.\n "; 700 if (NumCostEntries) 701 OS << ProcModel.ModelName << "RegisterCosts,\n "; 702 else 703 OS << "nullptr,\n "; 704 OS << NumCostEntries << ", // Number of register cost entries.\n"; 705 } 706 707 unsigned 708 SubtargetEmitter::emitRegisterFileTables(const CodeGenProcModel &ProcModel, 709 raw_ostream &OS) { 710 if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) { 711 return RF.hasDefaultCosts(); 712 })) 713 return 0; 714 715 // Print the RegisterCost table first. 716 OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n"; 717 OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName 718 << "RegisterCosts" 719 << "[] = {\n"; 720 721 for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) { 722 // Skip register files with a default cost table. 723 if (RF.hasDefaultCosts()) 724 continue; 725 // Add entries to the cost table. 726 for (const CodeGenRegisterCost &RC : RF.Costs) { 727 OS << " { "; 728 const Record *Rec = RC.RCDef; 729 if (Rec->getValue("Namespace")) 730 OS << Rec->getValueAsString("Namespace") << "::"; 731 OS << Rec->getName() << "RegClassID, " << RC.Cost << ", " 732 << RC.AllowMoveElimination << "},\n"; 733 } 734 } 735 OS << "};\n"; 736 737 // Now generate a table with register file info. 738 OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, " 739 << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n"; 740 OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName 741 << "RegisterFiles" 742 << "[] = {\n" 743 << " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n"; 744 unsigned CostTblIndex = 0; 745 746 for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) { 747 OS << " { "; 748 OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", "; 749 unsigned NumCostEntries = RD.Costs.size(); 750 OS << NumCostEntries << ", " << CostTblIndex << ", " 751 << RD.MaxMovesEliminatedPerCycle << ", " 752 << RD.AllowZeroMoveEliminationOnly << "},\n"; 753 CostTblIndex += NumCostEntries; 754 } 755 OS << "};\n"; 756 757 return CostTblIndex; 758 } 759 760 void SubtargetEmitter::emitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, 761 raw_ostream &OS) { 762 unsigned QueueID = 0; 763 if (ProcModel.LoadQueue) { 764 const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor"); 765 QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(), 766 find(ProcModel.ProcResourceDefs, Queue)); 767 } 768 OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n"; 769 770 QueueID = 0; 771 if (ProcModel.StoreQueue) { 772 const Record *Queue = 773 ProcModel.StoreQueue->getValueAsDef("QueueDescriptor"); 774 QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(), 775 find(ProcModel.ProcResourceDefs, Queue)); 776 } 777 OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n"; 778 } 779 780 void SubtargetEmitter::emitExtraProcessorInfo(const CodeGenProcModel &ProcModel, 781 raw_ostream &OS) { 782 // Generate a table of register file descriptors (one entry per each user 783 // defined register file), and a table of register costs. 784 unsigned NumCostEntries = emitRegisterFileTables(ProcModel, OS); 785 786 // Now generate a table for the extra processor info. 787 OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName 788 << "ExtraInfo = {\n "; 789 790 // Add information related to the retire control unit. 791 emitRetireControlUnitInfo(ProcModel, OS); 792 793 // Add information related to the register files (i.e. where to find register 794 // file descriptors and register costs). 795 emitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), 796 NumCostEntries, OS); 797 798 // Add information about load/store queues. 799 emitLoadStoreQueueInfo(ProcModel, OS); 800 801 OS << "};\n"; 802 } 803 804 void SubtargetEmitter::emitProcessorResources(const CodeGenProcModel &ProcModel, 805 raw_ostream &OS) { 806 emitProcessorResourceSubUnits(ProcModel, OS); 807 808 OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n"; 809 OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName 810 << "ProcResources" 811 << "[] = {\n" 812 << " {\"InvalidUnit\", 0, 0, 0, 0},\n"; 813 814 unsigned SubUnitsOffset = 1; 815 for (unsigned I = 0, E = ProcModel.ProcResourceDefs.size(); I < E; ++I) { 816 const Record *PRDef = ProcModel.ProcResourceDefs[I]; 817 818 const Record *SuperDef = nullptr; 819 unsigned SuperIdx = 0; 820 unsigned NumUnits = 0; 821 const unsigned SubUnitsBeginOffset = SubUnitsOffset; 822 int BufferSize = PRDef->getValueAsInt("BufferSize"); 823 if (PRDef->isSubClassOf("ProcResGroup")) { 824 for (const Record *RU : PRDef->getValueAsListOfDefs("Resources")) { 825 NumUnits += RU->getValueAsInt("NumUnits"); 826 SubUnitsOffset += RU->getValueAsInt("NumUnits"); 827 } 828 } else { 829 // Find the SuperIdx 830 if (PRDef->getValueInit("Super")->isComplete()) { 831 SuperDef = SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), 832 ProcModel, PRDef->getLoc()); 833 SuperIdx = ProcModel.getProcResourceIdx(SuperDef); 834 } 835 NumUnits = PRDef->getValueAsInt("NumUnits"); 836 } 837 // Emit the ProcResourceDesc 838 OS << " {\"" << PRDef->getName() << "\", "; 839 if (PRDef->getName().size() < 15) 840 OS.indent(15 - PRDef->getName().size()); 841 OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", "; 842 if (SubUnitsBeginOffset != SubUnitsOffset) { 843 OS << ProcModel.ModelName << "ProcResourceSubUnits + " 844 << SubUnitsBeginOffset; 845 } else { 846 OS << "nullptr"; 847 } 848 OS << "}, // #" << I + 1; 849 if (SuperDef) 850 OS << ", Super=" << SuperDef->getName(); 851 OS << "\n"; 852 } 853 OS << "};\n"; 854 } 855 856 // Find the WriteRes Record that defines processor resources for this 857 // SchedWrite. 858 const Record * 859 SubtargetEmitter::findWriteResources(const CodeGenSchedRW &SchedWrite, 860 const CodeGenProcModel &ProcModel) { 861 862 // Check if the SchedWrite is already subtarget-specific and directly 863 // specifies a set of processor resources. 864 if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) 865 return SchedWrite.TheDef; 866 867 const Record *AliasDef = nullptr; 868 for (const Record *A : SchedWrite.Aliases) { 869 const CodeGenSchedRW &AliasRW = 870 SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); 871 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 872 const Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 873 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 874 continue; 875 } 876 if (AliasDef) 877 PrintFatalError(AliasRW.TheDef->getLoc(), 878 "Multiple aliases " 879 "defined for processor " + 880 ProcModel.ModelName + 881 " Ensure only one SchedAlias exists per RW."); 882 AliasDef = AliasRW.TheDef; 883 } 884 if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) 885 return AliasDef; 886 887 // Check this processor's list of write resources. 888 const Record *ResDef = nullptr; 889 890 auto I = ProcModel.WriteResMap.find(SchedWrite.TheDef); 891 if (I != ProcModel.WriteResMap.end()) 892 ResDef = I->second; 893 894 if (AliasDef) { 895 I = ProcModel.WriteResMap.find(AliasDef); 896 if (I != ProcModel.WriteResMap.end()) { 897 if (ResDef) 898 PrintFatalError(I->second->getLoc(), 899 "Resources are defined for both SchedWrite and its " 900 "alias on processor " + 901 ProcModel.ModelName); 902 ResDef = I->second; 903 } 904 } 905 906 // TODO: If ProcModel has a base model (previous generation processor), 907 // then call FindWriteResources recursively with that model here. 908 if (!ResDef) { 909 PrintFatalError(ProcModel.ModelDef->getLoc(), 910 Twine("Processor does not define resources for ") + 911 SchedWrite.TheDef->getName()); 912 } 913 return ResDef; 914 } 915 916 /// Find the ReadAdvance record for the given SchedRead on this processor or 917 /// return NULL. 918 const Record * 919 SubtargetEmitter::findReadAdvance(const CodeGenSchedRW &SchedRead, 920 const CodeGenProcModel &ProcModel) { 921 // Check for SchedReads that directly specify a ReadAdvance. 922 if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) 923 return SchedRead.TheDef; 924 925 // Check this processor's list of aliases for SchedRead. 926 const Record *AliasDef = nullptr; 927 for (const Record *A : SchedRead.Aliases) { 928 const CodeGenSchedRW &AliasRW = 929 SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); 930 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 931 const Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 932 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 933 continue; 934 } 935 if (AliasDef) 936 PrintFatalError(AliasRW.TheDef->getLoc(), 937 "Multiple aliases " 938 "defined for processor " + 939 ProcModel.ModelName + 940 " Ensure only one SchedAlias exists per RW."); 941 AliasDef = AliasRW.TheDef; 942 } 943 if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) 944 return AliasDef; 945 946 // Check this processor's ReadAdvanceList. 947 const Record *ResDef = nullptr; 948 949 auto I = ProcModel.ReadAdvanceMap.find(SchedRead.TheDef); 950 if (I != ProcModel.ReadAdvanceMap.end()) 951 ResDef = I->second; 952 953 if (AliasDef) { 954 I = ProcModel.ReadAdvanceMap.find(AliasDef); 955 if (I != ProcModel.ReadAdvanceMap.end()) { 956 if (ResDef) 957 PrintFatalError( 958 I->second->getLoc(), 959 "Resources are defined for both SchedRead and its alias on " 960 "processor " + 961 ProcModel.ModelName); 962 ResDef = I->second; 963 } 964 } 965 966 // TODO: If ProcModel has a base model (previous generation processor), 967 // then call FindReadAdvance recursively with that model here. 968 if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { 969 PrintFatalError(ProcModel.ModelDef->getLoc(), 970 Twine("Processor does not define resources for ") + 971 SchedRead.TheDef->getName()); 972 } 973 return ResDef; 974 } 975 976 // Expand an explicit list of processor resources into a full list of implied 977 // resource groups and super resources that cover them. 978 void SubtargetEmitter::expandProcResources( 979 ConstRecVec &PRVec, std::vector<int64_t> &ReleaseAtCycles, 980 std::vector<int64_t> &AcquireAtCycles, const CodeGenProcModel &PM) { 981 assert(PRVec.size() == ReleaseAtCycles.size() && "failed precondition"); 982 for (unsigned I = 0, E = PRVec.size(); I != E; ++I) { 983 const Record *PRDef = PRVec[I]; 984 ConstRecVec SubResources; 985 if (PRDef->isSubClassOf("ProcResGroup")) { 986 SubResources = PRDef->getValueAsListOfDefs("Resources"); 987 } else { 988 SubResources.push_back(PRDef); 989 PRDef = SchedModels.findProcResUnits(PRDef, PM, PRDef->getLoc()); 990 for (const Record *SubDef = PRDef; 991 SubDef->getValueInit("Super")->isComplete();) { 992 if (SubDef->isSubClassOf("ProcResGroup")) { 993 // Disallow this for simplicitly. 994 PrintFatalError(SubDef->getLoc(), "Processor resource group " 995 " cannot be a super resources."); 996 } 997 const Record *SuperDef = SchedModels.findProcResUnits( 998 SubDef->getValueAsDef("Super"), PM, SubDef->getLoc()); 999 PRVec.push_back(SuperDef); 1000 ReleaseAtCycles.push_back(ReleaseAtCycles[I]); 1001 AcquireAtCycles.push_back(AcquireAtCycles[I]); 1002 SubDef = SuperDef; 1003 } 1004 } 1005 for (const Record *PR : PM.ProcResourceDefs) { 1006 if (PR == PRDef || !PR->isSubClassOf("ProcResGroup")) 1007 continue; 1008 ConstRecVec SuperResources = PR->getValueAsListOfDefs("Resources"); 1009 bool AllContained = 1010 all_of(SubResources, [SuperResources](const Record *SubResource) { 1011 return is_contained(SuperResources, SubResource); 1012 }); 1013 if (AllContained) { 1014 PRVec.push_back(PR); 1015 ReleaseAtCycles.push_back(ReleaseAtCycles[I]); 1016 AcquireAtCycles.push_back(AcquireAtCycles[I]); 1017 } 1018 } 1019 } 1020 } 1021 1022 // Generate the SchedClass table for this processor and update global 1023 // tables. Must be called for each processor in order. 1024 void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel, 1025 SchedClassTables &SchedTables) { 1026 std::vector<MCSchedClassDesc> &SCTab = 1027 SchedTables.ProcSchedClasses.emplace_back(); 1028 if (!ProcModel.hasInstrSchedModel()) 1029 return; 1030 1031 LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n"); 1032 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { 1033 LLVM_DEBUG(SC.dump(&SchedModels)); 1034 1035 MCSchedClassDesc &SCDesc = SCTab.emplace_back(); 1036 // SCDesc.Name is guarded by NDEBUG 1037 SCDesc.NumMicroOps = 0; 1038 SCDesc.BeginGroup = false; 1039 SCDesc.EndGroup = false; 1040 SCDesc.RetireOOO = false; 1041 SCDesc.WriteProcResIdx = 0; 1042 SCDesc.WriteLatencyIdx = 0; 1043 SCDesc.ReadAdvanceIdx = 0; 1044 1045 // A Variant SchedClass has no resources of its own. 1046 bool HasVariants = false; 1047 for (const CodeGenSchedTransition &CGT : SC.Transitions) { 1048 if (CGT.ProcIndex == ProcModel.Index) { 1049 HasVariants = true; 1050 break; 1051 } 1052 } 1053 if (HasVariants) { 1054 SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; 1055 continue; 1056 } 1057 1058 // Determine if the SchedClass is actually reachable on this processor. If 1059 // not don't try to locate the processor resources, it will fail. 1060 // If ProcIndices contains 0, this class applies to all processors. 1061 assert(!SC.ProcIndices.empty() && "expect at least one procidx"); 1062 if (SC.ProcIndices[0] != 0) { 1063 if (!is_contained(SC.ProcIndices, ProcModel.Index)) 1064 continue; 1065 } 1066 IdxVec Writes = SC.Writes; 1067 IdxVec Reads = SC.Reads; 1068 if (!SC.InstRWs.empty()) { 1069 // This class has a default ReadWrite list which can be overridden by 1070 // InstRW definitions. 1071 const Record *RWDef = nullptr; 1072 for (const Record *RW : SC.InstRWs) { 1073 const Record *RWModelDef = RW->getValueAsDef("SchedModel"); 1074 if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { 1075 RWDef = RW; 1076 break; 1077 } 1078 } 1079 if (RWDef) { 1080 Writes.clear(); 1081 Reads.clear(); 1082 SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), 1083 Writes, Reads); 1084 } 1085 } 1086 if (Writes.empty()) { 1087 // Check this processor's itinerary class resources. 1088 for (const Record *I : ProcModel.ItinRWDefs) { 1089 ConstRecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses"); 1090 if (is_contained(Matched, SC.ItinClassDef)) { 1091 SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"), 1092 Writes, Reads); 1093 break; 1094 } 1095 } 1096 if (Writes.empty()) { 1097 LLVM_DEBUG(dbgs() << ProcModel.ModelName 1098 << " does not have resources for class " << SC.Name 1099 << '\n'); 1100 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 1101 } 1102 } 1103 // Sum resources across all operand writes. 1104 std::vector<MCWriteProcResEntry> WriteProcResources; 1105 std::vector<MCWriteLatencyEntry> WriteLatencies; 1106 std::vector<std::string> WriterNames; 1107 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 1108 for (unsigned W : Writes) { 1109 IdxVec WriteSeq; 1110 SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, ProcModel); 1111 1112 // For each operand, create a latency entry. 1113 MCWriteLatencyEntry WLEntry; 1114 WLEntry.Cycles = 0; 1115 unsigned WriteID = WriteSeq.back(); 1116 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); 1117 // If this Write is not referenced by a ReadAdvance, don't distinguish it 1118 // from other WriteLatency entries. 1119 if (!ProcModel.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef)) 1120 WriteID = 0; 1121 WLEntry.WriteResourceID = WriteID; 1122 1123 for (unsigned WS : WriteSeq) { 1124 const Record *WriteRes = 1125 findWriteResources(SchedModels.getSchedWrite(WS), ProcModel); 1126 1127 // Mark the parent class as invalid for unsupported write types. 1128 if (WriteRes->getValueAsBit("Unsupported")) { 1129 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 1130 break; 1131 } 1132 WLEntry.Cycles += WriteRes->getValueAsInt("Latency"); 1133 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps"); 1134 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup"); 1135 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup"); 1136 SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue"); 1137 SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue"); 1138 SCDesc.RetireOOO |= WriteRes->getValueAsBit("RetireOOO"); 1139 1140 // Create an entry for each ProcResource listed in WriteRes. 1141 ConstRecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); 1142 std::vector<int64_t> ReleaseAtCycles = 1143 WriteRes->getValueAsListOfInts("ReleaseAtCycles"); 1144 1145 std::vector<int64_t> AcquireAtCycles = 1146 WriteRes->getValueAsListOfInts("AcquireAtCycles"); 1147 1148 // Check consistency of the two vectors carrying the start and 1149 // stop cycles of the resources. 1150 if (!ReleaseAtCycles.empty() && 1151 ReleaseAtCycles.size() != PRVec.size()) { 1152 // If ReleaseAtCycles is provided, check consistency. 1153 PrintFatalError( 1154 WriteRes->getLoc(), 1155 Twine("Inconsistent release at cycles: size(ReleaseAtCycles) != " 1156 "size(ProcResources): ") 1157 .concat(Twine(PRVec.size())) 1158 .concat(" vs ") 1159 .concat(Twine(ReleaseAtCycles.size()))); 1160 } 1161 1162 if (!AcquireAtCycles.empty() && 1163 AcquireAtCycles.size() != PRVec.size()) { 1164 PrintFatalError( 1165 WriteRes->getLoc(), 1166 Twine("Inconsistent resource cycles: size(AcquireAtCycles) != " 1167 "size(ProcResources): ") 1168 .concat(Twine(AcquireAtCycles.size())) 1169 .concat(" vs ") 1170 .concat(Twine(PRVec.size()))); 1171 } 1172 1173 if (ReleaseAtCycles.empty()) { 1174 // If ReleaseAtCycles is not provided, default to one cycle 1175 // per resource. 1176 ReleaseAtCycles.resize(PRVec.size(), 1); 1177 } 1178 1179 if (AcquireAtCycles.empty()) { 1180 // If AcquireAtCycles is not provided, reserve the resource 1181 // starting from cycle 0. 1182 AcquireAtCycles.resize(PRVec.size(), 0); 1183 } 1184 1185 assert(AcquireAtCycles.size() == ReleaseAtCycles.size()); 1186 1187 expandProcResources(PRVec, ReleaseAtCycles, AcquireAtCycles, ProcModel); 1188 assert(AcquireAtCycles.size() == ReleaseAtCycles.size()); 1189 1190 for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd; 1191 ++PRIdx) { 1192 MCWriteProcResEntry WPREntry; 1193 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); 1194 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); 1195 WPREntry.ReleaseAtCycle = ReleaseAtCycles[PRIdx]; 1196 WPREntry.AcquireAtCycle = AcquireAtCycles[PRIdx]; 1197 if (AcquireAtCycles[PRIdx] > ReleaseAtCycles[PRIdx]) { 1198 PrintFatalError( 1199 WriteRes->getLoc(), 1200 Twine("Inconsistent resource cycles: AcquireAtCycles " 1201 "<= ReleaseAtCycles must hold.")); 1202 } 1203 if (AcquireAtCycles[PRIdx] < 0) { 1204 PrintFatalError(WriteRes->getLoc(), 1205 Twine("Invalid value: AcquireAtCycle " 1206 "must be a non-negative value.")); 1207 } 1208 // If this resource is already used in this sequence, add the current 1209 // entry's cycles so that the same resource appears to be used 1210 // serially, rather than multiple parallel uses. This is important for 1211 // in-order machine where the resource consumption is a hazard. 1212 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); 1213 for (; WPRIdx != WPREnd; ++WPRIdx) { 1214 if (WriteProcResources[WPRIdx].ProcResourceIdx == 1215 WPREntry.ProcResourceIdx) { 1216 // TODO: multiple use of the same resources would 1217 // require either 1. thinking of how to handle multiple 1218 // intervals for the same resource in 1219 // `<Target>WriteProcResTable` (see 1220 // `SubtargetEmitter::EmitSchedClassTables`), or 1221 // 2. thinking how to merge multiple intervals into a 1222 // single interval. 1223 assert(WPREntry.AcquireAtCycle == 0 && 1224 "multiple use ofthe same resource is not yet handled"); 1225 WriteProcResources[WPRIdx].ReleaseAtCycle += 1226 WPREntry.ReleaseAtCycle; 1227 break; 1228 } 1229 } 1230 if (WPRIdx == WPREnd) 1231 WriteProcResources.push_back(WPREntry); 1232 } 1233 } 1234 WriteLatencies.push_back(WLEntry); 1235 } 1236 // Create an entry for each operand Read in this SchedClass. 1237 // Entries must be sorted first by UseIdx then by WriteResourceID. 1238 for (unsigned UseIdx = 0, EndIdx = Reads.size(); UseIdx != EndIdx; 1239 ++UseIdx) { 1240 const Record *ReadAdvance = 1241 findReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); 1242 if (!ReadAdvance) 1243 continue; 1244 1245 // Mark the parent class as invalid for unsupported write types. 1246 if (ReadAdvance->getValueAsBit("Unsupported")) { 1247 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 1248 break; 1249 } 1250 ConstRecVec ValidWrites = 1251 ReadAdvance->getValueAsListOfDefs("ValidWrites"); 1252 std::vector<int64_t> CycleTunables = 1253 ReadAdvance->getValueAsListOfInts("CycleTunables"); 1254 std::vector<std::pair<unsigned, int>> WriteIDs; 1255 assert(CycleTunables.size() <= ValidWrites.size() && "Bad ReadAdvance"); 1256 CycleTunables.resize(ValidWrites.size(), 0); 1257 if (ValidWrites.empty()) 1258 WriteIDs.emplace_back(0, 0); 1259 else { 1260 for (const auto [VW, CT] : zip_equal(ValidWrites, CycleTunables)) { 1261 unsigned WriteID = SchedModels.getSchedRWIdx(VW, /*IsRead=*/false); 1262 assert(WriteID != 0 && 1263 "Expected a valid SchedRW in the list of ValidWrites"); 1264 WriteIDs.emplace_back(WriteID, CT); 1265 } 1266 } 1267 llvm::sort(WriteIDs); 1268 for (const auto &[W, T] : WriteIDs) { 1269 MCReadAdvanceEntry RAEntry; 1270 RAEntry.UseIdx = UseIdx; 1271 RAEntry.WriteResourceID = W; 1272 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles") + T; 1273 ReadAdvanceEntries.push_back(RAEntry); 1274 } 1275 } 1276 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 1277 WriteProcResources.clear(); 1278 WriteLatencies.clear(); 1279 ReadAdvanceEntries.clear(); 1280 } 1281 // Add the information for this SchedClass to the global tables using basic 1282 // compression. 1283 // 1284 // WritePrecRes entries are sorted by ProcResIdx. 1285 llvm::sort(WriteProcResources, LessWriteProcResources()); 1286 1287 SCDesc.NumWriteProcResEntries = WriteProcResources.size(); 1288 std::vector<MCWriteProcResEntry>::iterator WPRPos = 1289 std::search(SchedTables.WriteProcResources.begin(), 1290 SchedTables.WriteProcResources.end(), 1291 WriteProcResources.begin(), WriteProcResources.end()); 1292 if (WPRPos != SchedTables.WriteProcResources.end()) 1293 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin(); 1294 else { 1295 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size(); 1296 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(), 1297 WriteProcResources.end()); 1298 } 1299 // Latency entries must remain in operand order. 1300 SCDesc.NumWriteLatencyEntries = WriteLatencies.size(); 1301 std::vector<MCWriteLatencyEntry>::iterator WLPos = std::search( 1302 SchedTables.WriteLatencies.begin(), SchedTables.WriteLatencies.end(), 1303 WriteLatencies.begin(), WriteLatencies.end()); 1304 if (WLPos != SchedTables.WriteLatencies.end()) { 1305 unsigned Idx = WLPos - SchedTables.WriteLatencies.begin(); 1306 SCDesc.WriteLatencyIdx = Idx; 1307 for (unsigned I = 0, E = WriteLatencies.size(); I < E; ++I) 1308 if (SchedTables.WriterNames[Idx + I].find(WriterNames[I]) == 1309 std::string::npos) { 1310 SchedTables.WriterNames[Idx + I] += "_" + WriterNames[I]; 1311 } 1312 } else { 1313 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); 1314 llvm::append_range(SchedTables.WriteLatencies, WriteLatencies); 1315 llvm::append_range(SchedTables.WriterNames, WriterNames); 1316 } 1317 // ReadAdvanceEntries must remain in operand order. 1318 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); 1319 std::vector<MCReadAdvanceEntry>::iterator RAPos = 1320 std::search(SchedTables.ReadAdvanceEntries.begin(), 1321 SchedTables.ReadAdvanceEntries.end(), 1322 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end()); 1323 if (RAPos != SchedTables.ReadAdvanceEntries.end()) 1324 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); 1325 else { 1326 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); 1327 llvm::append_range(SchedTables.ReadAdvanceEntries, ReadAdvanceEntries); 1328 } 1329 } 1330 } 1331 1332 // Emit SchedClass tables for all processors and associated global tables. 1333 void SubtargetEmitter::emitSchedClassTables(SchedClassTables &SchedTables, 1334 raw_ostream &OS) { 1335 // Emit global WriteProcResTable. 1336 OS << "\n// {ProcResourceIdx, ReleaseAtCycle, AcquireAtCycle}\n" 1337 << "extern const llvm::MCWriteProcResEntry " << Target 1338 << "WriteProcResTable[] = {\n" 1339 << " { 0, 0, 0 }, // Invalid\n"; 1340 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); 1341 WPRIdx != WPREnd; ++WPRIdx) { 1342 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; 1343 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " 1344 << format("%2d", WPREntry.ReleaseAtCycle) << ", " 1345 << format("%2d", WPREntry.AcquireAtCycle) << "}"; 1346 if (WPRIdx + 1 < WPREnd) 1347 OS << ','; 1348 OS << " // #" << WPRIdx << '\n'; 1349 } 1350 OS << "}; // " << Target << "WriteProcResTable\n"; 1351 1352 // Emit global WriteLatencyTable. 1353 OS << "\n// {Cycles, WriteResourceID}\n" 1354 << "extern const llvm::MCWriteLatencyEntry " << Target 1355 << "WriteLatencyTable[] = {\n" 1356 << " { 0, 0}, // Invalid\n"; 1357 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); 1358 WLIdx != WLEnd; ++WLIdx) { 1359 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; 1360 OS << " {" << format("%2d", WLEntry.Cycles) << ", " 1361 << format("%2d", WLEntry.WriteResourceID) << "}"; 1362 if (WLIdx + 1 < WLEnd) 1363 OS << ','; 1364 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; 1365 } 1366 OS << "}; // " << Target << "WriteLatencyTable\n"; 1367 1368 // Emit global ReadAdvanceTable. 1369 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" 1370 << "extern const llvm::MCReadAdvanceEntry " << Target 1371 << "ReadAdvanceTable[] = {\n" 1372 << " {0, 0, 0}, // Invalid\n"; 1373 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); 1374 RAIdx != RAEnd; ++RAIdx) { 1375 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; 1376 OS << " {" << RAEntry.UseIdx << ", " 1377 << format("%2d", RAEntry.WriteResourceID) << ", " 1378 << format("%2d", RAEntry.Cycles) << "}"; 1379 if (RAIdx + 1 < RAEnd) 1380 OS << ','; 1381 OS << " // #" << RAIdx << '\n'; 1382 } 1383 OS << "}; // " << Target << "ReadAdvanceTable\n"; 1384 1385 // Pool all SchedClass names in a string table. 1386 StringToOffsetTable StrTab; 1387 unsigned InvalidNameOff = StrTab.GetOrAddStringOffset("InvalidSchedClass"); 1388 1389 // Emit a SchedClass table for each processor. 1390 for (const auto &[Idx, Proc] : enumerate(SchedModels.procModels())) { 1391 if (!Proc.hasInstrSchedModel()) 1392 continue; 1393 1394 std::vector<MCSchedClassDesc> &SCTab = 1395 SchedTables.ProcSchedClasses[1 + Idx]; 1396 1397 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO," 1398 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; 1399 OS << "static const llvm::MCSchedClassDesc " << Proc.ModelName 1400 << "SchedClasses[] = {\n"; 1401 1402 // The first class is always invalid. We no way to distinguish it except by 1403 // name and position. 1404 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" && 1405 "invalid class not first"); 1406 OS << " {DBGFIELD(" << InvalidNameOff << ") " 1407 << MCSchedClassDesc::InvalidNumMicroOps 1408 << ", false, false, false, 0, 0, 0, 0, 0, 0},\n"; 1409 1410 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { 1411 MCSchedClassDesc &MCDesc = SCTab[SCIdx]; 1412 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); 1413 unsigned NameOff = StrTab.GetOrAddStringOffset(SchedClass.Name); 1414 OS << " {DBGFIELD(/*" << SchedClass.Name << "*/ " << NameOff << ") "; 1415 if (SchedClass.Name.size() < 18) 1416 OS.indent(18 - SchedClass.Name.size()); 1417 OS << MCDesc.NumMicroOps << ", " << (MCDesc.BeginGroup ? "true" : "false") 1418 << ", " << (MCDesc.EndGroup ? "true" : "false") << ", " 1419 << (MCDesc.RetireOOO ? "true" : "false") << ", " 1420 << format("%2d", MCDesc.WriteProcResIdx) << ", " 1421 << MCDesc.NumWriteProcResEntries << ", " 1422 << format("%2d", MCDesc.WriteLatencyIdx) << ", " 1423 << MCDesc.NumWriteLatencyEntries << ", " 1424 << format("%2d", MCDesc.ReadAdvanceIdx) << ", " 1425 << MCDesc.NumReadAdvanceEntries << "}, // #" << SCIdx << '\n'; 1426 } 1427 OS << "}; // " << Proc.ModelName << "SchedClasses\n"; 1428 } 1429 1430 StrTab.EmitStringTableDef(OS, Target + "SchedClassNames"); 1431 } 1432 1433 void SubtargetEmitter::emitProcessorModels(raw_ostream &OS) { 1434 // For each processor model. 1435 for (const CodeGenProcModel &PM : SchedModels.procModels()) { 1436 // Emit extra processor info if available. 1437 if (PM.hasExtraProcessorInfo()) 1438 emitExtraProcessorInfo(PM, OS); 1439 // Emit processor resource table. 1440 if (PM.hasInstrSchedModel()) 1441 emitProcessorResources(PM, OS); 1442 else if (!PM.ProcResourceDefs.empty()) 1443 PrintFatalError(PM.ModelDef->getLoc(), 1444 "SchedMachineModel defines " 1445 "ProcResources without defining WriteRes SchedWriteRes"); 1446 1447 // Begin processor itinerary properties 1448 OS << "\n"; 1449 OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n"; 1450 emitProcessorProp(OS, PM.ModelDef, "IssueWidth", ','); 1451 emitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ','); 1452 emitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ','); 1453 emitProcessorProp(OS, PM.ModelDef, "LoadLatency", ','); 1454 emitProcessorProp(OS, PM.ModelDef, "HighLatency", ','); 1455 emitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ','); 1456 1457 bool PostRAScheduler = 1458 (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false); 1459 1460 OS << " " << (PostRAScheduler ? "true" : "false") << ", // " 1461 << "PostRAScheduler\n"; 1462 1463 bool CompleteModel = 1464 (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false); 1465 1466 OS << " " << (CompleteModel ? "true" : "false") << ", // " 1467 << "CompleteModel\n"; 1468 1469 bool EnableIntervals = 1470 (PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false); 1471 1472 OS << " " << (EnableIntervals ? "true" : "false") << ", // " 1473 << "EnableIntervals\n"; 1474 1475 OS << " " << PM.Index << ", // Processor ID\n"; 1476 if (PM.hasInstrSchedModel()) 1477 OS << " " << PM.ModelName << "ProcResources" << ",\n" 1478 << " " << PM.ModelName << "SchedClasses" << ",\n" 1479 << " " << PM.ProcResourceDefs.size() + 1 << ",\n" 1480 << " " << SchedModels.schedClasses().size() << ",\n"; 1481 else 1482 OS << " nullptr, nullptr, 0, 0," 1483 << " // No instruction-level machine model.\n"; 1484 OS << " DBGVAL_OR_NULLPTR(&" << Target 1485 << "SchedClassNames), // SchedClassNames\n"; 1486 if (PM.hasItineraries()) 1487 OS << " " << PM.ItinsDef->getName() << ",\n"; 1488 else 1489 OS << " nullptr, // No Itinerary\n"; 1490 if (PM.hasExtraProcessorInfo()) 1491 OS << " &" << PM.ModelName << "ExtraInfo,\n"; 1492 else 1493 OS << " nullptr // No extra processor descriptor\n"; 1494 OS << "};\n"; 1495 } 1496 } 1497 1498 // 1499 // EmitSchedModel - Emits all scheduling model tables, folding common patterns. 1500 // 1501 void SubtargetEmitter::emitSchedModel(raw_ostream &OS) { 1502 OS << "#ifdef DBGFIELD\n" 1503 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" 1504 << "#endif\n" 1505 << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n" 1506 << "#define DBGFIELD(x) x,\n" 1507 << "#define DBGVAL_OR_NULLPTR(x) x\n" 1508 << "#else\n" 1509 << "#define DBGFIELD(x)\n" 1510 << "#define DBGVAL_OR_NULLPTR(x) nullptr\n" 1511 << "#endif\n"; 1512 1513 if (SchedModels.hasItineraries()) { 1514 std::vector<std::vector<InstrItinerary>> ProcItinLists; 1515 // Emit the stage data 1516 emitStageAndOperandCycleData(OS, ProcItinLists); 1517 emitItineraries(OS, ProcItinLists); 1518 } 1519 OS << "\n// ===============================================================\n" 1520 << "// Data tables for the new per-operand machine model.\n"; 1521 1522 SchedClassTables SchedTables; 1523 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { 1524 genSchedClassTables(ProcModel, SchedTables); 1525 } 1526 emitSchedClassTables(SchedTables, OS); 1527 1528 // Emit the processor machine model 1529 emitProcessorModels(OS); 1530 1531 OS << "\n#undef DBGFIELD\n"; 1532 OS << "\n#undef DBGVAL_OR_NULLPTR\n"; 1533 } 1534 1535 static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { 1536 std::string Buffer; 1537 raw_string_ostream Stream(Buffer); 1538 1539 // Print all PredicateProlog records to the output stream. 1540 for (const Record *P : Records.getAllDerivedDefinitions("PredicateProlog")) 1541 Stream << P->getValueAsString("Code") << '\n'; 1542 1543 OS << Buffer; 1544 } 1545 1546 static bool isTruePredicate(const Record *Rec) { 1547 return Rec->isSubClassOf("MCSchedPredicate") && 1548 Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue"); 1549 } 1550 1551 static void emitPredicates(const CodeGenSchedTransition &T, 1552 const CodeGenSchedClass &SC, PredicateExpander &PE, 1553 raw_ostream &OS) { 1554 std::string Buffer; 1555 raw_string_ostream SS(Buffer); 1556 1557 // If not all predicates are MCTrue, then we need an if-stmt. 1558 unsigned NumNonTruePreds = 1559 T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate); 1560 1561 SS << PE.getIndent(); 1562 1563 if (NumNonTruePreds) { 1564 bool FirstNonTruePredicate = true; 1565 SS << "if ("; 1566 1567 PE.getIndent() += 2; 1568 1569 for (const Record *Rec : T.PredTerm) { 1570 // Skip predicates that evaluate to "true". 1571 if (isTruePredicate(Rec)) 1572 continue; 1573 1574 if (FirstNonTruePredicate) { 1575 FirstNonTruePredicate = false; 1576 } else { 1577 SS << "\n"; 1578 SS << PE.getIndent(); 1579 SS << "&& "; 1580 } 1581 1582 if (Rec->isSubClassOf("MCSchedPredicate")) { 1583 PE.expandPredicate(SS, Rec->getValueAsDef("Pred")); 1584 continue; 1585 } 1586 1587 // Expand this legacy predicate and wrap it around braces if there is more 1588 // than one predicate to expand. 1589 SS << ((NumNonTruePreds > 1) ? "(" : "") 1590 << Rec->getValueAsString("Predicate") 1591 << ((NumNonTruePreds > 1) ? ")" : ""); 1592 } 1593 1594 SS << ")\n"; // end of if-stmt 1595 --PE.getIndent(); 1596 SS << PE.getIndent(); 1597 --PE.getIndent(); 1598 } 1599 1600 SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; 1601 OS << Buffer; 1602 } 1603 1604 // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate 1605 // epilogue code for the auto-generated helper. 1606 static void emitSchedModelHelperEpilogue(raw_ostream &OS, 1607 bool ShouldReturnZero) { 1608 if (ShouldReturnZero) { 1609 OS << " // Don't know how to resolve this scheduling class.\n" 1610 << " return 0;\n"; 1611 return; 1612 } 1613 1614 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; 1615 } 1616 1617 static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { 1618 return all_of(T.PredTerm, [](const Record *Rec) { 1619 return Rec->isSubClassOf("MCSchedPredicate"); 1620 }); 1621 } 1622 1623 static void collectVariantClasses(const CodeGenSchedModels &SchedModels, 1624 IdxVec &VariantClasses, 1625 bool OnlyExpandMCInstPredicates) { 1626 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { 1627 // Ignore non-variant scheduling classes. 1628 if (SC.Transitions.empty()) 1629 continue; 1630 1631 if (OnlyExpandMCInstPredicates) { 1632 // Ignore this variant scheduling class no transitions use any meaningful 1633 // MCSchedPredicate definitions. 1634 if (llvm::none_of(SC.Transitions, hasMCSchedPredicates)) 1635 continue; 1636 } 1637 1638 VariantClasses.push_back(SC.Index); 1639 } 1640 } 1641 1642 static void collectProcessorIndices(const CodeGenSchedClass &SC, 1643 IdxVec &ProcIndices) { 1644 // A variant scheduling class may define transitions for multiple 1645 // processors. This function identifies wich processors are associated with 1646 // transition rules specified by variant class `SC`. 1647 for (const CodeGenSchedTransition &T : SC.Transitions) { 1648 IdxVec PI; 1649 std::set_union(&T.ProcIndex, &T.ProcIndex + 1, ProcIndices.begin(), 1650 ProcIndices.end(), std::back_inserter(PI)); 1651 ProcIndices = std::move(PI); 1652 } 1653 } 1654 1655 static bool isAlwaysTrue(const CodeGenSchedTransition &T) { 1656 return llvm::all_of(T.PredTerm, isTruePredicate); 1657 } 1658 1659 void SubtargetEmitter::emitSchedModelHelpersImpl( 1660 raw_ostream &OS, bool OnlyExpandMCInstPredicates) { 1661 IdxVec VariantClasses; 1662 collectVariantClasses(SchedModels, VariantClasses, 1663 OnlyExpandMCInstPredicates); 1664 1665 if (VariantClasses.empty()) { 1666 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); 1667 return; 1668 } 1669 1670 // Construct a switch statement where the condition is a check on the 1671 // scheduling class identifier. There is a `case` for every variant class 1672 // defined by the processor models of this target. 1673 // Each `case` implements a number of rules to resolve (i.e. to transition 1674 // from) a variant scheduling class to another scheduling class. Rules are 1675 // described by instances of CodeGenSchedTransition. Note that transitions may 1676 // not be valid for all processors. 1677 OS << " switch (SchedClass) {\n"; 1678 for (unsigned VC : VariantClasses) { 1679 IdxVec ProcIndices; 1680 const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); 1681 collectProcessorIndices(SC, ProcIndices); 1682 1683 OS << " case " << VC << ": // " << SC.Name << '\n'; 1684 1685 PredicateExpander PE(Target); 1686 PE.setByRef(false); 1687 PE.setExpandForMC(OnlyExpandMCInstPredicates); 1688 for (unsigned PI : ProcIndices) { 1689 OS << " "; 1690 1691 // Emit a guard on the processor ID. 1692 if (PI != 0) { 1693 OS << (OnlyExpandMCInstPredicates 1694 ? "if (CPUID == " 1695 : "if (SchedModel->getProcessorID() == "); 1696 OS << PI << ") "; 1697 OS << "{ // " << SchedModels.procModels()[PI].ModelName << '\n'; 1698 } 1699 1700 // Now emit transitions associated with processor PI. 1701 const CodeGenSchedTransition *FinalT = nullptr; 1702 for (const CodeGenSchedTransition &T : SC.Transitions) { 1703 if (PI != 0 && T.ProcIndex != PI) 1704 continue; 1705 1706 // Emit only transitions based on MCSchedPredicate, if it's the case. 1707 // At least the transition specified by NoSchedPred is emitted, 1708 // which becomes the default transition for those variants otherwise 1709 // not based on MCSchedPredicate. 1710 // FIXME: preferably, llvm-mca should instead assume a reasonable 1711 // default when a variant transition is not based on MCSchedPredicate 1712 // for a given processor. 1713 if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T)) 1714 continue; 1715 1716 // If transition is folded to 'return X' it should be the last one. 1717 if (isAlwaysTrue(T)) { 1718 FinalT = &T; 1719 continue; 1720 } 1721 PE.getIndent() = 3; 1722 emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); 1723 } 1724 if (FinalT) 1725 emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx), 1726 PE, OS); 1727 1728 OS << " }\n"; 1729 1730 if (PI == 0) 1731 break; 1732 } 1733 1734 if (SC.isInferred()) 1735 OS << " return " << SC.Index << ";\n"; 1736 OS << " break;\n"; 1737 } 1738 1739 OS << " };\n"; 1740 1741 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); 1742 } 1743 1744 void SubtargetEmitter::emitSchedModelHelpers(const std::string &ClassName, 1745 raw_ostream &OS) { 1746 OS << "unsigned " << ClassName 1747 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," 1748 << " const TargetSchedModel *SchedModel) const {\n"; 1749 1750 // Emit the predicate prolog code. 1751 emitPredicateProlog(Records, OS); 1752 1753 // Emit target predicates. 1754 emitSchedModelHelpersImpl(OS); 1755 1756 OS << "} // " << ClassName << "::resolveSchedClass\n\n"; 1757 1758 OS << "unsigned " << ClassName 1759 << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," 1760 << " const MCInstrInfo *MCII, unsigned CPUID) const {\n" 1761 << " return " << Target << "_MC" 1762 << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n" 1763 << "} // " << ClassName << "::resolveVariantSchedClass\n\n"; 1764 1765 STIPredicateExpander PE(Target, /*Indent=*/0); 1766 PE.setClassPrefix(ClassName); 1767 PE.setExpandDefinition(true); 1768 PE.setByRef(false); 1769 1770 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1771 PE.expandSTIPredicate(OS, Fn); 1772 } 1773 1774 void SubtargetEmitter::emitHwModeCheck(const std::string &ClassName, 1775 raw_ostream &OS) { 1776 const CodeGenHwModes &CGH = TGT.getHwModes(); 1777 assert(CGH.getNumModeIds() > 0); 1778 if (CGH.getNumModeIds() == 1) 1779 return; 1780 1781 // Collect all HwModes and related features defined in the TD files, 1782 // and store them as a bit set. 1783 unsigned ValueTypeModes = 0; 1784 unsigned RegInfoModes = 0; 1785 unsigned EncodingInfoModes = 0; 1786 for (const auto &MS : CGH.getHwModeSelects()) { 1787 for (const HwModeSelect::PairType &P : MS.second.Items) { 1788 if (P.first == DefaultMode) 1789 continue; 1790 if (P.second->isSubClassOf("ValueType")) { 1791 ValueTypeModes |= (1 << (P.first - 1)); 1792 } else if (P.second->isSubClassOf("RegInfo") || 1793 P.second->isSubClassOf("SubRegRange")) { 1794 RegInfoModes |= (1 << (P.first - 1)); 1795 } else if (P.second->isSubClassOf("InstructionEncoding")) { 1796 EncodingInfoModes |= (1 << (P.first - 1)); 1797 } 1798 } 1799 } 1800 1801 // Start emitting for getHwModeSet(). 1802 OS << "unsigned " << ClassName << "::getHwModeSet() const {\n"; 1803 OS << " // Collect HwModes and store them as a bit set.\n"; 1804 OS << " unsigned Modes = 0;\n"; 1805 for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) { 1806 const HwMode &HM = CGH.getMode(M); 1807 OS << " if (checkFeatures(\"" << HM.Features << "\")) Modes |= (1 << " 1808 << (M - 1) << ");\n"; 1809 } 1810 OS << " return Modes;\n}\n"; 1811 // End emitting for getHwModeSet(). 1812 1813 auto HandlePerMode = [&](std::string ModeType, unsigned ModeInBitSet) { 1814 OS << " case HwMode_" << ModeType << ":\n" 1815 << " Modes &= " << ModeInBitSet << ";\n" 1816 << " if (!Modes)\n return Modes;\n" 1817 << " if (!llvm::has_single_bit<unsigned>(Modes))\n" 1818 << " llvm_unreachable(\"Two or more HwModes for " << ModeType 1819 << " were found!\");\n" 1820 << " return llvm::countr_zero(Modes) + 1;\n"; 1821 }; 1822 1823 // Start emitting for getHwMode(). 1824 OS << "unsigned " << ClassName 1825 << "::getHwMode(enum HwModeType type) const {\n"; 1826 OS << " unsigned Modes = getHwModeSet();\n\n"; 1827 OS << " if (!Modes)\n return Modes;\n\n"; 1828 OS << " switch (type) {\n"; 1829 OS << " case HwMode_Default:\n return llvm::countr_zero(Modes) + 1;\n"; 1830 HandlePerMode("ValueType", ValueTypeModes); 1831 HandlePerMode("RegInfo", RegInfoModes); 1832 HandlePerMode("EncodingInfo", EncodingInfoModes); 1833 OS << " }\n"; 1834 OS << " llvm_unreachable(\"unexpected HwModeType\");\n" 1835 << " return 0; // should not get here\n}\n"; 1836 // End emitting for getHwMode(). 1837 } 1838 1839 void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName, 1840 raw_ostream &OS) { 1841 if (!TGT.hasMacroFusion()) 1842 return; 1843 1844 OS << "std::vector<MacroFusionPredTy> " << ClassName 1845 << "::getMacroFusions() const {\n"; 1846 OS.indent(2) << "std::vector<MacroFusionPredTy> Fusions;\n"; 1847 for (auto *Fusion : TGT.getMacroFusions()) { 1848 std::string Name = Fusion->getNameInitAsString(); 1849 OS.indent(2) << "if (hasFeature(" << Target << "::" << Name 1850 << ")) Fusions.push_back(llvm::is" << Name << ");\n"; 1851 } 1852 1853 OS.indent(2) << "return Fusions;\n"; 1854 OS << "}\n"; 1855 } 1856 1857 // Produces a subtarget specific function for parsing 1858 // the subtarget features string. 1859 void SubtargetEmitter::parseFeaturesFunction(raw_ostream &OS) { 1860 ArrayRef<const Record *> Features = 1861 Records.getAllDerivedDefinitions("SubtargetFeature"); 1862 1863 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" 1864 << "// subtarget options.\n" 1865 << "void llvm::"; 1866 OS << Target; 1867 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, " 1868 << "StringRef FS) {\n" 1869 << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" 1870 << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n" 1871 << " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n"; 1872 1873 if (Features.empty()) { 1874 OS << "}\n"; 1875 return; 1876 } 1877 1878 if (Target == "AArch64") 1879 OS << " CPU = AArch64::resolveCPUAlias(CPU);\n" 1880 << " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n"; 1881 1882 OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n" 1883 << " const FeatureBitset &Bits = getFeatureBits();\n"; 1884 1885 for (const Record *R : Features) { 1886 // Next record 1887 StringRef Instance = R->getName(); 1888 StringRef Value = R->getValueAsString("Value"); 1889 StringRef FieldName = R->getValueAsString("FieldName"); 1890 1891 if (Value == "true" || Value == "false") 1892 OS << " if (Bits[" << Target << "::" << Instance << "]) " << FieldName 1893 << " = " << Value << ";\n"; 1894 else 1895 OS << " if (Bits[" << Target << "::" << Instance << "] && " << FieldName 1896 << " < " << Value << ") " << FieldName << " = " << Value << ";\n"; 1897 } 1898 1899 OS << "}\n"; 1900 } 1901 1902 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { 1903 OS << "namespace " << Target << "_MC {\n" 1904 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" 1905 << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n"; 1906 emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true); 1907 OS << "}\n"; 1908 OS << "} // end namespace " << Target << "_MC\n\n"; 1909 1910 OS << "struct " << Target 1911 << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; 1912 OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT,\n" 1913 << " StringRef CPU, StringRef TuneCPU, StringRef FS,\n" 1914 << " ArrayRef<StringRef> PN,\n" 1915 << " ArrayRef<SubtargetFeatureKV> PF,\n" 1916 << " ArrayRef<SubtargetSubTypeKV> PD,\n" 1917 << " const MCWriteProcResEntry *WPR,\n" 1918 << " const MCWriteLatencyEntry *WL,\n" 1919 << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" 1920 << " const unsigned *OC, const unsigned *FP) :\n" 1921 << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PN, PF, PD,\n" 1922 << " WPR, WL, RA, IS, OC, FP) { }\n\n" 1923 << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" 1924 << " const MCInst *MI, const MCInstrInfo *MCII,\n" 1925 << " unsigned CPUID) const override {\n" 1926 << " return " << Target << "_MC" 1927 << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"; 1928 OS << " }\n"; 1929 if (TGT.getHwModes().getNumModeIds() > 1) { 1930 OS << " unsigned getHwModeSet() const override;\n"; 1931 OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const " 1932 "override;\n"; 1933 } 1934 if (Target == "AArch64") 1935 OS << " bool isCPUStringValid(StringRef CPU) const override {\n" 1936 << " CPU = AArch64::resolveCPUAlias(CPU);\n" 1937 << " return MCSubtargetInfo::isCPUStringValid(CPU);\n" 1938 << " }\n"; 1939 OS << "};\n"; 1940 emitHwModeCheck(Target + "GenMCSubtargetInfo", OS); 1941 } 1942 1943 void SubtargetEmitter::emitMcInstrAnalysisPredicateFunctions(raw_ostream &OS) { 1944 OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n"; 1945 OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; 1946 1947 STIPredicateExpander PE(Target, /*Indent=*/0); 1948 PE.setExpandForMC(true); 1949 PE.setByRef(true); 1950 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1951 PE.expandSTIPredicate(OS, Fn); 1952 1953 OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; 1954 1955 OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n"; 1956 OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; 1957 1958 std::string ClassPrefix = Target + "MCInstrAnalysis"; 1959 PE.setExpandDefinition(true); 1960 PE.setClassPrefix(ClassPrefix); 1961 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1962 PE.expandSTIPredicate(OS, Fn); 1963 1964 OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; 1965 } 1966 1967 // 1968 // SubtargetEmitter::run - Main subtarget enumeration emitter. 1969 // 1970 void SubtargetEmitter::run(raw_ostream &OS) { 1971 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); 1972 1973 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; 1974 OS << "#undef GET_SUBTARGETINFO_ENUM\n\n"; 1975 1976 OS << "namespace llvm {\n"; 1977 auto FeatureMap = enumeration(OS); 1978 OS << "} // end namespace llvm\n\n"; 1979 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; 1980 1981 emitSubtargetInfoMacroCalls(OS); 1982 1983 OS << "namespace llvm {\n"; 1984 unsigned NumFeatures = featureKeyValues(OS, FeatureMap); 1985 OS << "\n"; 1986 emitSchedModel(OS); 1987 OS << "\n"; 1988 unsigned NumProcs = cpuKeyValues(OS, FeatureMap); 1989 OS << "\n"; 1990 unsigned NumNames = cpuNames(OS); 1991 OS << "\n"; 1992 1993 // MCInstrInfo initialization routine. 1994 emitGenMCSubtargetInfo(OS); 1995 1996 OS << "\nstatic inline MCSubtargetInfo *create" << Target 1997 << "MCSubtargetInfoImpl(" 1998 << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n"; 1999 if (Target == "AArch64") 2000 OS << " CPU = AArch64::resolveCPUAlias(CPU);\n" 2001 << " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n"; 2002 OS << " return new " << Target 2003 << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, "; 2004 if (NumNames) 2005 OS << Target << "Names, "; 2006 else 2007 OS << "{}, "; 2008 if (NumFeatures) 2009 OS << Target << "FeatureKV, "; 2010 else 2011 OS << "{}, "; 2012 if (NumProcs) 2013 OS << Target << "SubTypeKV, "; 2014 else 2015 OS << "{}, "; 2016 OS << '\n'; 2017 OS.indent(22); 2018 OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " 2019 << Target << "ReadAdvanceTable, "; 2020 OS << '\n'; 2021 OS.indent(22); 2022 if (SchedModels.hasItineraries()) { 2023 OS << Target << "Stages, " << Target << "OperandCycles, " << Target 2024 << "ForwardingPaths"; 2025 } else { 2026 OS << "nullptr, nullptr, nullptr"; 2027 } 2028 OS << ");\n}\n\n"; 2029 2030 OS << "} // end namespace llvm\n\n"; 2031 2032 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; 2033 2034 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; 2035 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n"; 2036 2037 OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; 2038 OS << "#include \"llvm/Support/Debug.h\"\n"; 2039 OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; 2040 if (Target == "AArch64") 2041 OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n"; 2042 parseFeaturesFunction(OS); 2043 2044 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; 2045 2046 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. 2047 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; 2048 OS << "#undef GET_SUBTARGETINFO_HEADER\n\n"; 2049 2050 std::string ClassName = Target + "GenSubtargetInfo"; 2051 OS << "namespace llvm {\n"; 2052 OS << "class DFAPacketizer;\n"; 2053 OS << "namespace " << Target << "_MC {\n" 2054 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," 2055 << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n" 2056 << "} // end namespace " << Target << "_MC\n\n"; 2057 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" 2058 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " 2059 << "StringRef TuneCPU, StringRef FS);\n" 2060 << "public:\n" 2061 << " unsigned resolveSchedClass(unsigned SchedClass, " 2062 << " const MachineInstr *DefMI," 2063 << " const TargetSchedModel *SchedModel) const override;\n" 2064 << " unsigned resolveVariantSchedClass(unsigned SchedClass," 2065 << " const MCInst *MI, const MCInstrInfo *MCII," 2066 << " unsigned CPUID) const override;\n" 2067 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" 2068 << " const;\n"; 2069 2070 const CodeGenHwModes &CGH = TGT.getHwModes(); 2071 if (CGH.getNumModeIds() > 1) { 2072 OS << " enum class " << Target << "HwModeBits : unsigned {\n"; 2073 for (unsigned M = 0, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) { 2074 StringRef ModeName = CGH.getModeName(M, /*IncludeDefault=*/true); 2075 OS << " " << ModeName << " = "; 2076 if (M == 0) 2077 OS << "0"; 2078 else 2079 OS << "(1 << " << (M - 1) << ")"; 2080 OS << ",\n"; 2081 if (M == NumModes - 1) { 2082 OS << "\n"; 2083 OS << " LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/" << ModeName 2084 << "),\n"; 2085 } 2086 } 2087 OS << " };\n"; 2088 2089 OS << " unsigned getHwModeSet() const override;\n"; 2090 OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const " 2091 "override;\n"; 2092 } 2093 if (TGT.hasMacroFusion()) 2094 OS << " std::vector<MacroFusionPredTy> getMacroFusions() const " 2095 "override;\n"; 2096 2097 STIPredicateExpander PE(Target); 2098 PE.setByRef(false); 2099 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 2100 PE.expandSTIPredicate(OS, Fn); 2101 2102 OS << "};\n" 2103 << "} // end namespace llvm\n\n"; 2104 2105 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; 2106 2107 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; 2108 OS << "#undef GET_SUBTARGETINFO_CTOR\n\n"; 2109 2110 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; 2111 OS << "namespace llvm {\n"; 2112 OS << "extern const llvm::StringRef " << Target << "Names[];\n"; 2113 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; 2114 OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n"; 2115 OS << "extern const llvm::MCWriteProcResEntry " << Target 2116 << "WriteProcResTable[];\n"; 2117 OS << "extern const llvm::MCWriteLatencyEntry " << Target 2118 << "WriteLatencyTable[];\n"; 2119 OS << "extern const llvm::MCReadAdvanceEntry " << Target 2120 << "ReadAdvanceTable[];\n"; 2121 2122 if (SchedModels.hasItineraries()) { 2123 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; 2124 OS << "extern const unsigned " << Target << "OperandCycles[];\n"; 2125 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; 2126 } 2127 2128 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " 2129 << "StringRef TuneCPU, StringRef FS)\n"; 2130 2131 if (Target == "AArch64") 2132 OS << " : TargetSubtargetInfo(TT, AArch64::resolveCPUAlias(CPU),\n" 2133 << " AArch64::resolveCPUAlias(TuneCPU), FS, "; 2134 else 2135 OS << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, "; 2136 if (NumNames) 2137 OS << "ArrayRef(" << Target << "Names, " << NumNames << "), "; 2138 else 2139 OS << "{}, "; 2140 if (NumFeatures) 2141 OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; 2142 else 2143 OS << "{}, "; 2144 if (NumProcs) 2145 OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; 2146 else 2147 OS << "{}, "; 2148 OS << '\n'; 2149 OS.indent(24); 2150 OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " 2151 << Target << "ReadAdvanceTable, "; 2152 OS << '\n'; 2153 OS.indent(24); 2154 if (SchedModels.hasItineraries()) { 2155 OS << Target << "Stages, " << Target << "OperandCycles, " << Target 2156 << "ForwardingPaths"; 2157 } else { 2158 OS << "nullptr, nullptr, nullptr"; 2159 } 2160 OS << ") {}\n\n"; 2161 2162 emitSchedModelHelpers(ClassName, OS); 2163 emitHwModeCheck(ClassName, OS); 2164 emitGetMacroFusions(ClassName, OS); 2165 2166 OS << "} // end namespace llvm\n\n"; 2167 2168 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; 2169 2170 emitMcInstrAnalysisPredicateFunctions(OS); 2171 } 2172 2173 static TableGen::Emitter::OptClass<SubtargetEmitter> 2174 X("gen-subtarget", "Generate subtarget enumerations"); 2175