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