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