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