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