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 "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/StringExtras.h" 18 #include "llvm/MC/MCInstrItineraries.h" 19 #include "llvm/MC/SubtargetFeature.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/Format.h" 22 #include "llvm/TableGen/Error.h" 23 #include "llvm/TableGen/Record.h" 24 #include "llvm/TableGen/TableGenBackend.h" 25 #include <algorithm> 26 #include <map> 27 #include <string> 28 #include <vector> 29 30 using namespace llvm; 31 32 #define DEBUG_TYPE "subtarget-emitter" 33 34 namespace { 35 class SubtargetEmitter { 36 // Each processor has a SchedClassDesc table with an entry for each SchedClass. 37 // The SchedClassDesc table indexes into a global write resource table, write 38 // latency table, and read advance table. 39 struct SchedClassTables { 40 std::vector<std::vector<MCSchedClassDesc> > ProcSchedClasses; 41 std::vector<MCWriteProcResEntry> WriteProcResources; 42 std::vector<MCWriteLatencyEntry> WriteLatencies; 43 std::vector<std::string> WriterNames; 44 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 45 46 // Reserve an invalid entry at index 0 47 SchedClassTables() { 48 ProcSchedClasses.resize(1); 49 WriteProcResources.resize(1); 50 WriteLatencies.resize(1); 51 WriterNames.push_back("InvalidWrite"); 52 ReadAdvanceEntries.resize(1); 53 } 54 }; 55 56 struct LessWriteProcResources { 57 bool operator()(const MCWriteProcResEntry &LHS, 58 const MCWriteProcResEntry &RHS) { 59 return LHS.ProcResourceIdx < RHS.ProcResourceIdx; 60 } 61 }; 62 63 RecordKeeper &Records; 64 CodeGenSchedModels &SchedModels; 65 std::string Target; 66 67 void Enumeration(raw_ostream &OS); 68 unsigned FeatureKeyValues(raw_ostream &OS); 69 unsigned CPUKeyValues(raw_ostream &OS); 70 void FormItineraryStageString(const std::string &Names, 71 Record *ItinData, std::string &ItinString, 72 unsigned &NStages); 73 void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, 74 unsigned &NOperandCycles); 75 void FormItineraryBypassString(const std::string &Names, 76 Record *ItinData, 77 std::string &ItinString, unsigned NOperandCycles); 78 void EmitStageAndOperandCycleData(raw_ostream &OS, 79 std::vector<std::vector<InstrItinerary> > 80 &ProcItinLists); 81 void EmitItineraries(raw_ostream &OS, 82 std::vector<std::vector<InstrItinerary> > 83 &ProcItinLists); 84 void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name, 85 char Separator); 86 void EmitProcessorResources(const CodeGenProcModel &ProcModel, 87 raw_ostream &OS); 88 Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, 89 const CodeGenProcModel &ProcModel); 90 Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, 91 const CodeGenProcModel &ProcModel); 92 void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, 93 const CodeGenProcModel &ProcModel); 94 void GenSchedClassTables(const CodeGenProcModel &ProcModel, 95 SchedClassTables &SchedTables); 96 void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); 97 void EmitProcessorModels(raw_ostream &OS); 98 void EmitProcessorLookup(raw_ostream &OS); 99 void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS); 100 void EmitSchedModel(raw_ostream &OS); 101 void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, 102 unsigned NumProcs); 103 104 public: 105 SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT): 106 Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {} 107 108 void run(raw_ostream &o); 109 }; 110 } // end anonymous namespace 111 112 // 113 // Enumeration - Emit the specified class as an enumeration. 114 // 115 void SubtargetEmitter::Enumeration(raw_ostream &OS) { 116 // Get all records of class and sort 117 std::vector<Record*> DefList = 118 Records.getAllDerivedDefinitions("SubtargetFeature"); 119 std::sort(DefList.begin(), DefList.end(), LessRecord()); 120 121 unsigned N = DefList.size(); 122 if (N == 0) 123 return; 124 if (N > MAX_SUBTARGET_FEATURES) 125 PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); 126 127 OS << "namespace " << Target << " {\n"; 128 129 // Open enumeration. 130 OS << "enum {\n"; 131 132 // For each record 133 for (unsigned i = 0; i < N;) { 134 // Next record 135 Record *Def = DefList[i]; 136 137 // Get and emit name 138 OS << " " << Def->getName() << " = " << i; 139 if (++i < N) OS << ","; 140 141 OS << "\n"; 142 } 143 144 // Close enumeration and namespace 145 OS << "};\n}\n"; 146 } 147 148 // 149 // FeatureKeyValues - Emit data of all the subtarget features. Used by the 150 // command line. 151 // 152 unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) { 153 // Gather and sort all the features 154 std::vector<Record*> FeatureList = 155 Records.getAllDerivedDefinitions("SubtargetFeature"); 156 157 if (FeatureList.empty()) 158 return 0; 159 160 std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName()); 161 162 // Begin feature table 163 OS << "// Sorted (by key) array of values for CPU features.\n" 164 << "extern const llvm::SubtargetFeatureKV " << Target 165 << "FeatureKV[] = {\n"; 166 167 // For each feature 168 unsigned NumFeatures = 0; 169 for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) { 170 // Next feature 171 Record *Feature = FeatureList[i]; 172 173 const std::string &Name = Feature->getName(); 174 const std::string &CommandLineName = Feature->getValueAsString("Name"); 175 const std::string &Desc = Feature->getValueAsString("Desc"); 176 177 if (CommandLineName.empty()) continue; 178 179 // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } } 180 OS << " { " 181 << "\"" << CommandLineName << "\", " 182 << "\"" << Desc << "\", " 183 << "{ " << Target << "::" << Name << " }, "; 184 185 const std::vector<Record*> &ImpliesList = 186 Feature->getValueAsListOfDefs("Implies"); 187 188 OS << "{"; 189 for (unsigned j = 0, M = ImpliesList.size(); j < M;) { 190 OS << " " << Target << "::" << ImpliesList[j]->getName(); 191 if (++j < M) OS << ","; 192 } 193 OS << " }"; 194 195 OS << " }"; 196 ++NumFeatures; 197 198 // Depending on 'if more in the list' emit comma 199 if ((i + 1) < N) OS << ","; 200 201 OS << "\n"; 202 } 203 204 // End feature table 205 OS << "};\n"; 206 207 return NumFeatures; 208 } 209 210 // 211 // CPUKeyValues - Emit data of all the subtarget processors. Used by command 212 // line. 213 // 214 unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { 215 // Gather and sort processor information 216 std::vector<Record*> ProcessorList = 217 Records.getAllDerivedDefinitions("Processor"); 218 std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); 219 220 // Begin processor table 221 OS << "// Sorted (by key) array of values for CPU subtype.\n" 222 << "extern const llvm::SubtargetFeatureKV " << Target 223 << "SubTypeKV[] = {\n"; 224 225 // For each processor 226 for (unsigned i = 0, N = ProcessorList.size(); i < N;) { 227 // Next processor 228 Record *Processor = ProcessorList[i]; 229 230 const std::string &Name = Processor->getValueAsString("Name"); 231 const std::vector<Record*> &FeatureList = 232 Processor->getValueAsListOfDefs("Features"); 233 234 // Emit as { "cpu", "description", { f1 , f2 , ... fn } }, 235 OS << " { " 236 << "\"" << Name << "\", " 237 << "\"Select the " << Name << " processor\", "; 238 239 OS << "{"; 240 for (unsigned j = 0, M = FeatureList.size(); j < M;) { 241 OS << " " << Target << "::" << FeatureList[j]->getName(); 242 if (++j < M) OS << ","; 243 } 244 OS << " }"; 245 246 // The { } is for the "implies" section of this data structure. 247 OS << ", { } }"; 248 249 // Depending on 'if more in the list' emit comma 250 if (++i < N) OS << ","; 251 252 OS << "\n"; 253 } 254 255 // End processor table 256 OS << "};\n"; 257 258 return ProcessorList.size(); 259 } 260 261 // 262 // FormItineraryStageString - Compose a string containing the stage 263 // data initialization for the specified itinerary. N is the number 264 // of stages. 265 // 266 void SubtargetEmitter::FormItineraryStageString(const std::string &Name, 267 Record *ItinData, 268 std::string &ItinString, 269 unsigned &NStages) { 270 // Get states list 271 const std::vector<Record*> &StageList = 272 ItinData->getValueAsListOfDefs("Stages"); 273 274 // For each stage 275 unsigned N = NStages = StageList.size(); 276 for (unsigned i = 0; i < N;) { 277 // Next stage 278 const Record *Stage = StageList[i]; 279 280 // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind } 281 int Cycles = Stage->getValueAsInt("Cycles"); 282 ItinString += " { " + itostr(Cycles) + ", "; 283 284 // Get unit list 285 const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units"); 286 287 // For each unit 288 for (unsigned j = 0, M = UnitList.size(); j < M;) { 289 // Add name and bitwise or 290 ItinString += Name + "FU::" + UnitList[j]->getName(); 291 if (++j < M) ItinString += " | "; 292 } 293 294 int TimeInc = Stage->getValueAsInt("TimeInc"); 295 ItinString += ", " + itostr(TimeInc); 296 297 int Kind = Stage->getValueAsInt("Kind"); 298 ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind); 299 300 // Close off stage 301 ItinString += " }"; 302 if (++i < N) ItinString += ", "; 303 } 304 } 305 306 // 307 // FormItineraryOperandCycleString - Compose a string containing the 308 // operand cycle initialization for the specified itinerary. N is the 309 // number of operands that has cycles specified. 310 // 311 void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, 312 std::string &ItinString, unsigned &NOperandCycles) { 313 // Get operand cycle list 314 const std::vector<int64_t> &OperandCycleList = 315 ItinData->getValueAsListOfInts("OperandCycles"); 316 317 // For each operand cycle 318 unsigned N = NOperandCycles = OperandCycleList.size(); 319 for (unsigned i = 0; i < N;) { 320 // Next operand cycle 321 const int OCycle = OperandCycleList[i]; 322 323 ItinString += " " + itostr(OCycle); 324 if (++i < N) ItinString += ", "; 325 } 326 } 327 328 void SubtargetEmitter::FormItineraryBypassString(const std::string &Name, 329 Record *ItinData, 330 std::string &ItinString, 331 unsigned NOperandCycles) { 332 const std::vector<Record*> &BypassList = 333 ItinData->getValueAsListOfDefs("Bypasses"); 334 unsigned N = BypassList.size(); 335 unsigned i = 0; 336 for (; i < N;) { 337 ItinString += Name + "Bypass::" + BypassList[i]->getName(); 338 if (++i < NOperandCycles) ItinString += ", "; 339 } 340 for (; i < NOperandCycles;) { 341 ItinString += " 0"; 342 if (++i < NOperandCycles) ItinString += ", "; 343 } 344 } 345 346 // 347 // EmitStageAndOperandCycleData - Generate unique itinerary stages and operand 348 // cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed 349 // by CodeGenSchedClass::Index. 350 // 351 void SubtargetEmitter:: 352 EmitStageAndOperandCycleData(raw_ostream &OS, 353 std::vector<std::vector<InstrItinerary> > 354 &ProcItinLists) { 355 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 std::vector<Record*> FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); 366 if (FUs.empty()) 367 continue; 368 369 const std::string &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 << "}\n"; 378 379 std::vector<Record*> BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); 380 if (!BPs.empty()) { 381 OS << "\n// Pipeline forwarding pathes 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 << "}\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 pipepine bypess 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 const std::string &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 unsigned 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 unsigned 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 int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; 492 InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, 493 FindOperandCycle, 494 FindOperandCycle + NOperandCycles}; 495 496 // Inject - empty slots will be 0, 0 497 ItinList[SchedClassIdx] = Intinerary; 498 } 499 } 500 501 // Closing stage 502 StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n"; 503 StageTable += "};\n"; 504 505 // Closing operand cycles 506 OperandCycleTable += " 0 // End operand cycles\n"; 507 OperandCycleTable += "};\n"; 508 509 BypassTable += " 0 // End bypass tables\n"; 510 BypassTable += "};\n"; 511 512 // Emit tables. 513 OS << StageTable; 514 OS << OperandCycleTable; 515 OS << BypassTable; 516 } 517 518 // 519 // EmitProcessorData - Generate data for processor itineraries that were 520 // computed during EmitStageAndOperandCycleData(). ProcItinLists lists all 521 // Itineraries for each processor. The Itinerary lists are indexed on 522 // CodeGenSchedClass::Index. 523 // 524 void SubtargetEmitter:: 525 EmitItineraries(raw_ostream &OS, 526 std::vector<std::vector<InstrItinerary> > &ProcItinLists) { 527 528 // Multiple processor models may share an itinerary record. Emit it once. 529 SmallPtrSet<Record*, 8> ItinsDefSet; 530 531 // For each processor's machine model 532 std::vector<std::vector<InstrItinerary> >::iterator 533 ProcItinListsIter = ProcItinLists.begin(); 534 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 535 PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) { 536 537 Record *ItinsDef = PI->ItinsDef; 538 if (!ItinsDefSet.insert(ItinsDef).second) 539 continue; 540 541 // Get processor itinerary name 542 const std::string &Name = ItinsDef->getName(); 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 << Name << "[] = {\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, ~0U, ~0U, ~0U, ~0U } // end marker\n"; 575 OS << "};\n"; 576 } 577 } 578 579 // Emit either the value defined in the TableGen Record, or the default 580 // value defined in the C++ header. The Record is null if the processor does not 581 // define a model. 582 void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, 583 const char *Name, char Separator) { 584 OS << " "; 585 int V = R ? R->getValueAsInt(Name) : -1; 586 if (V >= 0) 587 OS << V << Separator << " // " << Name; 588 else 589 OS << "MCSchedModel::Default" << Name << Separator; 590 OS << '\n'; 591 } 592 593 void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, 594 raw_ostream &OS) { 595 char Sep = ProcModel.ProcResourceDefs.empty() ? ' ' : ','; 596 597 OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n"; 598 OS << "static const llvm::MCProcResourceDesc " 599 << ProcModel.ModelName << "ProcResources" << "[] = {\n" 600 << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0}" << Sep << "\n"; 601 602 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { 603 Record *PRDef = ProcModel.ProcResourceDefs[i]; 604 605 Record *SuperDef = nullptr; 606 unsigned SuperIdx = 0; 607 unsigned NumUnits = 0; 608 int BufferSize = PRDef->getValueAsInt("BufferSize"); 609 if (PRDef->isSubClassOf("ProcResGroup")) { 610 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); 611 for (Record *RU : ResUnits) { 612 NumUnits += RU->getValueAsInt("NumUnits"); 613 } 614 } 615 else { 616 // Find the SuperIdx 617 if (PRDef->getValueInit("Super")->isComplete()) { 618 SuperDef = SchedModels.findProcResUnits( 619 PRDef->getValueAsDef("Super"), ProcModel); 620 SuperIdx = ProcModel.getProcResourceIdx(SuperDef); 621 } 622 NumUnits = PRDef->getValueAsInt("NumUnits"); 623 } 624 // Emit the ProcResourceDesc 625 if (i+1 == e) 626 Sep = ' '; 627 OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; 628 if (PRDef->getName().size() < 15) 629 OS.indent(15 - PRDef->getName().size()); 630 OS << NumUnits << ", " << SuperIdx << ", " 631 << BufferSize << "}" << Sep << " // #" << i+1; 632 if (SuperDef) 633 OS << ", Super=" << SuperDef->getName(); 634 OS << "\n"; 635 } 636 OS << "};\n"; 637 } 638 639 // Find the WriteRes Record that defines processor resources for this 640 // SchedWrite. 641 Record *SubtargetEmitter::FindWriteResources( 642 const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { 643 644 // Check if the SchedWrite is already subtarget-specific and directly 645 // specifies a set of processor resources. 646 if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) 647 return SchedWrite.TheDef; 648 649 Record *AliasDef = nullptr; 650 for (Record *A : SchedWrite.Aliases) { 651 const CodeGenSchedRW &AliasRW = 652 SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); 653 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 654 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 655 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 656 continue; 657 } 658 if (AliasDef) 659 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 660 "defined for processor " + ProcModel.ModelName + 661 " Ensure only one SchedAlias exists per RW."); 662 AliasDef = AliasRW.TheDef; 663 } 664 if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) 665 return AliasDef; 666 667 // Check this processor's list of write resources. 668 Record *ResDef = nullptr; 669 for (Record *WR : ProcModel.WriteResDefs) { 670 if (!WR->isSubClassOf("WriteRes")) 671 continue; 672 if (AliasDef == WR->getValueAsDef("WriteType") 673 || SchedWrite.TheDef == WR->getValueAsDef("WriteType")) { 674 if (ResDef) { 675 PrintFatalError(WR->getLoc(), "Resources are defined for both " 676 "SchedWrite and its alias on processor " + 677 ProcModel.ModelName); 678 } 679 ResDef = WR; 680 } 681 } 682 // TODO: If ProcModel has a base model (previous generation processor), 683 // then call FindWriteResources recursively with that model here. 684 if (!ResDef) { 685 PrintFatalError(ProcModel.ModelDef->getLoc(), 686 std::string("Processor does not define resources for ") 687 + SchedWrite.TheDef->getName()); 688 } 689 return ResDef; 690 } 691 692 /// Find the ReadAdvance record for the given SchedRead on this processor or 693 /// return NULL. 694 Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, 695 const CodeGenProcModel &ProcModel) { 696 // Check for SchedReads that directly specify a ReadAdvance. 697 if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) 698 return SchedRead.TheDef; 699 700 // Check this processor's list of aliases for SchedRead. 701 Record *AliasDef = nullptr; 702 for (Record *A : SchedRead.Aliases) { 703 const CodeGenSchedRW &AliasRW = 704 SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); 705 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 706 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 707 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 708 continue; 709 } 710 if (AliasDef) 711 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 712 "defined for processor " + ProcModel.ModelName + 713 " Ensure only one SchedAlias exists per RW."); 714 AliasDef = AliasRW.TheDef; 715 } 716 if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) 717 return AliasDef; 718 719 // Check this processor's ReadAdvanceList. 720 Record *ResDef = nullptr; 721 for (Record *RA : ProcModel.ReadAdvanceDefs) { 722 if (!RA->isSubClassOf("ReadAdvance")) 723 continue; 724 if (AliasDef == RA->getValueAsDef("ReadType") 725 || SchedRead.TheDef == RA->getValueAsDef("ReadType")) { 726 if (ResDef) { 727 PrintFatalError(RA->getLoc(), "Resources are defined for both " 728 "SchedRead and its alias on processor " + 729 ProcModel.ModelName); 730 } 731 ResDef = RA; 732 } 733 } 734 // TODO: If ProcModel has a base model (previous generation processor), 735 // then call FindReadAdvance recursively with that model here. 736 if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { 737 PrintFatalError(ProcModel.ModelDef->getLoc(), 738 std::string("Processor does not define resources for ") 739 + SchedRead.TheDef->getName()); 740 } 741 return ResDef; 742 } 743 744 // Expand an explicit list of processor resources into a full list of implied 745 // resource groups and super resources that cover them. 746 void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, 747 std::vector<int64_t> &Cycles, 748 const CodeGenProcModel &PM) { 749 // Default to 1 resource cycle. 750 Cycles.resize(PRVec.size(), 1); 751 for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { 752 Record *PRDef = PRVec[i]; 753 RecVec SubResources; 754 if (PRDef->isSubClassOf("ProcResGroup")) 755 SubResources = PRDef->getValueAsListOfDefs("Resources"); 756 else { 757 SubResources.push_back(PRDef); 758 PRDef = SchedModels.findProcResUnits(PRVec[i], PM); 759 for (Record *SubDef = PRDef; 760 SubDef->getValueInit("Super")->isComplete();) { 761 if (SubDef->isSubClassOf("ProcResGroup")) { 762 // Disallow this for simplicitly. 763 PrintFatalError(SubDef->getLoc(), "Processor resource group " 764 " cannot be a super resources."); 765 } 766 Record *SuperDef = 767 SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM); 768 PRVec.push_back(SuperDef); 769 Cycles.push_back(Cycles[i]); 770 SubDef = SuperDef; 771 } 772 } 773 for (Record *PR : PM.ProcResourceDefs) { 774 if (PR == PRDef || !PR->isSubClassOf("ProcResGroup")) 775 continue; 776 RecVec SuperResources = PR->getValueAsListOfDefs("Resources"); 777 RecIter SubI = SubResources.begin(), SubE = SubResources.end(); 778 for( ; SubI != SubE; ++SubI) { 779 if (std::find(SuperResources.begin(), SuperResources.end(), *SubI) 780 == SuperResources.end()) { 781 break; 782 } 783 } 784 if (SubI == SubE) { 785 PRVec.push_back(PR); 786 Cycles.push_back(Cycles[i]); 787 } 788 } 789 } 790 } 791 792 // Generate the SchedClass table for this processor and update global 793 // tables. Must be called for each processor in order. 794 void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, 795 SchedClassTables &SchedTables) { 796 SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1); 797 if (!ProcModel.hasInstrSchedModel()) 798 return; 799 800 std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); 801 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { 802 DEBUG(SC.dump(&SchedModels)); 803 804 SCTab.resize(SCTab.size() + 1); 805 MCSchedClassDesc &SCDesc = SCTab.back(); 806 // SCDesc.Name is guarded by NDEBUG 807 SCDesc.NumMicroOps = 0; 808 SCDesc.BeginGroup = false; 809 SCDesc.EndGroup = false; 810 SCDesc.WriteProcResIdx = 0; 811 SCDesc.WriteLatencyIdx = 0; 812 SCDesc.ReadAdvanceIdx = 0; 813 814 // A Variant SchedClass has no resources of its own. 815 bool HasVariants = false; 816 for (std::vector<CodeGenSchedTransition>::const_iterator 817 TI = SC.Transitions.begin(), TE = SC.Transitions.end(); 818 TI != TE; ++TI) { 819 if (TI->ProcIndices[0] == 0) { 820 HasVariants = true; 821 break; 822 } 823 IdxIter PIPos = std::find(TI->ProcIndices.begin(), 824 TI->ProcIndices.end(), ProcModel.Index); 825 if (PIPos != TI->ProcIndices.end()) { 826 HasVariants = true; 827 break; 828 } 829 } 830 if (HasVariants) { 831 SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; 832 continue; 833 } 834 835 // Determine if the SchedClass is actually reachable on this processor. If 836 // not don't try to locate the processor resources, it will fail. 837 // If ProcIndices contains 0, this class applies to all processors. 838 assert(!SC.ProcIndices.empty() && "expect at least one procidx"); 839 if (SC.ProcIndices[0] != 0) { 840 IdxIter PIPos = std::find(SC.ProcIndices.begin(), 841 SC.ProcIndices.end(), ProcModel.Index); 842 if (PIPos == SC.ProcIndices.end()) 843 continue; 844 } 845 IdxVec Writes = SC.Writes; 846 IdxVec Reads = SC.Reads; 847 if (!SC.InstRWs.empty()) { 848 // This class has a default ReadWrite list which can be overriden by 849 // InstRW definitions. 850 Record *RWDef = nullptr; 851 for (Record *RW : SC.InstRWs) { 852 Record *RWModelDef = RW->getValueAsDef("SchedModel"); 853 if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { 854 RWDef = RW; 855 break; 856 } 857 } 858 if (RWDef) { 859 Writes.clear(); 860 Reads.clear(); 861 SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), 862 Writes, Reads); 863 } 864 } 865 if (Writes.empty()) { 866 // Check this processor's itinerary class resources. 867 for (Record *I : ProcModel.ItinRWDefs) { 868 RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses"); 869 if (std::find(Matched.begin(), Matched.end(), SC.ItinClassDef) 870 != Matched.end()) { 871 SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"), 872 Writes, Reads); 873 break; 874 } 875 } 876 if (Writes.empty()) { 877 DEBUG(dbgs() << ProcModel.ModelName 878 << " does not have resources for class " << SC.Name << '\n'); 879 } 880 } 881 // Sum resources across all operand writes. 882 std::vector<MCWriteProcResEntry> WriteProcResources; 883 std::vector<MCWriteLatencyEntry> WriteLatencies; 884 std::vector<std::string> WriterNames; 885 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 886 for (unsigned W : Writes) { 887 IdxVec WriteSeq; 888 SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, 889 ProcModel); 890 891 // For each operand, create a latency entry. 892 MCWriteLatencyEntry WLEntry; 893 WLEntry.Cycles = 0; 894 unsigned WriteID = WriteSeq.back(); 895 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); 896 // If this Write is not referenced by a ReadAdvance, don't distinguish it 897 // from other WriteLatency entries. 898 if (!SchedModels.hasReadOfWrite( 899 SchedModels.getSchedWrite(WriteID).TheDef)) { 900 WriteID = 0; 901 } 902 WLEntry.WriteResourceID = WriteID; 903 904 for (unsigned WS : WriteSeq) { 905 906 Record *WriteRes = 907 FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel); 908 909 // Mark the parent class as invalid for unsupported write types. 910 if (WriteRes->getValueAsBit("Unsupported")) { 911 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 912 break; 913 } 914 WLEntry.Cycles += WriteRes->getValueAsInt("Latency"); 915 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps"); 916 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup"); 917 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup"); 918 919 // Create an entry for each ProcResource listed in WriteRes. 920 RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); 921 std::vector<int64_t> Cycles = 922 WriteRes->getValueAsListOfInts("ResourceCycles"); 923 924 ExpandProcResources(PRVec, Cycles, ProcModel); 925 926 for (unsigned PRIdx = 0, PREnd = PRVec.size(); 927 PRIdx != PREnd; ++PRIdx) { 928 MCWriteProcResEntry WPREntry; 929 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); 930 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); 931 WPREntry.Cycles = Cycles[PRIdx]; 932 // If this resource is already used in this sequence, add the current 933 // entry's cycles so that the same resource appears to be used 934 // serially, rather than multiple parallel uses. This is important for 935 // in-order machine where the resource consumption is a hazard. 936 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); 937 for( ; WPRIdx != WPREnd; ++WPRIdx) { 938 if (WriteProcResources[WPRIdx].ProcResourceIdx 939 == WPREntry.ProcResourceIdx) { 940 WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles; 941 break; 942 } 943 } 944 if (WPRIdx == WPREnd) 945 WriteProcResources.push_back(WPREntry); 946 } 947 } 948 WriteLatencies.push_back(WLEntry); 949 } 950 // Create an entry for each operand Read in this SchedClass. 951 // Entries must be sorted first by UseIdx then by WriteResourceID. 952 for (unsigned UseIdx = 0, EndIdx = Reads.size(); 953 UseIdx != EndIdx; ++UseIdx) { 954 Record *ReadAdvance = 955 FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); 956 if (!ReadAdvance) 957 continue; 958 959 // Mark the parent class as invalid for unsupported write types. 960 if (ReadAdvance->getValueAsBit("Unsupported")) { 961 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 962 break; 963 } 964 RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites"); 965 IdxVec WriteIDs; 966 if (ValidWrites.empty()) 967 WriteIDs.push_back(0); 968 else { 969 for (Record *VW : ValidWrites) { 970 WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false)); 971 } 972 } 973 std::sort(WriteIDs.begin(), WriteIDs.end()); 974 for(unsigned W : WriteIDs) { 975 MCReadAdvanceEntry RAEntry; 976 RAEntry.UseIdx = UseIdx; 977 RAEntry.WriteResourceID = W; 978 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); 979 ReadAdvanceEntries.push_back(RAEntry); 980 } 981 } 982 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 983 WriteProcResources.clear(); 984 WriteLatencies.clear(); 985 ReadAdvanceEntries.clear(); 986 } 987 // Add the information for this SchedClass to the global tables using basic 988 // compression. 989 // 990 // WritePrecRes entries are sorted by ProcResIdx. 991 std::sort(WriteProcResources.begin(), WriteProcResources.end(), 992 LessWriteProcResources()); 993 994 SCDesc.NumWriteProcResEntries = WriteProcResources.size(); 995 std::vector<MCWriteProcResEntry>::iterator WPRPos = 996 std::search(SchedTables.WriteProcResources.begin(), 997 SchedTables.WriteProcResources.end(), 998 WriteProcResources.begin(), WriteProcResources.end()); 999 if (WPRPos != SchedTables.WriteProcResources.end()) 1000 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin(); 1001 else { 1002 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size(); 1003 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(), 1004 WriteProcResources.end()); 1005 } 1006 // Latency entries must remain in operand order. 1007 SCDesc.NumWriteLatencyEntries = WriteLatencies.size(); 1008 std::vector<MCWriteLatencyEntry>::iterator WLPos = 1009 std::search(SchedTables.WriteLatencies.begin(), 1010 SchedTables.WriteLatencies.end(), 1011 WriteLatencies.begin(), WriteLatencies.end()); 1012 if (WLPos != SchedTables.WriteLatencies.end()) { 1013 unsigned idx = WLPos - SchedTables.WriteLatencies.begin(); 1014 SCDesc.WriteLatencyIdx = idx; 1015 for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i) 1016 if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) == 1017 std::string::npos) { 1018 SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i]; 1019 } 1020 } 1021 else { 1022 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); 1023 SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), 1024 WriteLatencies.begin(), 1025 WriteLatencies.end()); 1026 SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), 1027 WriterNames.begin(), WriterNames.end()); 1028 } 1029 // ReadAdvanceEntries must remain in operand order. 1030 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); 1031 std::vector<MCReadAdvanceEntry>::iterator RAPos = 1032 std::search(SchedTables.ReadAdvanceEntries.begin(), 1033 SchedTables.ReadAdvanceEntries.end(), 1034 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end()); 1035 if (RAPos != SchedTables.ReadAdvanceEntries.end()) 1036 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); 1037 else { 1038 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); 1039 SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(), 1040 ReadAdvanceEntries.end()); 1041 } 1042 } 1043 } 1044 1045 // Emit SchedClass tables for all processors and associated global tables. 1046 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, 1047 raw_ostream &OS) { 1048 // Emit global WriteProcResTable. 1049 OS << "\n// {ProcResourceIdx, Cycles}\n" 1050 << "extern const llvm::MCWriteProcResEntry " 1051 << Target << "WriteProcResTable[] = {\n" 1052 << " { 0, 0}, // Invalid\n"; 1053 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); 1054 WPRIdx != WPREnd; ++WPRIdx) { 1055 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; 1056 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " 1057 << format("%2d", WPREntry.Cycles) << "}"; 1058 if (WPRIdx + 1 < WPREnd) 1059 OS << ','; 1060 OS << " // #" << WPRIdx << '\n'; 1061 } 1062 OS << "}; // " << Target << "WriteProcResTable\n"; 1063 1064 // Emit global WriteLatencyTable. 1065 OS << "\n// {Cycles, WriteResourceID}\n" 1066 << "extern const llvm::MCWriteLatencyEntry " 1067 << Target << "WriteLatencyTable[] = {\n" 1068 << " { 0, 0}, // Invalid\n"; 1069 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); 1070 WLIdx != WLEnd; ++WLIdx) { 1071 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; 1072 OS << " {" << format("%2d", WLEntry.Cycles) << ", " 1073 << format("%2d", WLEntry.WriteResourceID) << "}"; 1074 if (WLIdx + 1 < WLEnd) 1075 OS << ','; 1076 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; 1077 } 1078 OS << "}; // " << Target << "WriteLatencyTable\n"; 1079 1080 // Emit global ReadAdvanceTable. 1081 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" 1082 << "extern const llvm::MCReadAdvanceEntry " 1083 << Target << "ReadAdvanceTable[] = {\n" 1084 << " {0, 0, 0}, // Invalid\n"; 1085 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); 1086 RAIdx != RAEnd; ++RAIdx) { 1087 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; 1088 OS << " {" << RAEntry.UseIdx << ", " 1089 << format("%2d", RAEntry.WriteResourceID) << ", " 1090 << format("%2d", RAEntry.Cycles) << "}"; 1091 if (RAIdx + 1 < RAEnd) 1092 OS << ','; 1093 OS << " // #" << RAIdx << '\n'; 1094 } 1095 OS << "}; // " << Target << "ReadAdvanceTable\n"; 1096 1097 // Emit a SchedClass table for each processor. 1098 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1099 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1100 if (!PI->hasInstrSchedModel()) 1101 continue; 1102 1103 std::vector<MCSchedClassDesc> &SCTab = 1104 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; 1105 1106 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup," 1107 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; 1108 OS << "static const llvm::MCSchedClassDesc " 1109 << PI->ModelName << "SchedClasses[] = {\n"; 1110 1111 // The first class is always invalid. We no way to distinguish it except by 1112 // name and position. 1113 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" 1114 && "invalid class not first"); 1115 OS << " {DBGFIELD(\"InvalidSchedClass\") " 1116 << MCSchedClassDesc::InvalidNumMicroOps 1117 << ", 0, 0, 0, 0, 0, 0, 0, 0},\n"; 1118 1119 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { 1120 MCSchedClassDesc &MCDesc = SCTab[SCIdx]; 1121 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); 1122 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; 1123 if (SchedClass.Name.size() < 18) 1124 OS.indent(18 - SchedClass.Name.size()); 1125 OS << MCDesc.NumMicroOps 1126 << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup 1127 << ", " << format("%2d", MCDesc.WriteProcResIdx) 1128 << ", " << MCDesc.NumWriteProcResEntries 1129 << ", " << format("%2d", MCDesc.WriteLatencyIdx) 1130 << ", " << MCDesc.NumWriteLatencyEntries 1131 << ", " << format("%2d", MCDesc.ReadAdvanceIdx) 1132 << ", " << MCDesc.NumReadAdvanceEntries << "}"; 1133 if (SCIdx + 1 < SCEnd) 1134 OS << ','; 1135 OS << " // #" << SCIdx << '\n'; 1136 } 1137 OS << "}; // " << PI->ModelName << "SchedClasses\n"; 1138 } 1139 } 1140 1141 void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { 1142 // For each processor model. 1143 for (const CodeGenProcModel &PM : SchedModels.procModels()) { 1144 // Emit processor resource table. 1145 if (PM.hasInstrSchedModel()) 1146 EmitProcessorResources(PM, OS); 1147 else if(!PM.ProcResourceDefs.empty()) 1148 PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines " 1149 "ProcResources without defining WriteRes SchedWriteRes"); 1150 1151 // Begin processor itinerary properties 1152 OS << "\n"; 1153 OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n"; 1154 EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ','); 1155 EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ','); 1156 EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ','); 1157 EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ','); 1158 EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ','); 1159 EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ','); 1160 1161 OS << " " << (bool)(PM.ModelDef ? 1162 PM.ModelDef->getValueAsBit("PostRAScheduler") : 0) 1163 << ", // " << "PostRAScheduler\n"; 1164 1165 OS << " " << (bool)(PM.ModelDef ? 1166 PM.ModelDef->getValueAsBit("CompleteModel") : 0) 1167 << ", // " << "CompleteModel\n"; 1168 1169 OS << " " << PM.Index << ", // Processor ID\n"; 1170 if (PM.hasInstrSchedModel()) 1171 OS << " " << PM.ModelName << "ProcResources" << ",\n" 1172 << " " << PM.ModelName << "SchedClasses" << ",\n" 1173 << " " << PM.ProcResourceDefs.size()+1 << ",\n" 1174 << " " << (SchedModels.schedClassEnd() 1175 - SchedModels.schedClassBegin()) << ",\n"; 1176 else 1177 OS << " nullptr, nullptr, 0, 0," 1178 << " // No instruction-level machine model.\n"; 1179 if (PM.hasItineraries()) 1180 OS << " " << PM.ItinsDef->getName() << "};\n"; 1181 else 1182 OS << " nullptr}; // No Itinerary\n"; 1183 } 1184 } 1185 1186 // 1187 // EmitProcessorLookup - generate cpu name to itinerary lookup table. 1188 // 1189 void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { 1190 // Gather and sort processor information 1191 std::vector<Record*> ProcessorList = 1192 Records.getAllDerivedDefinitions("Processor"); 1193 std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); 1194 1195 // Begin processor table 1196 OS << "\n"; 1197 OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" 1198 << "extern const llvm::SubtargetInfoKV " 1199 << Target << "ProcSchedKV[] = {\n"; 1200 1201 // For each processor 1202 for (unsigned i = 0, N = ProcessorList.size(); i < N;) { 1203 // Next processor 1204 Record *Processor = ProcessorList[i]; 1205 1206 const std::string &Name = Processor->getValueAsString("Name"); 1207 const std::string &ProcModelName = 1208 SchedModels.getModelForProc(Processor).ModelName; 1209 1210 // Emit as { "cpu", procinit }, 1211 OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " }"; 1212 1213 // Depending on ''if more in the list'' emit comma 1214 if (++i < N) OS << ","; 1215 1216 OS << "\n"; 1217 } 1218 1219 // End processor table 1220 OS << "};\n"; 1221 } 1222 1223 // 1224 // EmitSchedModel - Emits all scheduling model tables, folding common patterns. 1225 // 1226 void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { 1227 OS << "#ifdef DBGFIELD\n" 1228 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" 1229 << "#endif\n" 1230 << "#ifndef NDEBUG\n" 1231 << "#define DBGFIELD(x) x,\n" 1232 << "#else\n" 1233 << "#define DBGFIELD(x)\n" 1234 << "#endif\n"; 1235 1236 if (SchedModels.hasItineraries()) { 1237 std::vector<std::vector<InstrItinerary> > ProcItinLists; 1238 // Emit the stage data 1239 EmitStageAndOperandCycleData(OS, ProcItinLists); 1240 EmitItineraries(OS, ProcItinLists); 1241 } 1242 OS << "\n// ===============================================================\n" 1243 << "// Data tables for the new per-operand machine model.\n"; 1244 1245 SchedClassTables SchedTables; 1246 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { 1247 GenSchedClassTables(ProcModel, SchedTables); 1248 } 1249 EmitSchedClassTables(SchedTables, OS); 1250 1251 // Emit the processor machine model 1252 EmitProcessorModels(OS); 1253 // Emit the processor lookup data 1254 EmitProcessorLookup(OS); 1255 1256 OS << "#undef DBGFIELD"; 1257 } 1258 1259 void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, 1260 raw_ostream &OS) { 1261 OS << "unsigned " << ClassName 1262 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," 1263 << " const TargetSchedModel *SchedModel) const {\n"; 1264 1265 std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); 1266 std::sort(Prologs.begin(), Prologs.end(), LessRecord()); 1267 for (Record *P : Prologs) { 1268 OS << P->getValueAsString("Code") << '\n'; 1269 } 1270 IdxVec VariantClasses; 1271 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { 1272 if (SC.Transitions.empty()) 1273 continue; 1274 VariantClasses.push_back(SC.Index); 1275 } 1276 if (!VariantClasses.empty()) { 1277 OS << " switch (SchedClass) {\n"; 1278 for (unsigned VC : VariantClasses) { 1279 const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); 1280 OS << " case " << VC << ": // " << SC.Name << '\n'; 1281 IdxVec ProcIndices; 1282 for (const CodeGenSchedTransition &T : SC.Transitions) { 1283 IdxVec PI; 1284 std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), 1285 ProcIndices.begin(), ProcIndices.end(), 1286 std::back_inserter(PI)); 1287 ProcIndices.swap(PI); 1288 } 1289 for (unsigned PI : ProcIndices) { 1290 OS << " "; 1291 if (PI != 0) 1292 OS << "if (SchedModel->getProcessorID() == " << PI << ") "; 1293 OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName 1294 << '\n'; 1295 for (const CodeGenSchedTransition &T : SC.Transitions) { 1296 if (PI != 0 && !std::count(T.ProcIndices.begin(), 1297 T.ProcIndices.end(), PI)) { 1298 continue; 1299 } 1300 OS << " if ("; 1301 for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end(); 1302 RI != RE; ++RI) { 1303 if (RI != T.PredTerm.begin()) 1304 OS << "\n && "; 1305 OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; 1306 } 1307 OS << ")\n" 1308 << " return " << T.ToClassIdx << "; // " 1309 << SchedModels.getSchedClass(T.ToClassIdx).Name << '\n'; 1310 } 1311 OS << " }\n"; 1312 if (PI == 0) 1313 break; 1314 } 1315 if (SC.isInferred()) 1316 OS << " return " << SC.Index << ";\n"; 1317 OS << " break;\n"; 1318 } 1319 OS << " };\n"; 1320 } 1321 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" 1322 << "} // " << ClassName << "::resolveSchedClass\n"; 1323 } 1324 1325 // 1326 // ParseFeaturesFunction - Produces a subtarget specific function for parsing 1327 // the subtarget features string. 1328 // 1329 void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, 1330 unsigned NumFeatures, 1331 unsigned NumProcs) { 1332 std::vector<Record*> Features = 1333 Records.getAllDerivedDefinitions("SubtargetFeature"); 1334 std::sort(Features.begin(), Features.end(), LessRecord()); 1335 1336 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" 1337 << "// subtarget options.\n" 1338 << "void llvm::"; 1339 OS << Target; 1340 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" 1341 << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" 1342 << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; 1343 1344 if (Features.empty()) { 1345 OS << "}\n"; 1346 return; 1347 } 1348 1349 OS << " InitMCProcessorInfo(CPU, FS);\n" 1350 << " const FeatureBitset& Bits = getFeatureBits();\n"; 1351 1352 for (Record *R : Features) { 1353 // Next record 1354 const std::string &Instance = R->getName(); 1355 const std::string &Value = R->getValueAsString("Value"); 1356 const std::string &Attribute = R->getValueAsString("Attribute"); 1357 1358 if (Value=="true" || Value=="false") 1359 OS << " if (Bits[" << Target << "::" 1360 << Instance << "]) " 1361 << Attribute << " = " << Value << ";\n"; 1362 else 1363 OS << " if (Bits[" << Target << "::" 1364 << Instance << "] && " 1365 << Attribute << " < " << Value << ") " 1366 << Attribute << " = " << Value << ";\n"; 1367 } 1368 1369 OS << "}\n"; 1370 } 1371 1372 // 1373 // SubtargetEmitter::run - Main subtarget enumeration emitter. 1374 // 1375 void SubtargetEmitter::run(raw_ostream &OS) { 1376 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); 1377 1378 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; 1379 OS << "#undef GET_SUBTARGETINFO_ENUM\n"; 1380 1381 OS << "namespace llvm {\n"; 1382 Enumeration(OS); 1383 OS << "} // end llvm namespace\n"; 1384 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; 1385 1386 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; 1387 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n"; 1388 1389 OS << "namespace llvm {\n"; 1390 #if 0 1391 OS << "namespace {\n"; 1392 #endif 1393 unsigned NumFeatures = FeatureKeyValues(OS); 1394 OS << "\n"; 1395 unsigned NumProcs = CPUKeyValues(OS); 1396 OS << "\n"; 1397 EmitSchedModel(OS); 1398 OS << "\n"; 1399 #if 0 1400 OS << "}\n"; 1401 #endif 1402 1403 // MCInstrInfo initialization routine. 1404 OS << "static inline MCSubtargetInfo *create" << Target 1405 << "MCSubtargetInfoImpl(" 1406 << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; 1407 OS << " return new MCSubtargetInfo(TT, CPU, FS, "; 1408 if (NumFeatures) 1409 OS << Target << "FeatureKV, "; 1410 else 1411 OS << "None, "; 1412 if (NumProcs) 1413 OS << Target << "SubTypeKV, "; 1414 else 1415 OS << "None, "; 1416 OS << '\n'; OS.indent(22); 1417 OS << Target << "ProcSchedKV, " 1418 << Target << "WriteProcResTable, " 1419 << Target << "WriteLatencyTable, " 1420 << Target << "ReadAdvanceTable, "; 1421 if (SchedModels.hasItineraries()) { 1422 OS << '\n'; OS.indent(22); 1423 OS << Target << "Stages, " 1424 << Target << "OperandCycles, " 1425 << Target << "ForwardingPaths"; 1426 } else 1427 OS << "0, 0, 0"; 1428 OS << ");\n}\n\n"; 1429 1430 OS << "} // end llvm namespace\n"; 1431 1432 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; 1433 1434 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; 1435 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n"; 1436 1437 OS << "#include \"llvm/Support/Debug.h\"\n"; 1438 OS << "#include \"llvm/Support/raw_ostream.h\"\n"; 1439 ParseFeaturesFunction(OS, NumFeatures, NumProcs); 1440 1441 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; 1442 1443 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. 1444 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; 1445 OS << "#undef GET_SUBTARGETINFO_HEADER\n"; 1446 1447 std::string ClassName = Target + "GenSubtargetInfo"; 1448 OS << "namespace llvm {\n"; 1449 OS << "class DFAPacketizer;\n"; 1450 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" 1451 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " 1452 << "StringRef FS);\n" 1453 << "public:\n" 1454 << " unsigned resolveSchedClass(unsigned SchedClass, " 1455 << " const MachineInstr *DefMI," 1456 << " const TargetSchedModel *SchedModel) const override;\n" 1457 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" 1458 << " const;\n" 1459 << "};\n"; 1460 OS << "} // end llvm namespace\n"; 1461 1462 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; 1463 1464 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; 1465 OS << "#undef GET_SUBTARGETINFO_CTOR\n"; 1466 1467 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; 1468 OS << "namespace llvm {\n"; 1469 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; 1470 OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; 1471 OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; 1472 OS << "extern const llvm::MCWriteProcResEntry " 1473 << Target << "WriteProcResTable[];\n"; 1474 OS << "extern const llvm::MCWriteLatencyEntry " 1475 << Target << "WriteLatencyTable[];\n"; 1476 OS << "extern const llvm::MCReadAdvanceEntry " 1477 << Target << "ReadAdvanceTable[];\n"; 1478 1479 if (SchedModels.hasItineraries()) { 1480 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; 1481 OS << "extern const unsigned " << Target << "OperandCycles[];\n"; 1482 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; 1483 } 1484 1485 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " 1486 << "StringRef FS)\n" 1487 << " : TargetSubtargetInfo(TT, CPU, FS, "; 1488 if (NumFeatures) 1489 OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; 1490 else 1491 OS << "None, "; 1492 if (NumProcs) 1493 OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; 1494 else 1495 OS << "None, "; 1496 OS << '\n'; OS.indent(24); 1497 OS << Target << "ProcSchedKV, " 1498 << Target << "WriteProcResTable, " 1499 << Target << "WriteLatencyTable, " 1500 << Target << "ReadAdvanceTable, "; 1501 OS << '\n'; OS.indent(24); 1502 if (SchedModels.hasItineraries()) { 1503 OS << Target << "Stages, " 1504 << Target << "OperandCycles, " 1505 << Target << "ForwardingPaths"; 1506 } else 1507 OS << "0, 0, 0"; 1508 OS << ") {}\n\n"; 1509 1510 EmitSchedModelHelpers(ClassName, OS); 1511 1512 OS << "} // end llvm namespace\n"; 1513 1514 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; 1515 } 1516 1517 namespace llvm { 1518 1519 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { 1520 CodeGenTarget CGTarget(RK); 1521 SubtargetEmitter(RK, CGTarget).run(OS); 1522 } 1523 1524 } // end llvm namespace 1525