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