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 30using namespace llvm; 31 32#define DEBUG_TYPE "subtarget-emitter" 33 34namespace { 35class 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, const char *ClassName); 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 104public: 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// 115void SubtargetEmitter::Enumeration(raw_ostream &OS, 116 const char *ClassName) { 117 // Get all records of class and sort 118 std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName); 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. Use a 64-bit underlying type. 130 OS << "enum : uint64_t {\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// 152unsigned 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// 214unsigned 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// 266void 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// 311void 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 328void 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// 351void SubtargetEmitter:: 352EmitStageAndOperandCycleData(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 (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 361 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 362 363 if (!ItinsDefSet.insert(PI->ItinsDef).second) 364 continue; 365 366 std::vector<Record*> FUs = PI->ItinsDef->getValueAsListOfDefs("FU"); 367 if (FUs.empty()) 368 continue; 369 370 const std::string &Name = PI->ItinsDef->getName(); 371 OS << "\n// Functional units for \"" << Name << "\"\n" 372 << "namespace " << Name << "FU {\n"; 373 374 for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j) 375 OS << " const unsigned " << FUs[j]->getName() 376 << " = 1 << " << j << ";\n"; 377 378 OS << "}\n"; 379 380 std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP"); 381 if (!BPs.empty()) { 382 OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name 383 << "\"\n" << "namespace " << Name << "Bypass {\n"; 384 385 OS << " const unsigned NoBypass = 0;\n"; 386 for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j) 387 OS << " const unsigned " << BPs[j]->getName() 388 << " = 1 << " << j << ";\n"; 389 390 OS << "}\n"; 391 } 392 } 393 394 // Begin stages table 395 std::string StageTable = "\nextern const llvm::InstrStage " + Target + 396 "Stages[] = {\n"; 397 StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n"; 398 399 // Begin operand cycle table 400 std::string OperandCycleTable = "extern const unsigned " + Target + 401 "OperandCycles[] = {\n"; 402 OperandCycleTable += " 0, // No itinerary\n"; 403 404 // Begin pipeline bypass table 405 std::string BypassTable = "extern const unsigned " + Target + 406 "ForwardingPaths[] = {\n"; 407 BypassTable += " 0, // No itinerary\n"; 408 409 // For each Itinerary across all processors, add a unique entry to the stages, 410 // operand cycles, and pipepine bypess tables. Then add the new Itinerary 411 // object with computed offsets to the ProcItinLists result. 412 unsigned StageCount = 1, OperandCycleCount = 1; 413 std::map<std::string, unsigned> ItinStageMap, ItinOperandMap; 414 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 415 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 416 const CodeGenProcModel &ProcModel = *PI; 417 418 // Add process itinerary to the list. 419 ProcItinLists.resize(ProcItinLists.size()+1); 420 421 // If this processor defines no itineraries, then leave the itinerary list 422 // empty. 423 std::vector<InstrItinerary> &ItinList = ProcItinLists.back(); 424 if (!ProcModel.hasItineraries()) 425 continue; 426 427 const std::string &Name = ProcModel.ItinsDef->getName(); 428 429 ItinList.resize(SchedModels.numInstrSchedClasses()); 430 assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); 431 432 for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size(); 433 SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { 434 435 // Next itinerary data 436 Record *ItinData = ProcModel.ItinDefList[SchedClassIdx]; 437 438 // Get string and stage count 439 std::string ItinStageString; 440 unsigned NStages = 0; 441 if (ItinData) 442 FormItineraryStageString(Name, ItinData, ItinStageString, NStages); 443 444 // Get string and operand cycle count 445 std::string ItinOperandCycleString; 446 unsigned NOperandCycles = 0; 447 std::string ItinBypassString; 448 if (ItinData) { 449 FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, 450 NOperandCycles); 451 452 FormItineraryBypassString(Name, ItinData, ItinBypassString, 453 NOperandCycles); 454 } 455 456 // Check to see if stage already exists and create if it doesn't 457 unsigned FindStage = 0; 458 if (NStages > 0) { 459 FindStage = ItinStageMap[ItinStageString]; 460 if (FindStage == 0) { 461 // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices 462 StageTable += ItinStageString + ", // " + itostr(StageCount); 463 if (NStages > 1) 464 StageTable += "-" + itostr(StageCount + NStages - 1); 465 StageTable += "\n"; 466 // Record Itin class number. 467 ItinStageMap[ItinStageString] = FindStage = StageCount; 468 StageCount += NStages; 469 } 470 } 471 472 // Check to see if operand cycle already exists and create if it doesn't 473 unsigned FindOperandCycle = 0; 474 if (NOperandCycles > 0) { 475 std::string ItinOperandString = ItinOperandCycleString+ItinBypassString; 476 FindOperandCycle = ItinOperandMap[ItinOperandString]; 477 if (FindOperandCycle == 0) { 478 // Emit as cycle, // index 479 OperandCycleTable += ItinOperandCycleString + ", // "; 480 std::string OperandIdxComment = itostr(OperandCycleCount); 481 if (NOperandCycles > 1) 482 OperandIdxComment += "-" 483 + itostr(OperandCycleCount + NOperandCycles - 1); 484 OperandCycleTable += OperandIdxComment + "\n"; 485 // Record Itin class number. 486 ItinOperandMap[ItinOperandCycleString] = 487 FindOperandCycle = OperandCycleCount; 488 // Emit as bypass, // index 489 BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n"; 490 OperandCycleCount += NOperandCycles; 491 } 492 } 493 494 // Set up itinerary as location and location + stage count 495 int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; 496 InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, 497 FindOperandCycle, 498 FindOperandCycle + NOperandCycles}; 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// 528void SubtargetEmitter:: 529EmitItineraries(raw_ostream &OS, 530 std::vector<std::vector<InstrItinerary> > &ProcItinLists) { 531 532 // Multiple processor models may share an itinerary record. Emit it once. 533 SmallPtrSet<Record*, 8> ItinsDefSet; 534 535 // For each processor's machine model 536 std::vector<std::vector<InstrItinerary> >::iterator 537 ProcItinListsIter = ProcItinLists.begin(); 538 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 539 PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) { 540 541 Record *ItinsDef = PI->ItinsDef; 542 if (!ItinsDefSet.insert(ItinsDef).second) 543 continue; 544 545 // Get processor itinerary name 546 const std::string &Name = ItinsDef->getName(); 547 548 // Get the itinerary list for the processor. 549 assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator"); 550 std::vector<InstrItinerary> &ItinList = *ProcItinListsIter; 551 552 // Empty itineraries aren't referenced anywhere in the tablegen output 553 // so don't emit them. 554 if (ItinList.empty()) 555 continue; 556 557 OS << "\n"; 558 OS << "static const llvm::InstrItinerary "; 559 560 // Begin processor itinerary table 561 OS << Name << "[] = {\n"; 562 563 // For each itinerary class in CodeGenSchedClass::Index order. 564 for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { 565 InstrItinerary &Intinerary = ItinList[j]; 566 567 // Emit Itinerary in the form of 568 // { firstStage, lastStage, firstCycle, lastCycle } // index 569 OS << " { " << 570 Intinerary.NumMicroOps << ", " << 571 Intinerary.FirstStage << ", " << 572 Intinerary.LastStage << ", " << 573 Intinerary.FirstOperandCycle << ", " << 574 Intinerary.LastOperandCycle << " }" << 575 ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; 576 } 577 // End processor itinerary table 578 OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n"; 579 OS << "};\n"; 580 } 581} 582 583// Emit either the value defined in the TableGen Record, or the default 584// value defined in the C++ header. The Record is null if the processor does not 585// define a model. 586void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, 587 const char *Name, char Separator) { 588 OS << " "; 589 int V = R ? R->getValueAsInt(Name) : -1; 590 if (V >= 0) 591 OS << V << Separator << " // " << Name; 592 else 593 OS << "MCSchedModel::Default" << Name << Separator; 594 OS << '\n'; 595} 596 597void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, 598 raw_ostream &OS) { 599 char Sep = ProcModel.ProcResourceDefs.empty() ? ' ' : ','; 600 601 OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n"; 602 OS << "static const llvm::MCProcResourceDesc " 603 << ProcModel.ModelName << "ProcResources" << "[] = {\n" 604 << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0}" << Sep << "\n"; 605 606 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { 607 Record *PRDef = ProcModel.ProcResourceDefs[i]; 608 609 Record *SuperDef = nullptr; 610 unsigned SuperIdx = 0; 611 unsigned NumUnits = 0; 612 int BufferSize = PRDef->getValueAsInt("BufferSize"); 613 if (PRDef->isSubClassOf("ProcResGroup")) { 614 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); 615 for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end(); 616 RUI != RUE; ++RUI) { 617 NumUnits += (*RUI)->getValueAsInt("NumUnits"); 618 } 619 } 620 else { 621 // Find the SuperIdx 622 if (PRDef->getValueInit("Super")->isComplete()) { 623 SuperDef = SchedModels.findProcResUnits( 624 PRDef->getValueAsDef("Super"), ProcModel); 625 SuperIdx = ProcModel.getProcResourceIdx(SuperDef); 626 } 627 NumUnits = PRDef->getValueAsInt("NumUnits"); 628 } 629 // Emit the ProcResourceDesc 630 if (i+1 == e) 631 Sep = ' '; 632 OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; 633 if (PRDef->getName().size() < 15) 634 OS.indent(15 - PRDef->getName().size()); 635 OS << NumUnits << ", " << SuperIdx << ", " 636 << BufferSize << "}" << Sep << " // #" << i+1; 637 if (SuperDef) 638 OS << ", Super=" << SuperDef->getName(); 639 OS << "\n"; 640 } 641 OS << "};\n"; 642} 643 644// Find the WriteRes Record that defines processor resources for this 645// SchedWrite. 646Record *SubtargetEmitter::FindWriteResources( 647 const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { 648 649 // Check if the SchedWrite is already subtarget-specific and directly 650 // specifies a set of processor resources. 651 if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) 652 return SchedWrite.TheDef; 653 654 Record *AliasDef = nullptr; 655 for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); 656 AI != AE; ++AI) { 657 const CodeGenSchedRW &AliasRW = 658 SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); 659 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 660 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 661 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 662 continue; 663 } 664 if (AliasDef) 665 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 666 "defined for processor " + ProcModel.ModelName + 667 " Ensure only one SchedAlias exists per RW."); 668 AliasDef = AliasRW.TheDef; 669 } 670 if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) 671 return AliasDef; 672 673 // Check this processor's list of write resources. 674 Record *ResDef = nullptr; 675 for (RecIter WRI = ProcModel.WriteResDefs.begin(), 676 WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) { 677 if (!(*WRI)->isSubClassOf("WriteRes")) 678 continue; 679 if (AliasDef == (*WRI)->getValueAsDef("WriteType") 680 || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) { 681 if (ResDef) { 682 PrintFatalError((*WRI)->getLoc(), "Resources are defined for both " 683 "SchedWrite and its alias on processor " + 684 ProcModel.ModelName); 685 } 686 ResDef = *WRI; 687 } 688 } 689 // TODO: If ProcModel has a base model (previous generation processor), 690 // then call FindWriteResources recursively with that model here. 691 if (!ResDef) { 692 PrintFatalError(ProcModel.ModelDef->getLoc(), 693 std::string("Processor does not define resources for ") 694 + SchedWrite.TheDef->getName()); 695 } 696 return ResDef; 697} 698 699/// Find the ReadAdvance record for the given SchedRead on this processor or 700/// return NULL. 701Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, 702 const CodeGenProcModel &ProcModel) { 703 // Check for SchedReads that directly specify a ReadAdvance. 704 if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) 705 return SchedRead.TheDef; 706 707 // Check this processor's list of aliases for SchedRead. 708 Record *AliasDef = nullptr; 709 for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end(); 710 AI != AE; ++AI) { 711 const CodeGenSchedRW &AliasRW = 712 SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); 713 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 714 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 715 if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 716 continue; 717 } 718 if (AliasDef) 719 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 720 "defined for processor " + ProcModel.ModelName + 721 " Ensure only one SchedAlias exists per RW."); 722 AliasDef = AliasRW.TheDef; 723 } 724 if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) 725 return AliasDef; 726 727 // Check this processor's ReadAdvanceList. 728 Record *ResDef = nullptr; 729 for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(), 730 RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) { 731 if (!(*RAI)->isSubClassOf("ReadAdvance")) 732 continue; 733 if (AliasDef == (*RAI)->getValueAsDef("ReadType") 734 || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) { 735 if (ResDef) { 736 PrintFatalError((*RAI)->getLoc(), "Resources are defined for both " 737 "SchedRead and its alias on processor " + 738 ProcModel.ModelName); 739 } 740 ResDef = *RAI; 741 } 742 } 743 // TODO: If ProcModel has a base model (previous generation processor), 744 // then call FindReadAdvance recursively with that model here. 745 if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { 746 PrintFatalError(ProcModel.ModelDef->getLoc(), 747 std::string("Processor does not define resources for ") 748 + SchedRead.TheDef->getName()); 749 } 750 return ResDef; 751} 752 753// Expand an explicit list of processor resources into a full list of implied 754// resource groups and super resources that cover them. 755void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, 756 std::vector<int64_t> &Cycles, 757 const CodeGenProcModel &PM) { 758 // Default to 1 resource cycle. 759 Cycles.resize(PRVec.size(), 1); 760 for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { 761 Record *PRDef = PRVec[i]; 762 RecVec SubResources; 763 if (PRDef->isSubClassOf("ProcResGroup")) 764 SubResources = PRDef->getValueAsListOfDefs("Resources"); 765 else { 766 SubResources.push_back(PRDef); 767 PRDef = SchedModels.findProcResUnits(PRVec[i], PM); 768 for (Record *SubDef = PRDef; 769 SubDef->getValueInit("Super")->isComplete();) { 770 if (SubDef->isSubClassOf("ProcResGroup")) { 771 // Disallow this for simplicitly. 772 PrintFatalError(SubDef->getLoc(), "Processor resource group " 773 " cannot be a super resources."); 774 } 775 Record *SuperDef = 776 SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM); 777 PRVec.push_back(SuperDef); 778 Cycles.push_back(Cycles[i]); 779 SubDef = SuperDef; 780 } 781 } 782 for (RecIter PRI = PM.ProcResourceDefs.begin(), 783 PRE = PM.ProcResourceDefs.end(); 784 PRI != PRE; ++PRI) { 785 if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup")) 786 continue; 787 RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); 788 RecIter SubI = SubResources.begin(), SubE = SubResources.end(); 789 for( ; SubI != SubE; ++SubI) { 790 if (std::find(SuperResources.begin(), SuperResources.end(), *SubI) 791 == SuperResources.end()) { 792 break; 793 } 794 } 795 if (SubI == SubE) { 796 PRVec.push_back(*PRI); 797 Cycles.push_back(Cycles[i]); 798 } 799 } 800 } 801} 802 803// Generate the SchedClass table for this processor and update global 804// tables. Must be called for each processor in order. 805void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, 806 SchedClassTables &SchedTables) { 807 SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1); 808 if (!ProcModel.hasInstrSchedModel()) 809 return; 810 811 std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); 812 for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), 813 SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { 814 DEBUG(SCI->dump(&SchedModels)); 815 816 SCTab.resize(SCTab.size() + 1); 817 MCSchedClassDesc &SCDesc = SCTab.back(); 818 // SCDesc.Name is guarded by NDEBUG 819 SCDesc.NumMicroOps = 0; 820 SCDesc.BeginGroup = false; 821 SCDesc.EndGroup = false; 822 SCDesc.WriteProcResIdx = 0; 823 SCDesc.WriteLatencyIdx = 0; 824 SCDesc.ReadAdvanceIdx = 0; 825 826 // A Variant SchedClass has no resources of its own. 827 bool HasVariants = false; 828 for (std::vector<CodeGenSchedTransition>::const_iterator 829 TI = SCI->Transitions.begin(), TE = SCI->Transitions.end(); 830 TI != TE; ++TI) { 831 if (TI->ProcIndices[0] == 0) { 832 HasVariants = true; 833 break; 834 } 835 IdxIter PIPos = std::find(TI->ProcIndices.begin(), 836 TI->ProcIndices.end(), ProcModel.Index); 837 if (PIPos != TI->ProcIndices.end()) { 838 HasVariants = true; 839 break; 840 } 841 } 842 if (HasVariants) { 843 SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; 844 continue; 845 } 846 847 // Determine if the SchedClass is actually reachable on this processor. If 848 // not don't try to locate the processor resources, it will fail. 849 // If ProcIndices contains 0, this class applies to all processors. 850 assert(!SCI->ProcIndices.empty() && "expect at least one procidx"); 851 if (SCI->ProcIndices[0] != 0) { 852 IdxIter PIPos = std::find(SCI->ProcIndices.begin(), 853 SCI->ProcIndices.end(), ProcModel.Index); 854 if (PIPos == SCI->ProcIndices.end()) 855 continue; 856 } 857 IdxVec Writes = SCI->Writes; 858 IdxVec Reads = SCI->Reads; 859 if (!SCI->InstRWs.empty()) { 860 // This class has a default ReadWrite list which can be overriden by 861 // InstRW definitions. 862 Record *RWDef = nullptr; 863 for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); 864 RWI != RWE; ++RWI) { 865 Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel"); 866 if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { 867 RWDef = *RWI; 868 break; 869 } 870 } 871 if (RWDef) { 872 Writes.clear(); 873 Reads.clear(); 874 SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), 875 Writes, Reads); 876 } 877 } 878 if (Writes.empty()) { 879 // Check this processor's itinerary class resources. 880 for (RecIter II = ProcModel.ItinRWDefs.begin(), 881 IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { 882 RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); 883 if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) 884 != Matched.end()) { 885 SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), 886 Writes, Reads); 887 break; 888 } 889 } 890 if (Writes.empty()) { 891 DEBUG(dbgs() << ProcModel.ModelName 892 << " does not have resources for class " << SCI->Name << '\n'); 893 } 894 } 895 // Sum resources across all operand writes. 896 std::vector<MCWriteProcResEntry> WriteProcResources; 897 std::vector<MCWriteLatencyEntry> WriteLatencies; 898 std::vector<std::string> WriterNames; 899 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 900 for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) { 901 IdxVec WriteSeq; 902 SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false, 903 ProcModel); 904 905 // For each operand, create a latency entry. 906 MCWriteLatencyEntry WLEntry; 907 WLEntry.Cycles = 0; 908 unsigned WriteID = WriteSeq.back(); 909 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); 910 // If this Write is not referenced by a ReadAdvance, don't distinguish it 911 // from other WriteLatency entries. 912 if (!SchedModels.hasReadOfWrite( 913 SchedModels.getSchedWrite(WriteID).TheDef)) { 914 WriteID = 0; 915 } 916 WLEntry.WriteResourceID = WriteID; 917 918 for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end(); 919 WSI != WSE; ++WSI) { 920 921 Record *WriteRes = 922 FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel); 923 924 // Mark the parent class as invalid for unsupported write types. 925 if (WriteRes->getValueAsBit("Unsupported")) { 926 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 927 break; 928 } 929 WLEntry.Cycles += WriteRes->getValueAsInt("Latency"); 930 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps"); 931 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup"); 932 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup"); 933 934 // Create an entry for each ProcResource listed in WriteRes. 935 RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); 936 std::vector<int64_t> Cycles = 937 WriteRes->getValueAsListOfInts("ResourceCycles"); 938 939 ExpandProcResources(PRVec, Cycles, ProcModel); 940 941 for (unsigned PRIdx = 0, PREnd = PRVec.size(); 942 PRIdx != PREnd; ++PRIdx) { 943 MCWriteProcResEntry WPREntry; 944 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); 945 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); 946 WPREntry.Cycles = Cycles[PRIdx]; 947 // If this resource is already used in this sequence, add the current 948 // entry's cycles so that the same resource appears to be used 949 // serially, rather than multiple parallel uses. This is important for 950 // in-order machine where the resource consumption is a hazard. 951 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); 952 for( ; WPRIdx != WPREnd; ++WPRIdx) { 953 if (WriteProcResources[WPRIdx].ProcResourceIdx 954 == WPREntry.ProcResourceIdx) { 955 WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles; 956 break; 957 } 958 } 959 if (WPRIdx == WPREnd) 960 WriteProcResources.push_back(WPREntry); 961 } 962 } 963 WriteLatencies.push_back(WLEntry); 964 } 965 // Create an entry for each operand Read in this SchedClass. 966 // Entries must be sorted first by UseIdx then by WriteResourceID. 967 for (unsigned UseIdx = 0, EndIdx = Reads.size(); 968 UseIdx != EndIdx; ++UseIdx) { 969 Record *ReadAdvance = 970 FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); 971 if (!ReadAdvance) 972 continue; 973 974 // Mark the parent class as invalid for unsupported write types. 975 if (ReadAdvance->getValueAsBit("Unsupported")) { 976 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 977 break; 978 } 979 RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites"); 980 IdxVec WriteIDs; 981 if (ValidWrites.empty()) 982 WriteIDs.push_back(0); 983 else { 984 for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end(); 985 VWI != VWE; ++VWI) { 986 WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false)); 987 } 988 } 989 std::sort(WriteIDs.begin(), WriteIDs.end()); 990 for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) { 991 MCReadAdvanceEntry RAEntry; 992 RAEntry.UseIdx = UseIdx; 993 RAEntry.WriteResourceID = *WI; 994 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); 995 ReadAdvanceEntries.push_back(RAEntry); 996 } 997 } 998 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 999 WriteProcResources.clear(); 1000 WriteLatencies.clear(); 1001 ReadAdvanceEntries.clear(); 1002 } 1003 // Add the information for this SchedClass to the global tables using basic 1004 // compression. 1005 // 1006 // WritePrecRes entries are sorted by ProcResIdx. 1007 std::sort(WriteProcResources.begin(), WriteProcResources.end(), 1008 LessWriteProcResources()); 1009 1010 SCDesc.NumWriteProcResEntries = WriteProcResources.size(); 1011 std::vector<MCWriteProcResEntry>::iterator WPRPos = 1012 std::search(SchedTables.WriteProcResources.begin(), 1013 SchedTables.WriteProcResources.end(), 1014 WriteProcResources.begin(), WriteProcResources.end()); 1015 if (WPRPos != SchedTables.WriteProcResources.end()) 1016 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin(); 1017 else { 1018 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size(); 1019 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(), 1020 WriteProcResources.end()); 1021 } 1022 // Latency entries must remain in operand order. 1023 SCDesc.NumWriteLatencyEntries = WriteLatencies.size(); 1024 std::vector<MCWriteLatencyEntry>::iterator WLPos = 1025 std::search(SchedTables.WriteLatencies.begin(), 1026 SchedTables.WriteLatencies.end(), 1027 WriteLatencies.begin(), WriteLatencies.end()); 1028 if (WLPos != SchedTables.WriteLatencies.end()) { 1029 unsigned idx = WLPos - SchedTables.WriteLatencies.begin(); 1030 SCDesc.WriteLatencyIdx = idx; 1031 for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i) 1032 if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) == 1033 std::string::npos) { 1034 SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i]; 1035 } 1036 } 1037 else { 1038 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); 1039 SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), 1040 WriteLatencies.begin(), 1041 WriteLatencies.end()); 1042 SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), 1043 WriterNames.begin(), WriterNames.end()); 1044 } 1045 // ReadAdvanceEntries must remain in operand order. 1046 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); 1047 std::vector<MCReadAdvanceEntry>::iterator RAPos = 1048 std::search(SchedTables.ReadAdvanceEntries.begin(), 1049 SchedTables.ReadAdvanceEntries.end(), 1050 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end()); 1051 if (RAPos != SchedTables.ReadAdvanceEntries.end()) 1052 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); 1053 else { 1054 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); 1055 SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(), 1056 ReadAdvanceEntries.end()); 1057 } 1058 } 1059} 1060 1061// Emit SchedClass tables for all processors and associated global tables. 1062void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, 1063 raw_ostream &OS) { 1064 // Emit global WriteProcResTable. 1065 OS << "\n// {ProcResourceIdx, Cycles}\n" 1066 << "extern const llvm::MCWriteProcResEntry " 1067 << Target << "WriteProcResTable[] = {\n" 1068 << " { 0, 0}, // Invalid\n"; 1069 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); 1070 WPRIdx != WPREnd; ++WPRIdx) { 1071 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; 1072 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " 1073 << format("%2d", WPREntry.Cycles) << "}"; 1074 if (WPRIdx + 1 < WPREnd) 1075 OS << ','; 1076 OS << " // #" << WPRIdx << '\n'; 1077 } 1078 OS << "}; // " << Target << "WriteProcResTable\n"; 1079 1080 // Emit global WriteLatencyTable. 1081 OS << "\n// {Cycles, WriteResourceID}\n" 1082 << "extern const llvm::MCWriteLatencyEntry " 1083 << Target << "WriteLatencyTable[] = {\n" 1084 << " { 0, 0}, // Invalid\n"; 1085 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); 1086 WLIdx != WLEnd; ++WLIdx) { 1087 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; 1088 OS << " {" << format("%2d", WLEntry.Cycles) << ", " 1089 << format("%2d", WLEntry.WriteResourceID) << "}"; 1090 if (WLIdx + 1 < WLEnd) 1091 OS << ','; 1092 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; 1093 } 1094 OS << "}; // " << Target << "WriteLatencyTable\n"; 1095 1096 // Emit global ReadAdvanceTable. 1097 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" 1098 << "extern const llvm::MCReadAdvanceEntry " 1099 << Target << "ReadAdvanceTable[] = {\n" 1100 << " {0, 0, 0}, // Invalid\n"; 1101 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); 1102 RAIdx != RAEnd; ++RAIdx) { 1103 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; 1104 OS << " {" << RAEntry.UseIdx << ", " 1105 << format("%2d", RAEntry.WriteResourceID) << ", " 1106 << format("%2d", RAEntry.Cycles) << "}"; 1107 if (RAIdx + 1 < RAEnd) 1108 OS << ','; 1109 OS << " // #" << RAIdx << '\n'; 1110 } 1111 OS << "}; // " << Target << "ReadAdvanceTable\n"; 1112 1113 // Emit a SchedClass table for each processor. 1114 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1115 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1116 if (!PI->hasInstrSchedModel()) 1117 continue; 1118 1119 std::vector<MCSchedClassDesc> &SCTab = 1120 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; 1121 1122 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup," 1123 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; 1124 OS << "static const llvm::MCSchedClassDesc " 1125 << PI->ModelName << "SchedClasses[] = {\n"; 1126 1127 // The first class is always invalid. We no way to distinguish it except by 1128 // name and position. 1129 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" 1130 && "invalid class not first"); 1131 OS << " {DBGFIELD(\"InvalidSchedClass\") " 1132 << MCSchedClassDesc::InvalidNumMicroOps 1133 << ", 0, 0, 0, 0, 0, 0, 0, 0},\n"; 1134 1135 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { 1136 MCSchedClassDesc &MCDesc = SCTab[SCIdx]; 1137 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); 1138 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; 1139 if (SchedClass.Name.size() < 18) 1140 OS.indent(18 - SchedClass.Name.size()); 1141 OS << MCDesc.NumMicroOps 1142 << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup 1143 << ", " << format("%2d", MCDesc.WriteProcResIdx) 1144 << ", " << MCDesc.NumWriteProcResEntries 1145 << ", " << format("%2d", MCDesc.WriteLatencyIdx) 1146 << ", " << MCDesc.NumWriteLatencyEntries 1147 << ", " << format("%2d", MCDesc.ReadAdvanceIdx) 1148 << ", " << MCDesc.NumReadAdvanceEntries << "}"; 1149 if (SCIdx + 1 < SCEnd) 1150 OS << ','; 1151 OS << " // #" << SCIdx << '\n'; 1152 } 1153 OS << "}; // " << PI->ModelName << "SchedClasses\n"; 1154 } 1155} 1156 1157void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { 1158 // For each processor model. 1159 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1160 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1161 // Emit processor resource table. 1162 if (PI->hasInstrSchedModel()) 1163 EmitProcessorResources(*PI, OS); 1164 else if(!PI->ProcResourceDefs.empty()) 1165 PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines " 1166 "ProcResources without defining WriteRes SchedWriteRes"); 1167 1168 // Begin processor itinerary properties 1169 OS << "\n"; 1170 OS << "static const llvm::MCSchedModel " << PI->ModelName << " = {\n"; 1171 EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ','); 1172 EmitProcessorProp(OS, PI->ModelDef, "MicroOpBufferSize", ','); 1173 EmitProcessorProp(OS, PI->ModelDef, "LoopMicroOpBufferSize", ','); 1174 EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); 1175 EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); 1176 EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); 1177 1178 OS << " " << (bool)(PI->ModelDef ? 1179 PI->ModelDef->getValueAsBit("PostRAScheduler") : 0) 1180 << ", // " << "PostRAScheduler\n"; 1181 1182 OS << " " << (bool)(PI->ModelDef ? 1183 PI->ModelDef->getValueAsBit("CompleteModel") : 0) 1184 << ", // " << "CompleteModel\n"; 1185 1186 OS << " " << PI->Index << ", // Processor ID\n"; 1187 if (PI->hasInstrSchedModel()) 1188 OS << " " << PI->ModelName << "ProcResources" << ",\n" 1189 << " " << PI->ModelName << "SchedClasses" << ",\n" 1190 << " " << PI->ProcResourceDefs.size()+1 << ",\n" 1191 << " " << (SchedModels.schedClassEnd() 1192 - SchedModels.schedClassBegin()) << ",\n"; 1193 else 1194 OS << " nullptr, nullptr, 0, 0," 1195 << " // No instruction-level machine model.\n"; 1196 if (PI->hasItineraries()) 1197 OS << " " << PI->ItinsDef->getName() << "};\n"; 1198 else 1199 OS << " nullptr}; // No Itinerary\n"; 1200 } 1201} 1202 1203// 1204// EmitProcessorLookup - generate cpu name to itinerary lookup table. 1205// 1206void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { 1207 // Gather and sort processor information 1208 std::vector<Record*> ProcessorList = 1209 Records.getAllDerivedDefinitions("Processor"); 1210 std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); 1211 1212 // Begin processor table 1213 OS << "\n"; 1214 OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" 1215 << "extern const llvm::SubtargetInfoKV " 1216 << Target << "ProcSchedKV[] = {\n"; 1217 1218 // For each processor 1219 for (unsigned i = 0, N = ProcessorList.size(); i < N;) { 1220 // Next processor 1221 Record *Processor = ProcessorList[i]; 1222 1223 const std::string &Name = Processor->getValueAsString("Name"); 1224 const std::string &ProcModelName = 1225 SchedModels.getModelForProc(Processor).ModelName; 1226 1227 // Emit as { "cpu", procinit }, 1228 OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " }"; 1229 1230 // Depending on ''if more in the list'' emit comma 1231 if (++i < N) OS << ","; 1232 1233 OS << "\n"; 1234 } 1235 1236 // End processor table 1237 OS << "};\n"; 1238} 1239 1240// 1241// EmitSchedModel - Emits all scheduling model tables, folding common patterns. 1242// 1243void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { 1244 OS << "#ifdef DBGFIELD\n" 1245 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" 1246 << "#endif\n" 1247 << "#ifndef NDEBUG\n" 1248 << "#define DBGFIELD(x) x,\n" 1249 << "#else\n" 1250 << "#define DBGFIELD(x)\n" 1251 << "#endif\n"; 1252 1253 if (SchedModels.hasItineraries()) { 1254 std::vector<std::vector<InstrItinerary> > ProcItinLists; 1255 // Emit the stage data 1256 EmitStageAndOperandCycleData(OS, ProcItinLists); 1257 EmitItineraries(OS, ProcItinLists); 1258 } 1259 OS << "\n// ===============================================================\n" 1260 << "// Data tables for the new per-operand machine model.\n"; 1261 1262 SchedClassTables SchedTables; 1263 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1264 PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1265 GenSchedClassTables(*PI, SchedTables); 1266 } 1267 EmitSchedClassTables(SchedTables, OS); 1268 1269 // Emit the processor machine model 1270 EmitProcessorModels(OS); 1271 // Emit the processor lookup data 1272 EmitProcessorLookup(OS); 1273 1274 OS << "#undef DBGFIELD"; 1275} 1276 1277void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, 1278 raw_ostream &OS) { 1279 OS << "unsigned " << ClassName 1280 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," 1281 << " const TargetSchedModel *SchedModel) const {\n"; 1282 1283 std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); 1284 std::sort(Prologs.begin(), Prologs.end(), LessRecord()); 1285 for (std::vector<Record*>::const_iterator 1286 PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) { 1287 OS << (*PI)->getValueAsString("Code") << '\n'; 1288 } 1289 IdxVec VariantClasses; 1290 for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), 1291 SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { 1292 if (SCI->Transitions.empty()) 1293 continue; 1294 VariantClasses.push_back(SCI->Index); 1295 } 1296 if (!VariantClasses.empty()) { 1297 OS << " switch (SchedClass) {\n"; 1298 for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end(); 1299 VCI != VCE; ++VCI) { 1300 const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI); 1301 OS << " case " << *VCI << ": // " << SC.Name << '\n'; 1302 IdxVec ProcIndices; 1303 for (std::vector<CodeGenSchedTransition>::const_iterator 1304 TI = SC.Transitions.begin(), TE = SC.Transitions.end(); 1305 TI != TE; ++TI) { 1306 IdxVec PI; 1307 std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(), 1308 ProcIndices.begin(), ProcIndices.end(), 1309 std::back_inserter(PI)); 1310 ProcIndices.swap(PI); 1311 } 1312 for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); 1313 PI != PE; ++PI) { 1314 OS << " "; 1315 if (*PI != 0) 1316 OS << "if (SchedModel->getProcessorID() == " << *PI << ") "; 1317 OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName 1318 << '\n'; 1319 for (std::vector<CodeGenSchedTransition>::const_iterator 1320 TI = SC.Transitions.begin(), TE = SC.Transitions.end(); 1321 TI != TE; ++TI) { 1322 if (*PI != 0 && !std::count(TI->ProcIndices.begin(), 1323 TI->ProcIndices.end(), *PI)) { 1324 continue; 1325 } 1326 OS << " if ("; 1327 for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end(); 1328 RI != RE; ++RI) { 1329 if (RI != TI->PredTerm.begin()) 1330 OS << "\n && "; 1331 OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; 1332 } 1333 OS << ")\n" 1334 << " return " << TI->ToClassIdx << "; // " 1335 << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n'; 1336 } 1337 OS << " }\n"; 1338 if (*PI == 0) 1339 break; 1340 } 1341 if (SC.isInferred()) 1342 OS << " return " << SC.Index << ";\n"; 1343 OS << " break;\n"; 1344 } 1345 OS << " };\n"; 1346 } 1347 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" 1348 << "} // " << ClassName << "::resolveSchedClass\n"; 1349} 1350 1351// 1352// ParseFeaturesFunction - Produces a subtarget specific function for parsing 1353// the subtarget features string. 1354// 1355void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, 1356 unsigned NumFeatures, 1357 unsigned NumProcs) { 1358 std::vector<Record*> Features = 1359 Records.getAllDerivedDefinitions("SubtargetFeature"); 1360 std::sort(Features.begin(), Features.end(), LessRecord()); 1361 1362 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" 1363 << "// subtarget options.\n" 1364 << "void llvm::"; 1365 OS << Target; 1366 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" 1367 << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" 1368 << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; 1369 1370 if (Features.empty()) { 1371 OS << "}\n"; 1372 return; 1373 } 1374 1375 OS << " InitMCProcessorInfo(CPU, FS);\n" 1376 << " const FeatureBitset& Bits = getFeatureBits();\n"; 1377 1378 for (unsigned i = 0; i < Features.size(); i++) { 1379 // Next record 1380 Record *R = Features[i]; 1381 const std::string &Instance = R->getName(); 1382 const std::string &Value = R->getValueAsString("Value"); 1383 const std::string &Attribute = R->getValueAsString("Attribute"); 1384 1385 if (Value=="true" || Value=="false") 1386 OS << " if (Bits[" << Target << "::" 1387 << Instance << "]) " 1388 << Attribute << " = " << Value << ";\n"; 1389 else 1390 OS << " if (Bits[" << Target << "::" 1391 << Instance << "] && " 1392 << Attribute << " < " << Value << ") " 1393 << Attribute << " = " << Value << ";\n"; 1394 } 1395 1396 OS << "}\n"; 1397} 1398 1399// 1400// SubtargetEmitter::run - Main subtarget enumeration emitter. 1401// 1402void SubtargetEmitter::run(raw_ostream &OS) { 1403 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); 1404 1405 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; 1406 OS << "#undef GET_SUBTARGETINFO_ENUM\n"; 1407 1408 OS << "namespace llvm {\n"; 1409 Enumeration(OS, "SubtargetFeature"); 1410 OS << "} // end llvm namespace\n"; 1411 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; 1412 1413 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; 1414 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n"; 1415 1416 OS << "namespace llvm {\n"; 1417#if 0 1418 OS << "namespace {\n"; 1419#endif 1420 unsigned NumFeatures = FeatureKeyValues(OS); 1421 OS << "\n"; 1422 unsigned NumProcs = CPUKeyValues(OS); 1423 OS << "\n"; 1424 EmitSchedModel(OS); 1425 OS << "\n"; 1426#if 0 1427 OS << "}\n"; 1428#endif 1429 1430 // MCInstrInfo initialization routine. 1431 OS << "static inline MCSubtargetInfo *create" << Target 1432 << "MCSubtargetInfoImpl(" 1433 << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; 1434 OS << " return new MCSubtargetInfo(TT, CPU, FS, "; 1435 if (NumFeatures) 1436 OS << Target << "FeatureKV, "; 1437 else 1438 OS << "None, "; 1439 if (NumProcs) 1440 OS << Target << "SubTypeKV, "; 1441 else 1442 OS << "None, "; 1443 OS << '\n'; OS.indent(22); 1444 OS << Target << "ProcSchedKV, " 1445 << Target << "WriteProcResTable, " 1446 << Target << "WriteLatencyTable, " 1447 << Target << "ReadAdvanceTable, "; 1448 if (SchedModels.hasItineraries()) { 1449 OS << '\n'; OS.indent(22); 1450 OS << Target << "Stages, " 1451 << Target << "OperandCycles, " 1452 << Target << "ForwardingPaths"; 1453 } else 1454 OS << "0, 0, 0"; 1455 OS << ");\n}\n\n"; 1456 1457 OS << "} // end llvm namespace\n"; 1458 1459 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; 1460 1461 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; 1462 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n"; 1463 1464 OS << "#include \"llvm/Support/Debug.h\"\n"; 1465 OS << "#include \"llvm/Support/raw_ostream.h\"\n"; 1466 ParseFeaturesFunction(OS, NumFeatures, NumProcs); 1467 1468 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; 1469 1470 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. 1471 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; 1472 OS << "#undef GET_SUBTARGETINFO_HEADER\n"; 1473 1474 std::string ClassName = Target + "GenSubtargetInfo"; 1475 OS << "namespace llvm {\n"; 1476 OS << "class DFAPacketizer;\n"; 1477 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" 1478 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " 1479 << "StringRef FS);\n" 1480 << "public:\n" 1481 << " unsigned resolveSchedClass(unsigned SchedClass, " 1482 << " const MachineInstr *DefMI," 1483 << " const TargetSchedModel *SchedModel) const override;\n" 1484 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" 1485 << " const;\n" 1486 << "};\n"; 1487 OS << "} // end llvm namespace\n"; 1488 1489 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; 1490 1491 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; 1492 OS << "#undef GET_SUBTARGETINFO_CTOR\n"; 1493 1494 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; 1495 OS << "namespace llvm {\n"; 1496 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; 1497 OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; 1498 OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; 1499 OS << "extern const llvm::MCWriteProcResEntry " 1500 << Target << "WriteProcResTable[];\n"; 1501 OS << "extern const llvm::MCWriteLatencyEntry " 1502 << Target << "WriteLatencyTable[];\n"; 1503 OS << "extern const llvm::MCReadAdvanceEntry " 1504 << Target << "ReadAdvanceTable[];\n"; 1505 1506 if (SchedModels.hasItineraries()) { 1507 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; 1508 OS << "extern const unsigned " << Target << "OperandCycles[];\n"; 1509 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; 1510 } 1511 1512 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " 1513 << "StringRef FS)\n" 1514 << " : TargetSubtargetInfo(TT, CPU, FS, "; 1515 if (NumFeatures) 1516 OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; 1517 else 1518 OS << "None, "; 1519 if (NumProcs) 1520 OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; 1521 else 1522 OS << "None, "; 1523 OS << '\n'; OS.indent(24); 1524 OS << Target << "ProcSchedKV, " 1525 << Target << "WriteProcResTable, " 1526 << Target << "WriteLatencyTable, " 1527 << Target << "ReadAdvanceTable, "; 1528 OS << '\n'; OS.indent(24); 1529 if (SchedModels.hasItineraries()) { 1530 OS << Target << "Stages, " 1531 << Target << "OperandCycles, " 1532 << Target << "ForwardingPaths"; 1533 } else 1534 OS << "0, 0, 0"; 1535 OS << ") {}\n\n"; 1536 1537 EmitSchedModelHelpers(ClassName, OS); 1538 1539 OS << "} // end llvm namespace\n"; 1540 1541 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; 1542} 1543 1544namespace llvm { 1545 1546void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { 1547 CodeGenTarget CGTarget(RK); 1548 SubtargetEmitter(RK, CGTarget).run(OS); 1549} 1550 1551} // end llvm namespace 1552