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