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