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.begin(), DefList.end(), 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.begin(), FeatureList.end(), 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.begin(), ProcessorList.end(), 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}\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 << "},\n"; 672 } 673 } 674 OS << "};\n"; 675 676 // Now generate a table with register file info. 677 OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl}\n"; 678 OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName 679 << "RegisterFiles" 680 << "[] = {\n" 681 << " { \"InvalidRegisterFile\", 0, 0, 0 },\n"; 682 unsigned CostTblIndex = 0; 683 684 for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) { 685 OS << " { "; 686 OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", "; 687 unsigned NumCostEntries = RD.Costs.size(); 688 OS << NumCostEntries << ", " << CostTblIndex << "},\n"; 689 CostTblIndex += NumCostEntries; 690 } 691 OS << "};\n"; 692 693 return CostTblIndex; 694 } 695 696 static bool EmitPfmIssueCountersTable(const CodeGenProcModel &ProcModel, 697 raw_ostream &OS) { 698 unsigned NumCounterDefs = 1 + ProcModel.ProcResourceDefs.size(); 699 std::vector<const Record *> CounterDefs(NumCounterDefs); 700 bool HasCounters = false; 701 for (const Record *CounterDef : ProcModel.PfmIssueCounterDefs) { 702 const Record *&CD = CounterDefs[ProcModel.getProcResourceIdx( 703 CounterDef->getValueAsDef("Resource"))]; 704 if (CD) { 705 PrintFatalError(CounterDef->getLoc(), 706 "multiple issue counters for " + 707 CounterDef->getValueAsDef("Resource")->getName()); 708 } 709 CD = CounterDef; 710 HasCounters = true; 711 } 712 if (!HasCounters) { 713 return false; 714 } 715 OS << "\nstatic const char* " << ProcModel.ModelName 716 << "PfmIssueCounters[] = {\n"; 717 for (unsigned i = 0; i != NumCounterDefs; ++i) { 718 const Record *CounterDef = CounterDefs[i]; 719 if (CounterDef) { 720 const auto PfmCounters = CounterDef->getValueAsListOfStrings("Counters"); 721 if (PfmCounters.empty()) 722 PrintFatalError(CounterDef->getLoc(), "empty counter list"); 723 OS << " \"" << PfmCounters[0]; 724 for (unsigned p = 1, e = PfmCounters.size(); p != e; ++p) 725 OS << ",\" \"" << PfmCounters[p]; 726 OS << "\", // #" << i << " = "; 727 OS << CounterDef->getValueAsDef("Resource")->getName() << "\n"; 728 } else { 729 OS << " nullptr, // #" << i << "\n"; 730 } 731 } 732 OS << "};\n"; 733 return true; 734 } 735 736 static void EmitPfmCounters(const CodeGenProcModel &ProcModel, 737 const bool HasPfmIssueCounters, raw_ostream &OS) { 738 OS << " {\n"; 739 // Emit the cycle counter. 740 if (ProcModel.PfmCycleCounterDef) 741 OS << " \"" << ProcModel.PfmCycleCounterDef->getValueAsString("Counter") 742 << "\", // Cycle counter.\n"; 743 else 744 OS << " nullptr, // No cycle counter.\n"; 745 746 // Emit a reference to issue counters table. 747 if (HasPfmIssueCounters) 748 OS << " " << ProcModel.ModelName << "PfmIssueCounters\n"; 749 else 750 OS << " nullptr // No issue counters.\n"; 751 OS << " }\n"; 752 } 753 754 void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, 755 raw_ostream &OS) { 756 // Generate a table of register file descriptors (one entry per each user 757 // defined register file), and a table of register costs. 758 unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS); 759 760 // Generate a table of ProcRes counter names. 761 const bool HasPfmIssueCounters = EmitPfmIssueCountersTable(ProcModel, OS); 762 763 // Now generate a table for the extra processor info. 764 OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName 765 << "ExtraInfo = {\n "; 766 767 // Add information related to the retire control unit. 768 EmitRetireControlUnitInfo(ProcModel, OS); 769 770 // Add information related to the register files (i.e. where to find register 771 // file descriptors and register costs). 772 EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), 773 NumCostEntries, OS); 774 775 EmitPfmCounters(ProcModel, HasPfmIssueCounters, OS); 776 777 OS << "};\n"; 778 } 779 780 void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, 781 raw_ostream &OS) { 782 EmitProcessorResourceSubUnits(ProcModel, OS); 783 784 OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n"; 785 OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName 786 << "ProcResources" 787 << "[] = {\n" 788 << " {\"InvalidUnit\", 0, 0, 0, 0},\n"; 789 790 unsigned SubUnitsOffset = 1; 791 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { 792 Record *PRDef = ProcModel.ProcResourceDefs[i]; 793 794 Record *SuperDef = nullptr; 795 unsigned SuperIdx = 0; 796 unsigned NumUnits = 0; 797 const unsigned SubUnitsBeginOffset = SubUnitsOffset; 798 int BufferSize = PRDef->getValueAsInt("BufferSize"); 799 if (PRDef->isSubClassOf("ProcResGroup")) { 800 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); 801 for (Record *RU : ResUnits) { 802 NumUnits += RU->getValueAsInt("NumUnits"); 803 SubUnitsOffset += RU->getValueAsInt("NumUnits"); 804 } 805 } 806 else { 807 // Find the SuperIdx 808 if (PRDef->getValueInit("Super")->isComplete()) { 809 SuperDef = 810 SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), 811 ProcModel, PRDef->getLoc()); 812 SuperIdx = ProcModel.getProcResourceIdx(SuperDef); 813 } 814 NumUnits = PRDef->getValueAsInt("NumUnits"); 815 } 816 // Emit the ProcResourceDesc 817 OS << " {\"" << PRDef->getName() << "\", "; 818 if (PRDef->getName().size() < 15) 819 OS.indent(15 - PRDef->getName().size()); 820 OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", "; 821 if (SubUnitsBeginOffset != SubUnitsOffset) { 822 OS << ProcModel.ModelName << "ProcResourceSubUnits + " 823 << SubUnitsBeginOffset; 824 } else { 825 OS << "nullptr"; 826 } 827 OS << "}, // #" << i+1; 828 if (SuperDef) 829 OS << ", Super=" << SuperDef->getName(); 830 OS << "\n"; 831 } 832 OS << "};\n"; 833 } 834 835 // Find the WriteRes Record that defines processor resources for this 836 // SchedWrite. 837 Record *SubtargetEmitter::FindWriteResources( 838 const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { 839 840 // Check if the SchedWrite is already subtarget-specific and directly 841 // specifies a set of processor resources. 842 if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) 843 return SchedWrite.TheDef; 844 845 Record *AliasDef = nullptr; 846 for (Record *A : SchedWrite.Aliases) { 847 const CodeGenSchedRW &AliasRW = 848 SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); 849 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 850 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 851 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 852 continue; 853 } 854 if (AliasDef) 855 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 856 "defined for processor " + ProcModel.ModelName + 857 " Ensure only one SchedAlias exists per RW."); 858 AliasDef = AliasRW.TheDef; 859 } 860 if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) 861 return AliasDef; 862 863 // Check this processor's list of write resources. 864 Record *ResDef = nullptr; 865 for (Record *WR : ProcModel.WriteResDefs) { 866 if (!WR->isSubClassOf("WriteRes")) 867 continue; 868 if (AliasDef == WR->getValueAsDef("WriteType") 869 || SchedWrite.TheDef == WR->getValueAsDef("WriteType")) { 870 if (ResDef) { 871 PrintFatalError(WR->getLoc(), "Resources are defined for both " 872 "SchedWrite and its alias on processor " + 873 ProcModel.ModelName); 874 } 875 ResDef = WR; 876 } 877 } 878 // TODO: If ProcModel has a base model (previous generation processor), 879 // then call FindWriteResources recursively with that model here. 880 if (!ResDef) { 881 PrintFatalError(ProcModel.ModelDef->getLoc(), 882 Twine("Processor does not define resources for ") + 883 SchedWrite.TheDef->getName()); 884 } 885 return ResDef; 886 } 887 888 /// Find the ReadAdvance record for the given SchedRead on this processor or 889 /// return NULL. 890 Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, 891 const CodeGenProcModel &ProcModel) { 892 // Check for SchedReads that directly specify a ReadAdvance. 893 if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) 894 return SchedRead.TheDef; 895 896 // Check this processor's list of aliases for SchedRead. 897 Record *AliasDef = nullptr; 898 for (Record *A : SchedRead.Aliases) { 899 const CodeGenSchedRW &AliasRW = 900 SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); 901 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 902 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 903 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 904 continue; 905 } 906 if (AliasDef) 907 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 908 "defined for processor " + ProcModel.ModelName + 909 " Ensure only one SchedAlias exists per RW."); 910 AliasDef = AliasRW.TheDef; 911 } 912 if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) 913 return AliasDef; 914 915 // Check this processor's ReadAdvanceList. 916 Record *ResDef = nullptr; 917 for (Record *RA : ProcModel.ReadAdvanceDefs) { 918 if (!RA->isSubClassOf("ReadAdvance")) 919 continue; 920 if (AliasDef == RA->getValueAsDef("ReadType") 921 || SchedRead.TheDef == RA->getValueAsDef("ReadType")) { 922 if (ResDef) { 923 PrintFatalError(RA->getLoc(), "Resources are defined for both " 924 "SchedRead and its alias on processor " + 925 ProcModel.ModelName); 926 } 927 ResDef = RA; 928 } 929 } 930 // TODO: If ProcModel has a base model (previous generation processor), 931 // then call FindReadAdvance recursively with that model here. 932 if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { 933 PrintFatalError(ProcModel.ModelDef->getLoc(), 934 Twine("Processor does not define resources for ") + 935 SchedRead.TheDef->getName()); 936 } 937 return ResDef; 938 } 939 940 // Expand an explicit list of processor resources into a full list of implied 941 // resource groups and super resources that cover them. 942 void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, 943 std::vector<int64_t> &Cycles, 944 const CodeGenProcModel &PM) { 945 assert(PRVec.size() == Cycles.size() && "failed precondition"); 946 for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { 947 Record *PRDef = PRVec[i]; 948 RecVec SubResources; 949 if (PRDef->isSubClassOf("ProcResGroup")) 950 SubResources = PRDef->getValueAsListOfDefs("Resources"); 951 else { 952 SubResources.push_back(PRDef); 953 PRDef = SchedModels.findProcResUnits(PRDef, PM, PRDef->getLoc()); 954 for (Record *SubDef = PRDef; 955 SubDef->getValueInit("Super")->isComplete();) { 956 if (SubDef->isSubClassOf("ProcResGroup")) { 957 // Disallow this for simplicitly. 958 PrintFatalError(SubDef->getLoc(), "Processor resource group " 959 " cannot be a super resources."); 960 } 961 Record *SuperDef = 962 SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM, 963 SubDef->getLoc()); 964 PRVec.push_back(SuperDef); 965 Cycles.push_back(Cycles[i]); 966 SubDef = SuperDef; 967 } 968 } 969 for (Record *PR : PM.ProcResourceDefs) { 970 if (PR == PRDef || !PR->isSubClassOf("ProcResGroup")) 971 continue; 972 RecVec SuperResources = PR->getValueAsListOfDefs("Resources"); 973 RecIter SubI = SubResources.begin(), SubE = SubResources.end(); 974 for( ; SubI != SubE; ++SubI) { 975 if (!is_contained(SuperResources, *SubI)) { 976 break; 977 } 978 } 979 if (SubI == SubE) { 980 PRVec.push_back(PR); 981 Cycles.push_back(Cycles[i]); 982 } 983 } 984 } 985 } 986 987 // Generate the SchedClass table for this processor and update global 988 // tables. Must be called for each processor in order. 989 void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, 990 SchedClassTables &SchedTables) { 991 SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1); 992 if (!ProcModel.hasInstrSchedModel()) 993 return; 994 995 std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); 996 LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n"); 997 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { 998 LLVM_DEBUG(SC.dump(&SchedModels)); 999 1000 SCTab.resize(SCTab.size() + 1); 1001 MCSchedClassDesc &SCDesc = SCTab.back(); 1002 // SCDesc.Name is guarded by NDEBUG 1003 SCDesc.NumMicroOps = 0; 1004 SCDesc.BeginGroup = false; 1005 SCDesc.EndGroup = false; 1006 SCDesc.WriteProcResIdx = 0; 1007 SCDesc.WriteLatencyIdx = 0; 1008 SCDesc.ReadAdvanceIdx = 0; 1009 1010 // A Variant SchedClass has no resources of its own. 1011 bool HasVariants = false; 1012 for (const CodeGenSchedTransition &CGT : 1013 make_range(SC.Transitions.begin(), SC.Transitions.end())) { 1014 if (CGT.ProcIndices[0] == 0 || 1015 is_contained(CGT.ProcIndices, ProcModel.Index)) { 1016 HasVariants = true; 1017 break; 1018 } 1019 } 1020 if (HasVariants) { 1021 SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; 1022 continue; 1023 } 1024 1025 // Determine if the SchedClass is actually reachable on this processor. If 1026 // not don't try to locate the processor resources, it will fail. 1027 // If ProcIndices contains 0, this class applies to all processors. 1028 assert(!SC.ProcIndices.empty() && "expect at least one procidx"); 1029 if (SC.ProcIndices[0] != 0) { 1030 if (!is_contained(SC.ProcIndices, ProcModel.Index)) 1031 continue; 1032 } 1033 IdxVec Writes = SC.Writes; 1034 IdxVec Reads = SC.Reads; 1035 if (!SC.InstRWs.empty()) { 1036 // This class has a default ReadWrite list which can be overridden by 1037 // InstRW definitions. 1038 Record *RWDef = nullptr; 1039 for (Record *RW : SC.InstRWs) { 1040 Record *RWModelDef = RW->getValueAsDef("SchedModel"); 1041 if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { 1042 RWDef = RW; 1043 break; 1044 } 1045 } 1046 if (RWDef) { 1047 Writes.clear(); 1048 Reads.clear(); 1049 SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), 1050 Writes, Reads); 1051 } 1052 } 1053 if (Writes.empty()) { 1054 // Check this processor's itinerary class resources. 1055 for (Record *I : ProcModel.ItinRWDefs) { 1056 RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses"); 1057 if (is_contained(Matched, SC.ItinClassDef)) { 1058 SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"), 1059 Writes, Reads); 1060 break; 1061 } 1062 } 1063 if (Writes.empty()) { 1064 LLVM_DEBUG(dbgs() << ProcModel.ModelName 1065 << " does not have resources for class " << SC.Name 1066 << '\n'); 1067 } 1068 } 1069 // Sum resources across all operand writes. 1070 std::vector<MCWriteProcResEntry> WriteProcResources; 1071 std::vector<MCWriteLatencyEntry> WriteLatencies; 1072 std::vector<std::string> WriterNames; 1073 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 1074 for (unsigned W : Writes) { 1075 IdxVec WriteSeq; 1076 SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, 1077 ProcModel); 1078 1079 // For each operand, create a latency entry. 1080 MCWriteLatencyEntry WLEntry; 1081 WLEntry.Cycles = 0; 1082 unsigned WriteID = WriteSeq.back(); 1083 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); 1084 // If this Write is not referenced by a ReadAdvance, don't distinguish it 1085 // from other WriteLatency entries. 1086 if (!SchedModels.hasReadOfWrite( 1087 SchedModels.getSchedWrite(WriteID).TheDef)) { 1088 WriteID = 0; 1089 } 1090 WLEntry.WriteResourceID = WriteID; 1091 1092 for (unsigned WS : WriteSeq) { 1093 1094 Record *WriteRes = 1095 FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel); 1096 1097 // Mark the parent class as invalid for unsupported write types. 1098 if (WriteRes->getValueAsBit("Unsupported")) { 1099 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 1100 break; 1101 } 1102 WLEntry.Cycles += WriteRes->getValueAsInt("Latency"); 1103 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps"); 1104 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup"); 1105 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup"); 1106 SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue"); 1107 SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue"); 1108 1109 // Create an entry for each ProcResource listed in WriteRes. 1110 RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); 1111 std::vector<int64_t> Cycles = 1112 WriteRes->getValueAsListOfInts("ResourceCycles"); 1113 1114 if (Cycles.empty()) { 1115 // If ResourceCycles is not provided, default to one cycle per 1116 // resource. 1117 Cycles.resize(PRVec.size(), 1); 1118 } else if (Cycles.size() != PRVec.size()) { 1119 // If ResourceCycles is provided, check consistency. 1120 PrintFatalError( 1121 WriteRes->getLoc(), 1122 Twine("Inconsistent resource cycles: !size(ResourceCycles) != " 1123 "!size(ProcResources): ") 1124 .concat(Twine(PRVec.size())) 1125 .concat(" vs ") 1126 .concat(Twine(Cycles.size()))); 1127 } 1128 1129 ExpandProcResources(PRVec, Cycles, ProcModel); 1130 1131 for (unsigned PRIdx = 0, PREnd = PRVec.size(); 1132 PRIdx != PREnd; ++PRIdx) { 1133 MCWriteProcResEntry WPREntry; 1134 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); 1135 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); 1136 WPREntry.Cycles = Cycles[PRIdx]; 1137 // If this resource is already used in this sequence, add the current 1138 // entry's cycles so that the same resource appears to be used 1139 // serially, rather than multiple parallel uses. This is important for 1140 // in-order machine where the resource consumption is a hazard. 1141 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); 1142 for( ; WPRIdx != WPREnd; ++WPRIdx) { 1143 if (WriteProcResources[WPRIdx].ProcResourceIdx 1144 == WPREntry.ProcResourceIdx) { 1145 WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles; 1146 break; 1147 } 1148 } 1149 if (WPRIdx == WPREnd) 1150 WriteProcResources.push_back(WPREntry); 1151 } 1152 } 1153 WriteLatencies.push_back(WLEntry); 1154 } 1155 // Create an entry for each operand Read in this SchedClass. 1156 // Entries must be sorted first by UseIdx then by WriteResourceID. 1157 for (unsigned UseIdx = 0, EndIdx = Reads.size(); 1158 UseIdx != EndIdx; ++UseIdx) { 1159 Record *ReadAdvance = 1160 FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); 1161 if (!ReadAdvance) 1162 continue; 1163 1164 // Mark the parent class as invalid for unsupported write types. 1165 if (ReadAdvance->getValueAsBit("Unsupported")) { 1166 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 1167 break; 1168 } 1169 RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites"); 1170 IdxVec WriteIDs; 1171 if (ValidWrites.empty()) 1172 WriteIDs.push_back(0); 1173 else { 1174 for (Record *VW : ValidWrites) { 1175 WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false)); 1176 } 1177 } 1178 llvm::sort(WriteIDs.begin(), WriteIDs.end()); 1179 for(unsigned W : WriteIDs) { 1180 MCReadAdvanceEntry RAEntry; 1181 RAEntry.UseIdx = UseIdx; 1182 RAEntry.WriteResourceID = W; 1183 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); 1184 ReadAdvanceEntries.push_back(RAEntry); 1185 } 1186 } 1187 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 1188 WriteProcResources.clear(); 1189 WriteLatencies.clear(); 1190 ReadAdvanceEntries.clear(); 1191 } 1192 // Add the information for this SchedClass to the global tables using basic 1193 // compression. 1194 // 1195 // WritePrecRes entries are sorted by ProcResIdx. 1196 llvm::sort(WriteProcResources.begin(), WriteProcResources.end(), 1197 LessWriteProcResources()); 1198 1199 SCDesc.NumWriteProcResEntries = WriteProcResources.size(); 1200 std::vector<MCWriteProcResEntry>::iterator WPRPos = 1201 std::search(SchedTables.WriteProcResources.begin(), 1202 SchedTables.WriteProcResources.end(), 1203 WriteProcResources.begin(), WriteProcResources.end()); 1204 if (WPRPos != SchedTables.WriteProcResources.end()) 1205 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin(); 1206 else { 1207 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size(); 1208 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(), 1209 WriteProcResources.end()); 1210 } 1211 // Latency entries must remain in operand order. 1212 SCDesc.NumWriteLatencyEntries = WriteLatencies.size(); 1213 std::vector<MCWriteLatencyEntry>::iterator WLPos = 1214 std::search(SchedTables.WriteLatencies.begin(), 1215 SchedTables.WriteLatencies.end(), 1216 WriteLatencies.begin(), WriteLatencies.end()); 1217 if (WLPos != SchedTables.WriteLatencies.end()) { 1218 unsigned idx = WLPos - SchedTables.WriteLatencies.begin(); 1219 SCDesc.WriteLatencyIdx = idx; 1220 for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i) 1221 if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) == 1222 std::string::npos) { 1223 SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i]; 1224 } 1225 } 1226 else { 1227 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); 1228 SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), 1229 WriteLatencies.begin(), 1230 WriteLatencies.end()); 1231 SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), 1232 WriterNames.begin(), WriterNames.end()); 1233 } 1234 // ReadAdvanceEntries must remain in operand order. 1235 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); 1236 std::vector<MCReadAdvanceEntry>::iterator RAPos = 1237 std::search(SchedTables.ReadAdvanceEntries.begin(), 1238 SchedTables.ReadAdvanceEntries.end(), 1239 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end()); 1240 if (RAPos != SchedTables.ReadAdvanceEntries.end()) 1241 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); 1242 else { 1243 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); 1244 SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(), 1245 ReadAdvanceEntries.end()); 1246 } 1247 } 1248 } 1249 1250 // Emit SchedClass tables for all processors and associated global tables. 1251 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, 1252 raw_ostream &OS) { 1253 // Emit global WriteProcResTable. 1254 OS << "\n// {ProcResourceIdx, Cycles}\n" 1255 << "extern const llvm::MCWriteProcResEntry " 1256 << Target << "WriteProcResTable[] = {\n" 1257 << " { 0, 0}, // Invalid\n"; 1258 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); 1259 WPRIdx != WPREnd; ++WPRIdx) { 1260 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; 1261 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " 1262 << format("%2d", WPREntry.Cycles) << "}"; 1263 if (WPRIdx + 1 < WPREnd) 1264 OS << ','; 1265 OS << " // #" << WPRIdx << '\n'; 1266 } 1267 OS << "}; // " << Target << "WriteProcResTable\n"; 1268 1269 // Emit global WriteLatencyTable. 1270 OS << "\n// {Cycles, WriteResourceID}\n" 1271 << "extern const llvm::MCWriteLatencyEntry " 1272 << Target << "WriteLatencyTable[] = {\n" 1273 << " { 0, 0}, // Invalid\n"; 1274 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); 1275 WLIdx != WLEnd; ++WLIdx) { 1276 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; 1277 OS << " {" << format("%2d", WLEntry.Cycles) << ", " 1278 << format("%2d", WLEntry.WriteResourceID) << "}"; 1279 if (WLIdx + 1 < WLEnd) 1280 OS << ','; 1281 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; 1282 } 1283 OS << "}; // " << Target << "WriteLatencyTable\n"; 1284 1285 // Emit global ReadAdvanceTable. 1286 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" 1287 << "extern const llvm::MCReadAdvanceEntry " 1288 << Target << "ReadAdvanceTable[] = {\n" 1289 << " {0, 0, 0}, // Invalid\n"; 1290 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); 1291 RAIdx != RAEnd; ++RAIdx) { 1292 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; 1293 OS << " {" << RAEntry.UseIdx << ", " 1294 << format("%2d", RAEntry.WriteResourceID) << ", " 1295 << format("%2d", RAEntry.Cycles) << "}"; 1296 if (RAIdx + 1 < RAEnd) 1297 OS << ','; 1298 OS << " // #" << RAIdx << '\n'; 1299 } 1300 OS << "}; // " << Target << "ReadAdvanceTable\n"; 1301 1302 // Emit a SchedClass table for each processor. 1303 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1304 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1305 if (!PI->hasInstrSchedModel()) 1306 continue; 1307 1308 std::vector<MCSchedClassDesc> &SCTab = 1309 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; 1310 1311 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup," 1312 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; 1313 OS << "static const llvm::MCSchedClassDesc " 1314 << PI->ModelName << "SchedClasses[] = {\n"; 1315 1316 // The first class is always invalid. We no way to distinguish it except by 1317 // name and position. 1318 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" 1319 && "invalid class not first"); 1320 OS << " {DBGFIELD(\"InvalidSchedClass\") " 1321 << MCSchedClassDesc::InvalidNumMicroOps 1322 << ", false, false, 0, 0, 0, 0, 0, 0},\n"; 1323 1324 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { 1325 MCSchedClassDesc &MCDesc = SCTab[SCIdx]; 1326 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); 1327 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; 1328 if (SchedClass.Name.size() < 18) 1329 OS.indent(18 - SchedClass.Name.size()); 1330 OS << MCDesc.NumMicroOps 1331 << ", " << ( MCDesc.BeginGroup ? "true" : "false" ) 1332 << ", " << ( MCDesc.EndGroup ? "true" : "false" ) 1333 << ", " << format("%2d", MCDesc.WriteProcResIdx) 1334 << ", " << MCDesc.NumWriteProcResEntries 1335 << ", " << format("%2d", MCDesc.WriteLatencyIdx) 1336 << ", " << MCDesc.NumWriteLatencyEntries 1337 << ", " << format("%2d", MCDesc.ReadAdvanceIdx) 1338 << ", " << MCDesc.NumReadAdvanceEntries 1339 << "}, // #" << SCIdx << '\n'; 1340 } 1341 OS << "}; // " << PI->ModelName << "SchedClasses\n"; 1342 } 1343 } 1344 1345 void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { 1346 // For each processor model. 1347 for (const CodeGenProcModel &PM : SchedModels.procModels()) { 1348 // Emit extra processor info if available. 1349 if (PM.hasExtraProcessorInfo()) 1350 EmitExtraProcessorInfo(PM, OS); 1351 // Emit processor resource table. 1352 if (PM.hasInstrSchedModel()) 1353 EmitProcessorResources(PM, OS); 1354 else if(!PM.ProcResourceDefs.empty()) 1355 PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines " 1356 "ProcResources without defining WriteRes SchedWriteRes"); 1357 1358 // Begin processor itinerary properties 1359 OS << "\n"; 1360 OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n"; 1361 EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ','); 1362 EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ','); 1363 EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ','); 1364 EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ','); 1365 EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ','); 1366 EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ','); 1367 1368 bool PostRAScheduler = 1369 (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false); 1370 1371 OS << " " << (PostRAScheduler ? "true" : "false") << ", // " 1372 << "PostRAScheduler\n"; 1373 1374 bool CompleteModel = 1375 (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false); 1376 1377 OS << " " << (CompleteModel ? "true" : "false") << ", // " 1378 << "CompleteModel\n"; 1379 1380 OS << " " << PM.Index << ", // Processor ID\n"; 1381 if (PM.hasInstrSchedModel()) 1382 OS << " " << PM.ModelName << "ProcResources" << ",\n" 1383 << " " << PM.ModelName << "SchedClasses" << ",\n" 1384 << " " << PM.ProcResourceDefs.size()+1 << ",\n" 1385 << " " << (SchedModels.schedClassEnd() 1386 - SchedModels.schedClassBegin()) << ",\n"; 1387 else 1388 OS << " nullptr, nullptr, 0, 0," 1389 << " // No instruction-level machine model.\n"; 1390 if (PM.hasItineraries()) 1391 OS << " " << PM.ItinsDef->getName() << ",\n"; 1392 else 1393 OS << " nullptr, // No Itinerary\n"; 1394 if (PM.hasExtraProcessorInfo()) 1395 OS << " &" << PM.ModelName << "ExtraInfo,\n"; 1396 else 1397 OS << " nullptr // No extra processor descriptor\n"; 1398 OS << "};\n"; 1399 } 1400 } 1401 1402 // 1403 // EmitProcessorLookup - generate cpu name to itinerary lookup table. 1404 // 1405 void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { 1406 // Gather and sort processor information 1407 std::vector<Record*> ProcessorList = 1408 Records.getAllDerivedDefinitions("Processor"); 1409 llvm::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); 1410 1411 // Begin processor table 1412 OS << "\n"; 1413 OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" 1414 << "extern const llvm::SubtargetInfoKV " 1415 << Target << "ProcSchedKV[] = {\n"; 1416 1417 // For each processor 1418 for (Record *Processor : ProcessorList) { 1419 StringRef Name = Processor->getValueAsString("Name"); 1420 const std::string &ProcModelName = 1421 SchedModels.getModelForProc(Processor).ModelName; 1422 1423 // Emit as { "cpu", procinit }, 1424 OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " },\n"; 1425 } 1426 1427 // End processor table 1428 OS << "};\n"; 1429 } 1430 1431 // 1432 // EmitSchedModel - Emits all scheduling model tables, folding common patterns. 1433 // 1434 void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { 1435 OS << "#ifdef DBGFIELD\n" 1436 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" 1437 << "#endif\n" 1438 << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n" 1439 << "#define DBGFIELD(x) x,\n" 1440 << "#else\n" 1441 << "#define DBGFIELD(x)\n" 1442 << "#endif\n"; 1443 1444 if (SchedModels.hasItineraries()) { 1445 std::vector<std::vector<InstrItinerary>> ProcItinLists; 1446 // Emit the stage data 1447 EmitStageAndOperandCycleData(OS, ProcItinLists); 1448 EmitItineraries(OS, ProcItinLists); 1449 } 1450 OS << "\n// ===============================================================\n" 1451 << "// Data tables for the new per-operand machine model.\n"; 1452 1453 SchedClassTables SchedTables; 1454 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { 1455 GenSchedClassTables(ProcModel, SchedTables); 1456 } 1457 EmitSchedClassTables(SchedTables, OS); 1458 1459 // Emit the processor machine model 1460 EmitProcessorModels(OS); 1461 // Emit the processor lookup data 1462 EmitProcessorLookup(OS); 1463 1464 OS << "\n#undef DBGFIELD"; 1465 } 1466 1467 static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { 1468 std::string Buffer; 1469 raw_string_ostream Stream(Buffer); 1470 1471 // Collect all the PredicateProlog records and print them to the output 1472 // stream. 1473 std::vector<Record *> Prologs = 1474 Records.getAllDerivedDefinitions("PredicateProlog"); 1475 llvm::sort(Prologs.begin(), Prologs.end(), LessRecord()); 1476 for (Record *P : Prologs) 1477 Stream << P->getValueAsString("Code") << '\n'; 1478 1479 Stream.flush(); 1480 OS << Buffer; 1481 } 1482 1483 static void emitPredicates(const CodeGenSchedTransition &T, 1484 const CodeGenSchedClass &SC, PredicateExpander &PE, 1485 raw_ostream &OS) { 1486 std::string Buffer; 1487 raw_string_ostream SS(Buffer); 1488 1489 auto IsTruePredicate = [](const Record *Rec) { 1490 return Rec->isSubClassOf("MCSchedPredicate") && 1491 Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue"); 1492 }; 1493 1494 // If not all predicates are MCTrue, then we need an if-stmt. 1495 unsigned NumNonTruePreds = 1496 T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate); 1497 1498 SS.indent(PE.getIndentLevel() * 2); 1499 1500 if (NumNonTruePreds) { 1501 bool FirstNonTruePredicate = true; 1502 SS << "if ("; 1503 1504 PE.setIndentLevel(PE.getIndentLevel() + 2); 1505 1506 for (const Record *Rec : T.PredTerm) { 1507 // Skip predicates that evaluate to "true". 1508 if (IsTruePredicate(Rec)) 1509 continue; 1510 1511 if (FirstNonTruePredicate) { 1512 FirstNonTruePredicate = false; 1513 } else { 1514 SS << "\n"; 1515 SS.indent(PE.getIndentLevel() * 2); 1516 SS << "&& "; 1517 } 1518 1519 if (Rec->isSubClassOf("MCSchedPredicate")) { 1520 PE.expandPredicate(SS, Rec->getValueAsDef("Pred")); 1521 continue; 1522 } 1523 1524 // Expand this legacy predicate and wrap it around braces if there is more 1525 // than one predicate to expand. 1526 SS << ((NumNonTruePreds > 1) ? "(" : "") 1527 << Rec->getValueAsString("Predicate") 1528 << ((NumNonTruePreds > 1) ? ")" : ""); 1529 } 1530 1531 SS << ")\n"; // end of if-stmt 1532 PE.decreaseIndentLevel(); 1533 SS.indent(PE.getIndentLevel() * 2); 1534 PE.decreaseIndentLevel(); 1535 } 1536 1537 SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; 1538 SS.flush(); 1539 OS << Buffer; 1540 } 1541 1542 // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate 1543 // epilogue code for the auto-generated helper. 1544 void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) { 1545 if (ShouldReturnZero) { 1546 OS << " // Don't know how to resolve this scheduling class.\n" 1547 << " return 0;\n"; 1548 return; 1549 } 1550 1551 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; 1552 } 1553 1554 bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { 1555 return all_of(T.PredTerm, [](const Record *Rec) { 1556 return Rec->isSubClassOf("MCSchedPredicate"); 1557 }); 1558 } 1559 1560 void collectVariantClasses(const CodeGenSchedModels &SchedModels, 1561 IdxVec &VariantClasses, 1562 bool OnlyExpandMCInstPredicates) { 1563 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { 1564 // Ignore non-variant scheduling classes. 1565 if (SC.Transitions.empty()) 1566 continue; 1567 1568 if (OnlyExpandMCInstPredicates) { 1569 // Ignore this variant scheduling class if transitions don't uses any 1570 // MCSchedPredicate definitions. 1571 if (!all_of(SC.Transitions, [](const CodeGenSchedTransition &T) { 1572 return hasMCSchedPredicates(T); 1573 })) 1574 continue; 1575 } 1576 1577 VariantClasses.push_back(SC.Index); 1578 } 1579 } 1580 1581 void collectProcessorIndices(const CodeGenSchedClass &SC, IdxVec &ProcIndices) { 1582 // A variant scheduling class may define transitions for multiple 1583 // processors. This function identifies wich processors are associated with 1584 // transition rules specified by variant class `SC`. 1585 for (const CodeGenSchedTransition &T : SC.Transitions) { 1586 IdxVec PI; 1587 std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), 1588 ProcIndices.begin(), ProcIndices.end(), 1589 std::back_inserter(PI)); 1590 ProcIndices.swap(PI); 1591 } 1592 } 1593 1594 void SubtargetEmitter::emitSchedModelHelpersImpl( 1595 raw_ostream &OS, bool OnlyExpandMCInstPredicates) { 1596 IdxVec VariantClasses; 1597 collectVariantClasses(SchedModels, VariantClasses, 1598 OnlyExpandMCInstPredicates); 1599 1600 if (VariantClasses.empty()) { 1601 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); 1602 return; 1603 } 1604 1605 // Construct a switch statement where the condition is a check on the 1606 // scheduling class identifier. There is a `case` for every variant class 1607 // defined by the processor models of this target. 1608 // Each `case` implements a number of rules to resolve (i.e. to transition from) 1609 // a variant scheduling class to another scheduling class. Rules are 1610 // described by instances of CodeGenSchedTransition. Note that transitions may 1611 // not be valid for all processors. 1612 OS << " switch (SchedClass) {\n"; 1613 for (unsigned VC : VariantClasses) { 1614 IdxVec ProcIndices; 1615 const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); 1616 collectProcessorIndices(SC, ProcIndices); 1617 1618 OS << " case " << VC << ": // " << SC.Name << '\n'; 1619 1620 PredicateExpander PE(Target); 1621 PE.setByRef(false); 1622 PE.setExpandForMC(OnlyExpandMCInstPredicates); 1623 for (unsigned PI : ProcIndices) { 1624 OS << " "; 1625 // Emit a guard on the processor ID. 1626 if (PI != 0) { 1627 OS << (OnlyExpandMCInstPredicates 1628 ? "if (CPUID == " 1629 : "if (SchedModel->getProcessorID() == "); 1630 OS << PI << ") "; 1631 OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n'; 1632 } 1633 1634 // Now emit transitions associated with processor PI. 1635 for (const CodeGenSchedTransition &T : SC.Transitions) { 1636 if (PI != 0 && !count(T.ProcIndices, PI)) 1637 continue; 1638 PE.setIndentLevel(3); 1639 emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); 1640 } 1641 1642 OS << " }\n"; 1643 if (PI == 0) 1644 break; 1645 } 1646 1647 if (SC.isInferred()) 1648 OS << " return " << SC.Index << ";\n"; 1649 OS << " break;\n"; 1650 } 1651 1652 OS << " };\n"; 1653 1654 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); 1655 } 1656 1657 void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, 1658 raw_ostream &OS) { 1659 OS << "unsigned " << ClassName 1660 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," 1661 << " const TargetSchedModel *SchedModel) const {\n"; 1662 1663 // Emit the predicate prolog code. 1664 emitPredicateProlog(Records, OS); 1665 1666 // Emit target predicates. 1667 emitSchedModelHelpersImpl(OS); 1668 1669 OS << "} // " << ClassName << "::resolveSchedClass\n\n"; 1670 1671 OS << "unsigned " << ClassName 1672 << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," 1673 << " unsigned CPUID) const {\n" 1674 << " return " << Target << "_MC" 1675 << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n" 1676 << "} // " << ClassName << "::resolveVariantSchedClass\n\n"; 1677 1678 STIPredicateExpander PE(Target); 1679 PE.setClassPrefix(ClassName); 1680 PE.setExpandDefinition(true); 1681 PE.setByRef(false); 1682 PE.setIndentLevel(0); 1683 1684 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1685 PE.expandSTIPredicate(OS, Fn); 1686 } 1687 1688 void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName, 1689 raw_ostream &OS) { 1690 const CodeGenHwModes &CGH = TGT.getHwModes(); 1691 assert(CGH.getNumModeIds() > 0); 1692 if (CGH.getNumModeIds() == 1) 1693 return; 1694 1695 OS << "unsigned " << ClassName << "::getHwMode() const {\n"; 1696 for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) { 1697 const HwMode &HM = CGH.getMode(M); 1698 OS << " if (checkFeatures(\"" << HM.Features 1699 << "\")) return " << M << ";\n"; 1700 } 1701 OS << " return 0;\n}\n"; 1702 } 1703 1704 // 1705 // ParseFeaturesFunction - Produces a subtarget specific function for parsing 1706 // the subtarget features string. 1707 // 1708 void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, 1709 unsigned NumFeatures, 1710 unsigned NumProcs) { 1711 std::vector<Record*> Features = 1712 Records.getAllDerivedDefinitions("SubtargetFeature"); 1713 llvm::sort(Features.begin(), Features.end(), LessRecord()); 1714 1715 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" 1716 << "// subtarget options.\n" 1717 << "void llvm::"; 1718 OS << Target; 1719 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" 1720 << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" 1721 << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; 1722 1723 if (Features.empty()) { 1724 OS << "}\n"; 1725 return; 1726 } 1727 1728 OS << " InitMCProcessorInfo(CPU, FS);\n" 1729 << " const FeatureBitset& Bits = getFeatureBits();\n"; 1730 1731 for (Record *R : Features) { 1732 // Next record 1733 StringRef Instance = R->getName(); 1734 StringRef Value = R->getValueAsString("Value"); 1735 StringRef Attribute = R->getValueAsString("Attribute"); 1736 1737 if (Value=="true" || Value=="false") 1738 OS << " if (Bits[" << Target << "::" 1739 << Instance << "]) " 1740 << Attribute << " = " << Value << ";\n"; 1741 else 1742 OS << " if (Bits[" << Target << "::" 1743 << Instance << "] && " 1744 << Attribute << " < " << Value << ") " 1745 << Attribute << " = " << Value << ";\n"; 1746 } 1747 1748 OS << "}\n"; 1749 } 1750 1751 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { 1752 OS << "namespace " << Target << "_MC {\n" 1753 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" 1754 << " const MCInst *MI, unsigned CPUID) {\n"; 1755 emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true); 1756 OS << "}\n"; 1757 OS << "} // end of namespace " << Target << "_MC\n\n"; 1758 1759 OS << "struct " << Target 1760 << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; 1761 OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT, \n" 1762 << " StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF,\n" 1763 << " ArrayRef<SubtargetFeatureKV> PD,\n" 1764 << " const SubtargetInfoKV *ProcSched,\n" 1765 << " const MCWriteProcResEntry *WPR,\n" 1766 << " const MCWriteLatencyEntry *WL,\n" 1767 << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" 1768 << " const unsigned *OC, const unsigned *FP) :\n" 1769 << " MCSubtargetInfo(TT, CPU, FS, PF, PD, ProcSched,\n" 1770 << " WPR, WL, RA, IS, OC, FP) { }\n\n" 1771 << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" 1772 << " const MCInst *MI, unsigned CPUID) const override {\n" 1773 << " return " << Target << "_MC" 1774 << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n"; 1775 OS << " }\n"; 1776 OS << "};\n"; 1777 } 1778 1779 void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) { 1780 OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n"; 1781 OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; 1782 1783 STIPredicateExpander PE(Target); 1784 PE.setExpandForMC(true); 1785 PE.setByRef(true); 1786 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1787 PE.expandSTIPredicate(OS, Fn); 1788 1789 OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; 1790 1791 OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n"; 1792 OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; 1793 1794 std::string ClassPrefix = Target + "MCInstrAnalysis"; 1795 PE.setExpandDefinition(true); 1796 PE.setClassPrefix(ClassPrefix); 1797 PE.setIndentLevel(0); 1798 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1799 PE.expandSTIPredicate(OS, Fn); 1800 1801 OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; 1802 } 1803 1804 // 1805 // SubtargetEmitter::run - Main subtarget enumeration emitter. 1806 // 1807 void SubtargetEmitter::run(raw_ostream &OS) { 1808 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); 1809 1810 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; 1811 OS << "#undef GET_SUBTARGETINFO_ENUM\n\n"; 1812 1813 OS << "namespace llvm {\n"; 1814 Enumeration(OS); 1815 OS << "} // end namespace llvm\n\n"; 1816 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; 1817 1818 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; 1819 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; 1820 1821 OS << "namespace llvm {\n"; 1822 #if 0 1823 OS << "namespace {\n"; 1824 #endif 1825 unsigned NumFeatures = FeatureKeyValues(OS); 1826 OS << "\n"; 1827 unsigned NumProcs = CPUKeyValues(OS); 1828 OS << "\n"; 1829 EmitSchedModel(OS); 1830 OS << "\n"; 1831 #if 0 1832 OS << "} // end anonymous namespace\n\n"; 1833 #endif 1834 1835 // MCInstrInfo initialization routine. 1836 emitGenMCSubtargetInfo(OS); 1837 1838 OS << "\nstatic inline MCSubtargetInfo *create" << Target 1839 << "MCSubtargetInfoImpl(" 1840 << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; 1841 OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, "; 1842 if (NumFeatures) 1843 OS << Target << "FeatureKV, "; 1844 else 1845 OS << "None, "; 1846 if (NumProcs) 1847 OS << Target << "SubTypeKV, "; 1848 else 1849 OS << "None, "; 1850 OS << '\n'; OS.indent(22); 1851 OS << Target << "ProcSchedKV, " 1852 << Target << "WriteProcResTable, " 1853 << Target << "WriteLatencyTable, " 1854 << Target << "ReadAdvanceTable, "; 1855 OS << '\n'; OS.indent(22); 1856 if (SchedModels.hasItineraries()) { 1857 OS << Target << "Stages, " 1858 << Target << "OperandCycles, " 1859 << Target << "ForwardingPaths"; 1860 } else 1861 OS << "nullptr, nullptr, nullptr"; 1862 OS << ");\n}\n\n"; 1863 1864 OS << "} // end namespace llvm\n\n"; 1865 1866 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; 1867 1868 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; 1869 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n"; 1870 1871 OS << "#include \"llvm/Support/Debug.h\"\n"; 1872 OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; 1873 ParseFeaturesFunction(OS, NumFeatures, NumProcs); 1874 1875 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; 1876 1877 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. 1878 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; 1879 OS << "#undef GET_SUBTARGETINFO_HEADER\n\n"; 1880 1881 std::string ClassName = Target + "GenSubtargetInfo"; 1882 OS << "namespace llvm {\n"; 1883 OS << "class DFAPacketizer;\n"; 1884 OS << "namespace " << Target << "_MC {\n" 1885 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," 1886 << " const MCInst *MI, unsigned CPUID);\n" 1887 << "}\n\n"; 1888 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" 1889 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " 1890 << "StringRef FS);\n" 1891 << "public:\n" 1892 << " unsigned resolveSchedClass(unsigned SchedClass, " 1893 << " const MachineInstr *DefMI," 1894 << " const TargetSchedModel *SchedModel) const override;\n" 1895 << " unsigned resolveVariantSchedClass(unsigned SchedClass," 1896 << " const MCInst *MI, unsigned CPUID) const override;\n" 1897 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" 1898 << " const;\n"; 1899 if (TGT.getHwModes().getNumModeIds() > 1) 1900 OS << " unsigned getHwMode() const override;\n"; 1901 1902 STIPredicateExpander PE(Target); 1903 PE.setByRef(false); 1904 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) 1905 PE.expandSTIPredicate(OS, Fn); 1906 1907 OS << "};\n" 1908 << "} // end namespace llvm\n\n"; 1909 1910 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; 1911 1912 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; 1913 OS << "#undef GET_SUBTARGETINFO_CTOR\n\n"; 1914 1915 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; 1916 OS << "namespace llvm {\n"; 1917 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; 1918 OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; 1919 OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; 1920 OS << "extern const llvm::MCWriteProcResEntry " 1921 << Target << "WriteProcResTable[];\n"; 1922 OS << "extern const llvm::MCWriteLatencyEntry " 1923 << Target << "WriteLatencyTable[];\n"; 1924 OS << "extern const llvm::MCReadAdvanceEntry " 1925 << Target << "ReadAdvanceTable[];\n"; 1926 1927 if (SchedModels.hasItineraries()) { 1928 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; 1929 OS << "extern const unsigned " << Target << "OperandCycles[];\n"; 1930 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; 1931 } 1932 1933 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " 1934 << "StringRef FS)\n" 1935 << " : TargetSubtargetInfo(TT, CPU, FS, "; 1936 if (NumFeatures) 1937 OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; 1938 else 1939 OS << "None, "; 1940 if (NumProcs) 1941 OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; 1942 else 1943 OS << "None, "; 1944 OS << '\n'; OS.indent(24); 1945 OS << Target << "ProcSchedKV, " 1946 << Target << "WriteProcResTable, " 1947 << Target << "WriteLatencyTable, " 1948 << Target << "ReadAdvanceTable, "; 1949 OS << '\n'; OS.indent(24); 1950 if (SchedModels.hasItineraries()) { 1951 OS << Target << "Stages, " 1952 << Target << "OperandCycles, " 1953 << Target << "ForwardingPaths"; 1954 } else 1955 OS << "nullptr, nullptr, nullptr"; 1956 OS << ") {}\n\n"; 1957 1958 EmitSchedModelHelpers(ClassName, OS); 1959 EmitHwModeCheck(ClassName, OS); 1960 1961 OS << "} // end namespace llvm\n\n"; 1962 1963 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; 1964 1965 EmitMCInstrAnalysisPredicateFunctions(OS); 1966 } 1967 1968 namespace llvm { 1969 1970 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { 1971 CodeGenTarget CGTarget(RK); 1972 SubtargetEmitter(RK, CGTarget).run(OS); 1973 } 1974 1975 } // end namespace llvm 1976