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