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