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