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