1193323Sed//===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===// 2193323Sed// 3193323Sed// The LLVM Compiler Infrastructure 4193323Sed// 5193323Sed// This file is distributed under the University of Illinois Open Source 6193323Sed// License. See LICENSE.TXT for details. 7193323Sed// 8193323Sed//===----------------------------------------------------------------------===// 9193323Sed// 10193323Sed// This tablegen backend emits subtarget enumerations. 11193323Sed// 12193323Sed//===----------------------------------------------------------------------===// 13193323Sed 14243830Sdim#define DEBUG_TYPE "subtarget-emitter" 15243830Sdim 16193323Sed#include "CodeGenTarget.h" 17239462Sdim#include "CodeGenSchedule.h" 18249423Sdim#include "llvm/ADT/STLExtras.h" 19193323Sed#include "llvm/ADT/StringExtras.h" 20239462Sdim#include "llvm/MC/MCInstrItineraries.h" 21249423Sdim#include "llvm/Support/Debug.h" 22249423Sdim#include "llvm/Support/Format.h" 23243830Sdim#include "llvm/TableGen/Error.h" 24239462Sdim#include "llvm/TableGen/Record.h" 25239462Sdim#include "llvm/TableGen/TableGenBackend.h" 26193323Sed#include <algorithm> 27239462Sdim#include <map> 28239462Sdim#include <string> 29239462Sdim#include <vector> 30193323Sedusing namespace llvm; 31193323Sed 32239462Sdimnamespace { 33239462Sdimclass SubtargetEmitter { 34243830Sdim // Each processor has a SchedClassDesc table with an entry for each SchedClass. 35243830Sdim // The SchedClassDesc table indexes into a global write resource table, write 36243830Sdim // latency table, and read advance table. 37243830Sdim struct SchedClassTables { 38243830Sdim std::vector<std::vector<MCSchedClassDesc> > ProcSchedClasses; 39243830Sdim std::vector<MCWriteProcResEntry> WriteProcResources; 40243830Sdim std::vector<MCWriteLatencyEntry> WriteLatencies; 41243830Sdim std::vector<std::string> WriterNames; 42243830Sdim std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 43239462Sdim 44243830Sdim // Reserve an invalid entry at index 0 45243830Sdim SchedClassTables() { 46243830Sdim ProcSchedClasses.resize(1); 47243830Sdim WriteProcResources.resize(1); 48243830Sdim WriteLatencies.resize(1); 49243830Sdim WriterNames.push_back("InvalidWrite"); 50243830Sdim ReadAdvanceEntries.resize(1); 51243830Sdim } 52243830Sdim }; 53243830Sdim 54243830Sdim struct LessWriteProcResources { 55243830Sdim bool operator()(const MCWriteProcResEntry &LHS, 56243830Sdim const MCWriteProcResEntry &RHS) { 57243830Sdim return LHS.ProcResourceIdx < RHS.ProcResourceIdx; 58243830Sdim } 59243830Sdim }; 60243830Sdim 61239462Sdim RecordKeeper &Records; 62239462Sdim CodeGenSchedModels &SchedModels; 63239462Sdim std::string Target; 64239462Sdim 65239462Sdim void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits); 66239462Sdim unsigned FeatureKeyValues(raw_ostream &OS); 67239462Sdim unsigned CPUKeyValues(raw_ostream &OS); 68239462Sdim void FormItineraryStageString(const std::string &Names, 69239462Sdim Record *ItinData, std::string &ItinString, 70239462Sdim unsigned &NStages); 71239462Sdim void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, 72239462Sdim unsigned &NOperandCycles); 73239462Sdim void FormItineraryBypassString(const std::string &Names, 74239462Sdim Record *ItinData, 75239462Sdim std::string &ItinString, unsigned NOperandCycles); 76239462Sdim void EmitStageAndOperandCycleData(raw_ostream &OS, 77239462Sdim std::vector<std::vector<InstrItinerary> > 78239462Sdim &ProcItinLists); 79239462Sdim void EmitItineraries(raw_ostream &OS, 80239462Sdim std::vector<std::vector<InstrItinerary> > 81239462Sdim &ProcItinLists); 82239462Sdim void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name, 83239462Sdim char Separator); 84243830Sdim void EmitProcessorResources(const CodeGenProcModel &ProcModel, 85243830Sdim raw_ostream &OS); 86243830Sdim Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, 87243830Sdim const CodeGenProcModel &ProcModel); 88243830Sdim Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, 89243830Sdim const CodeGenProcModel &ProcModel); 90249423Sdim void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, 91249423Sdim const CodeGenProcModel &ProcModel); 92243830Sdim void GenSchedClassTables(const CodeGenProcModel &ProcModel, 93243830Sdim SchedClassTables &SchedTables); 94243830Sdim void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); 95239462Sdim void EmitProcessorModels(raw_ostream &OS); 96239462Sdim void EmitProcessorLookup(raw_ostream &OS); 97243830Sdim void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS); 98239462Sdim void EmitSchedModel(raw_ostream &OS); 99239462Sdim void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, 100239462Sdim unsigned NumProcs); 101239462Sdim 102239462Sdimpublic: 103239462Sdim SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT): 104239462Sdim Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {} 105239462Sdim 106239462Sdim void run(raw_ostream &o); 107239462Sdim 108239462Sdim}; 109239462Sdim} // End anonymous namespace 110239462Sdim 111193323Sed// 112193323Sed// Enumeration - Emit the specified class as an enumeration. 113193323Sed// 114195340Sedvoid SubtargetEmitter::Enumeration(raw_ostream &OS, 115193323Sed const char *ClassName, 116193323Sed bool isBits) { 117193323Sed // Get all records of class and sort 118193323Sed std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName); 119193323Sed std::sort(DefList.begin(), DefList.end(), LessRecord()); 120193323Sed 121221345Sdim unsigned N = DefList.size(); 122224145Sdim if (N == 0) 123224145Sdim return; 124221345Sdim if (N > 64) { 125221345Sdim errs() << "Too many (> 64) subtarget features!\n"; 126221345Sdim exit(1); 127221345Sdim } 128221345Sdim 129224145Sdim OS << "namespace " << Target << " {\n"; 130224145Sdim 131234353Sdim // For bit flag enumerations with more than 32 items, emit constants. 132234353Sdim // Emit an enum for everything else. 133234353Sdim if (isBits && N > 32) { 134234353Sdim // For each record 135234353Sdim for (unsigned i = 0; i < N; i++) { 136234353Sdim // Next record 137234353Sdim Record *Def = DefList[i]; 138224145Sdim 139234353Sdim // Get and emit name and expression (1 << i) 140234353Sdim OS << " const uint64_t " << Def->getName() << " = 1ULL << " << i << ";\n"; 141234353Sdim } 142234353Sdim } else { 143234353Sdim // Open enumeration 144234353Sdim OS << "enum {\n"; 145221345Sdim 146234353Sdim // For each record 147234353Sdim for (unsigned i = 0; i < N;) { 148234353Sdim // Next record 149234353Sdim Record *Def = DefList[i]; 150221345Sdim 151234353Sdim // Get and emit name 152234353Sdim OS << " " << Def->getName(); 153193323Sed 154234353Sdim // If bit flags then emit expression (1 << i) 155234353Sdim if (isBits) OS << " = " << " 1ULL << " << i; 156221345Sdim 157234353Sdim // Depending on 'if more in the list' emit comma 158234353Sdim if (++i < N) OS << ","; 159234353Sdim 160234353Sdim OS << "\n"; 161234353Sdim } 162234353Sdim 163234353Sdim // Close enumeration 164234353Sdim OS << "};\n"; 165193323Sed } 166221345Sdim 167224145Sdim OS << "}\n"; 168193323Sed} 169193323Sed 170193323Sed// 171193323Sed// FeatureKeyValues - Emit data of all the subtarget features. Used by the 172193323Sed// command line. 173193323Sed// 174224145Sdimunsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) { 175193323Sed // Gather and sort all the features 176193323Sed std::vector<Record*> FeatureList = 177193323Sed Records.getAllDerivedDefinitions("SubtargetFeature"); 178224145Sdim 179224145Sdim if (FeatureList.empty()) 180224145Sdim return 0; 181224145Sdim 182193323Sed std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName()); 183193323Sed 184193323Sed // Begin feature table 185193323Sed OS << "// Sorted (by key) array of values for CPU features.\n" 186234353Sdim << "extern const llvm::SubtargetFeatureKV " << Target 187234353Sdim << "FeatureKV[] = {\n"; 188221345Sdim 189193323Sed // For each feature 190224145Sdim unsigned NumFeatures = 0; 191193323Sed for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) { 192193323Sed // Next feature 193193323Sed Record *Feature = FeatureList[i]; 194193323Sed 195193323Sed const std::string &Name = Feature->getName(); 196193323Sed const std::string &CommandLineName = Feature->getValueAsString("Name"); 197193323Sed const std::string &Desc = Feature->getValueAsString("Desc"); 198221345Sdim 199193323Sed if (CommandLineName.empty()) continue; 200221345Sdim 201193323Sed // Emit as { "feature", "description", featureEnum, i1 | i2 | ... | in } 202193323Sed OS << " { " 203193323Sed << "\"" << CommandLineName << "\", " 204193323Sed << "\"" << Desc << "\", " 205224145Sdim << Target << "::" << Name << ", "; 206193323Sed 207221345Sdim const std::vector<Record*> &ImpliesList = 208193323Sed Feature->getValueAsListOfDefs("Implies"); 209221345Sdim 210193323Sed if (ImpliesList.empty()) { 211221345Sdim OS << "0ULL"; 212193323Sed } else { 213193323Sed for (unsigned j = 0, M = ImpliesList.size(); j < M;) { 214224145Sdim OS << Target << "::" << ImpliesList[j]->getName(); 215193323Sed if (++j < M) OS << " | "; 216193323Sed } 217193323Sed } 218193323Sed 219193323Sed OS << " }"; 220224145Sdim ++NumFeatures; 221221345Sdim 222193323Sed // Depending on 'if more in the list' emit comma 223193323Sed if ((i + 1) < N) OS << ","; 224221345Sdim 225193323Sed OS << "\n"; 226193323Sed } 227221345Sdim 228193323Sed // End feature table 229193323Sed OS << "};\n"; 230193323Sed 231224145Sdim return NumFeatures; 232193323Sed} 233193323Sed 234193323Sed// 235193323Sed// CPUKeyValues - Emit data of all the subtarget processors. Used by command 236193323Sed// line. 237193323Sed// 238224145Sdimunsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { 239193323Sed // Gather and sort processor information 240193323Sed std::vector<Record*> ProcessorList = 241193323Sed Records.getAllDerivedDefinitions("Processor"); 242193323Sed std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); 243193323Sed 244193323Sed // Begin processor table 245193323Sed OS << "// Sorted (by key) array of values for CPU subtype.\n" 246234353Sdim << "extern const llvm::SubtargetFeatureKV " << Target 247234353Sdim << "SubTypeKV[] = {\n"; 248221345Sdim 249193323Sed // For each processor 250193323Sed for (unsigned i = 0, N = ProcessorList.size(); i < N;) { 251193323Sed // Next processor 252193323Sed Record *Processor = ProcessorList[i]; 253193323Sed 254193323Sed const std::string &Name = Processor->getValueAsString("Name"); 255221345Sdim const std::vector<Record*> &FeatureList = 256193323Sed Processor->getValueAsListOfDefs("Features"); 257221345Sdim 258193323Sed // Emit as { "cpu", "description", f1 | f2 | ... fn }, 259193323Sed OS << " { " 260193323Sed << "\"" << Name << "\", " 261193323Sed << "\"Select the " << Name << " processor\", "; 262221345Sdim 263193323Sed if (FeatureList.empty()) { 264221345Sdim OS << "0ULL"; 265193323Sed } else { 266193323Sed for (unsigned j = 0, M = FeatureList.size(); j < M;) { 267224145Sdim OS << Target << "::" << FeatureList[j]->getName(); 268193323Sed if (++j < M) OS << " | "; 269193323Sed } 270193323Sed } 271221345Sdim 272193323Sed // The "0" is for the "implies" section of this data structure. 273221345Sdim OS << ", 0ULL }"; 274221345Sdim 275193323Sed // Depending on 'if more in the list' emit comma 276193323Sed if (++i < N) OS << ","; 277221345Sdim 278193323Sed OS << "\n"; 279193323Sed } 280221345Sdim 281193323Sed // End processor table 282193323Sed OS << "};\n"; 283193323Sed 284224145Sdim return ProcessorList.size(); 285193323Sed} 286193323Sed 287193323Sed// 288198090Srdivacky// FormItineraryStageString - Compose a string containing the stage 289198090Srdivacky// data initialization for the specified itinerary. N is the number 290198090Srdivacky// of stages. 291193323Sed// 292207618Srdivackyvoid SubtargetEmitter::FormItineraryStageString(const std::string &Name, 293207618Srdivacky Record *ItinData, 294198090Srdivacky std::string &ItinString, 295198090Srdivacky unsigned &NStages) { 296193323Sed // Get states list 297193323Sed const std::vector<Record*> &StageList = 298193323Sed ItinData->getValueAsListOfDefs("Stages"); 299193323Sed 300193323Sed // For each stage 301193323Sed unsigned N = NStages = StageList.size(); 302193323Sed for (unsigned i = 0; i < N;) { 303193323Sed // Next stage 304193323Sed const Record *Stage = StageList[i]; 305221345Sdim 306207618Srdivacky // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind } 307193323Sed int Cycles = Stage->getValueAsInt("Cycles"); 308193323Sed ItinString += " { " + itostr(Cycles) + ", "; 309221345Sdim 310193323Sed // Get unit list 311193323Sed const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units"); 312221345Sdim 313193323Sed // For each unit 314193323Sed for (unsigned j = 0, M = UnitList.size(); j < M;) { 315193323Sed // Add name and bitwise or 316207618Srdivacky ItinString += Name + "FU::" + UnitList[j]->getName(); 317193323Sed if (++j < M) ItinString += " | "; 318193323Sed } 319221345Sdim 320198090Srdivacky int TimeInc = Stage->getValueAsInt("TimeInc"); 321198090Srdivacky ItinString += ", " + itostr(TimeInc); 322198090Srdivacky 323207618Srdivacky int Kind = Stage->getValueAsInt("Kind"); 324207618Srdivacky ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind); 325207618Srdivacky 326193323Sed // Close off stage 327193323Sed ItinString += " }"; 328193323Sed if (++i < N) ItinString += ", "; 329193323Sed } 330193323Sed} 331193323Sed 332193323Sed// 333198090Srdivacky// FormItineraryOperandCycleString - Compose a string containing the 334198090Srdivacky// operand cycle initialization for the specified itinerary. N is the 335198090Srdivacky// number of operands that has cycles specified. 336193323Sed// 337198090Srdivackyvoid SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, 338198090Srdivacky std::string &ItinString, unsigned &NOperandCycles) { 339198090Srdivacky // Get operand cycle list 340198090Srdivacky const std::vector<int64_t> &OperandCycleList = 341198090Srdivacky ItinData->getValueAsListOfInts("OperandCycles"); 342198090Srdivacky 343198090Srdivacky // For each operand cycle 344198090Srdivacky unsigned N = NOperandCycles = OperandCycleList.size(); 345198090Srdivacky for (unsigned i = 0; i < N;) { 346198090Srdivacky // Next operand cycle 347198090Srdivacky const int OCycle = OperandCycleList[i]; 348221345Sdim 349198090Srdivacky ItinString += " " + itostr(OCycle); 350198090Srdivacky if (++i < N) ItinString += ", "; 351198090Srdivacky } 352198090Srdivacky} 353198090Srdivacky 354218893Sdimvoid SubtargetEmitter::FormItineraryBypassString(const std::string &Name, 355218893Sdim Record *ItinData, 356218893Sdim std::string &ItinString, 357218893Sdim unsigned NOperandCycles) { 358218893Sdim const std::vector<Record*> &BypassList = 359218893Sdim ItinData->getValueAsListOfDefs("Bypasses"); 360218893Sdim unsigned N = BypassList.size(); 361218893Sdim unsigned i = 0; 362218893Sdim for (; i < N;) { 363218893Sdim ItinString += Name + "Bypass::" + BypassList[i]->getName(); 364218893Sdim if (++i < NOperandCycles) ItinString += ", "; 365218893Sdim } 366218893Sdim for (; i < NOperandCycles;) { 367218893Sdim ItinString += " 0"; 368218893Sdim if (++i < NOperandCycles) ItinString += ", "; 369218893Sdim } 370218893Sdim} 371218893Sdim 372198090Srdivacky// 373239462Sdim// EmitStageAndOperandCycleData - Generate unique itinerary stages and operand 374239462Sdim// cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed 375239462Sdim// by CodeGenSchedClass::Index. 376198090Srdivacky// 377239462Sdimvoid SubtargetEmitter:: 378239462SdimEmitStageAndOperandCycleData(raw_ostream &OS, 379239462Sdim std::vector<std::vector<InstrItinerary> > 380239462Sdim &ProcItinLists) { 381221345Sdim 382239462Sdim // Multiple processor models may share an itinerary record. Emit it once. 383239462Sdim SmallPtrSet<Record*, 8> ItinsDefSet; 384193323Sed 385207618Srdivacky // Emit functional units for all the itineraries. 386239462Sdim for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 387239462Sdim PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 388207618Srdivacky 389239462Sdim if (!ItinsDefSet.insert(PI->ItinsDef)) 390239462Sdim continue; 391239462Sdim 392239462Sdim std::vector<Record*> FUs = PI->ItinsDef->getValueAsListOfDefs("FU"); 393207618Srdivacky if (FUs.empty()) 394207618Srdivacky continue; 395207618Srdivacky 396239462Sdim const std::string &Name = PI->ItinsDef->getName(); 397239462Sdim OS << "\n// Functional units for \"" << Name << "\"\n" 398207618Srdivacky << "namespace " << Name << "FU {\n"; 399207618Srdivacky 400207618Srdivacky for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j) 401207618Srdivacky OS << " const unsigned " << FUs[j]->getName() 402207618Srdivacky << " = 1 << " << j << ";\n"; 403207618Srdivacky 404207618Srdivacky OS << "}\n"; 405218893Sdim 406239462Sdim std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP"); 407218893Sdim if (BPs.size()) { 408218893Sdim OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name 409218893Sdim << "\"\n" << "namespace " << Name << "Bypass {\n"; 410218893Sdim 411234353Sdim OS << " const unsigned NoBypass = 0;\n"; 412218893Sdim for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j) 413234353Sdim OS << " const unsigned " << BPs[j]->getName() 414218893Sdim << " = 1 << " << j << ";\n"; 415218893Sdim 416218893Sdim OS << "}\n"; 417218893Sdim } 418207618Srdivacky } 419207618Srdivacky 420193323Sed // Begin stages table 421234353Sdim std::string StageTable = "\nextern const llvm::InstrStage " + Target + 422234353Sdim "Stages[] = {\n"; 423207618Srdivacky StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n"; 424221345Sdim 425198090Srdivacky // Begin operand cycle table 426234353Sdim std::string OperandCycleTable = "extern const unsigned " + Target + 427224145Sdim "OperandCycles[] = {\n"; 428198090Srdivacky OperandCycleTable += " 0, // No itinerary\n"; 429218893Sdim 430218893Sdim // Begin pipeline bypass table 431234353Sdim std::string BypassTable = "extern const unsigned " + Target + 432239462Sdim "ForwardingPaths[] = {\n"; 433239462Sdim BypassTable += " 0, // No itinerary\n"; 434221345Sdim 435239462Sdim // For each Itinerary across all processors, add a unique entry to the stages, 436239462Sdim // operand cycles, and pipepine bypess tables. Then add the new Itinerary 437239462Sdim // object with computed offsets to the ProcItinLists result. 438198090Srdivacky unsigned StageCount = 1, OperandCycleCount = 1; 439218893Sdim std::map<std::string, unsigned> ItinStageMap, ItinOperandMap; 440239462Sdim for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 441239462Sdim PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 442239462Sdim const CodeGenProcModel &ProcModel = *PI; 443221345Sdim 444239462Sdim // Add process itinerary to the list. 445239462Sdim ProcItinLists.resize(ProcItinLists.size()+1); 446221345Sdim 447239462Sdim // If this processor defines no itineraries, then leave the itinerary list 448239462Sdim // empty. 449239462Sdim std::vector<InstrItinerary> &ItinList = ProcItinLists.back(); 450249423Sdim if (!ProcModel.hasItineraries()) 451239462Sdim continue; 452221345Sdim 453239462Sdim const std::string &Name = ProcModel.ItinsDef->getName(); 454221345Sdim 455249423Sdim ItinList.resize(SchedModels.numInstrSchedClasses()); 456249423Sdim assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); 457249423Sdim 458249423Sdim for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size(); 459239462Sdim SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { 460239462Sdim 461193323Sed // Next itinerary data 462239462Sdim Record *ItinData = ProcModel.ItinDefList[SchedClassIdx]; 463221345Sdim 464193323Sed // Get string and stage count 465198090Srdivacky std::string ItinStageString; 466239462Sdim unsigned NStages = 0; 467239462Sdim if (ItinData) 468239462Sdim FormItineraryStageString(Name, ItinData, ItinStageString, NStages); 469193323Sed 470198090Srdivacky // Get string and operand cycle count 471198090Srdivacky std::string ItinOperandCycleString; 472239462Sdim unsigned NOperandCycles = 0; 473218893Sdim std::string ItinBypassString; 474239462Sdim if (ItinData) { 475239462Sdim FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, 476239462Sdim NOperandCycles); 477218893Sdim 478239462Sdim FormItineraryBypassString(Name, ItinData, ItinBypassString, 479239462Sdim NOperandCycles); 480239462Sdim } 481239462Sdim 482198090Srdivacky // Check to see if stage already exists and create if it doesn't 483198090Srdivacky unsigned FindStage = 0; 484198090Srdivacky if (NStages > 0) { 485198090Srdivacky FindStage = ItinStageMap[ItinStageString]; 486198090Srdivacky if (FindStage == 0) { 487221345Sdim // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices 488221345Sdim StageTable += ItinStageString + ", // " + itostr(StageCount); 489221345Sdim if (NStages > 1) 490221345Sdim StageTable += "-" + itostr(StageCount + NStages - 1); 491221345Sdim StageTable += "\n"; 492198090Srdivacky // Record Itin class number. 493198090Srdivacky ItinStageMap[ItinStageString] = FindStage = StageCount; 494198090Srdivacky StageCount += NStages; 495198090Srdivacky } 496198090Srdivacky } 497221345Sdim 498198090Srdivacky // Check to see if operand cycle already exists and create if it doesn't 499198090Srdivacky unsigned FindOperandCycle = 0; 500198090Srdivacky if (NOperandCycles > 0) { 501218893Sdim std::string ItinOperandString = ItinOperandCycleString+ItinBypassString; 502218893Sdim FindOperandCycle = ItinOperandMap[ItinOperandString]; 503198090Srdivacky if (FindOperandCycle == 0) { 504198090Srdivacky // Emit as cycle, // index 505221345Sdim OperandCycleTable += ItinOperandCycleString + ", // "; 506221345Sdim std::string OperandIdxComment = itostr(OperandCycleCount); 507221345Sdim if (NOperandCycles > 1) 508221345Sdim OperandIdxComment += "-" 509221345Sdim + itostr(OperandCycleCount + NOperandCycles - 1); 510221345Sdim OperandCycleTable += OperandIdxComment + "\n"; 511198090Srdivacky // Record Itin class number. 512221345Sdim ItinOperandMap[ItinOperandCycleString] = 513198090Srdivacky FindOperandCycle = OperandCycleCount; 514218893Sdim // Emit as bypass, // index 515221345Sdim BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n"; 516198090Srdivacky OperandCycleCount += NOperandCycles; 517198090Srdivacky } 518193323Sed } 519221345Sdim 520218893Sdim // Set up itinerary as location and location + stage count 521239462Sdim int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; 522218893Sdim InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, 523218893Sdim FindOperandCycle, 524218893Sdim FindOperandCycle + NOperandCycles}; 525218893Sdim 526193323Sed // Inject - empty slots will be 0, 0 527239462Sdim ItinList[SchedClassIdx] = Intinerary; 528193323Sed } 529193323Sed } 530218893Sdim 531193323Sed // Closing stage 532239462Sdim StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n"; 533198090Srdivacky StageTable += "};\n"; 534198090Srdivacky 535198090Srdivacky // Closing operand cycles 536239462Sdim OperandCycleTable += " 0 // End operand cycles\n"; 537198090Srdivacky OperandCycleTable += "};\n"; 538198090Srdivacky 539239462Sdim BypassTable += " 0 // End bypass tables\n"; 540218893Sdim BypassTable += "};\n"; 541218893Sdim 542198090Srdivacky // Emit tables. 543198090Srdivacky OS << StageTable; 544198090Srdivacky OS << OperandCycleTable; 545218893Sdim OS << BypassTable; 546193323Sed} 547193323Sed 548193323Sed// 549239462Sdim// EmitProcessorData - Generate data for processor itineraries that were 550239462Sdim// computed during EmitStageAndOperandCycleData(). ProcItinLists lists all 551239462Sdim// Itineraries for each processor. The Itinerary lists are indexed on 552239462Sdim// CodeGenSchedClass::Index. 553193323Sed// 554221345Sdimvoid SubtargetEmitter:: 555239462SdimEmitItineraries(raw_ostream &OS, 556239462Sdim std::vector<std::vector<InstrItinerary> > &ProcItinLists) { 557239462Sdim 558239462Sdim // Multiple processor models may share an itinerary record. Emit it once. 559239462Sdim SmallPtrSet<Record*, 8> ItinsDefSet; 560239462Sdim 561239462Sdim // For each processor's machine model 562193323Sed std::vector<std::vector<InstrItinerary> >::iterator 563239462Sdim ProcItinListsIter = ProcItinLists.begin(); 564239462Sdim for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 565243830Sdim PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) { 566221345Sdim 567239462Sdim Record *ItinsDef = PI->ItinsDef; 568239462Sdim if (!ItinsDefSet.insert(ItinsDef)) 569239462Sdim continue; 570193323Sed 571193323Sed // Get processor itinerary name 572239462Sdim const std::string &Name = ItinsDef->getName(); 573221345Sdim 574239462Sdim // Get the itinerary list for the processor. 575239462Sdim assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator"); 576243830Sdim std::vector<InstrItinerary> &ItinList = *ProcItinListsIter; 577193323Sed 578193323Sed OS << "\n"; 579239462Sdim OS << "static const llvm::InstrItinerary "; 580239462Sdim if (ItinList.empty()) { 581239462Sdim OS << '*' << Name << " = 0;\n"; 582239462Sdim continue; 583239462Sdim } 584221345Sdim 585239462Sdim // Begin processor itinerary table 586239462Sdim OS << Name << "[] = {\n"; 587239462Sdim 588239462Sdim // For each itinerary class in CodeGenSchedClass::Index order. 589198090Srdivacky for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { 590193323Sed InstrItinerary &Intinerary = ItinList[j]; 591221345Sdim 592239462Sdim // Emit Itinerary in the form of 593198090Srdivacky // { firstStage, lastStage, firstCycle, lastCycle } // index 594239462Sdim OS << " { " << 595239462Sdim Intinerary.NumMicroOps << ", " << 596239462Sdim Intinerary.FirstStage << ", " << 597239462Sdim Intinerary.LastStage << ", " << 598239462Sdim Intinerary.FirstOperandCycle << ", " << 599239462Sdim Intinerary.LastOperandCycle << " }" << 600239462Sdim ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; 601193323Sed } 602193323Sed // End processor itinerary table 603239462Sdim OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n"; 604193323Sed OS << "};\n"; 605193323Sed } 606193323Sed} 607193323Sed 608239462Sdim// Emit either the value defined in the TableGen Record, or the default 609239462Sdim// value defined in the C++ header. The Record is null if the processor does not 610239462Sdim// define a model. 611239462Sdimvoid SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, 612239462Sdim const char *Name, char Separator) { 613239462Sdim OS << " "; 614239462Sdim int V = R ? R->getValueAsInt(Name) : -1; 615239462Sdim if (V >= 0) 616239462Sdim OS << V << Separator << " // " << Name; 617239462Sdim else 618239462Sdim OS << "MCSchedModel::Default" << Name << Separator; 619239462Sdim OS << '\n'; 620239462Sdim} 621239462Sdim 622243830Sdimvoid SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, 623243830Sdim raw_ostream &OS) { 624243830Sdim char Sep = ProcModel.ProcResourceDefs.empty() ? ' ' : ','; 625243830Sdim 626243830Sdim OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n"; 627243830Sdim OS << "static const llvm::MCProcResourceDesc " 628243830Sdim << ProcModel.ModelName << "ProcResources" << "[] = {\n" 629243830Sdim << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0}" << Sep << "\n"; 630243830Sdim 631243830Sdim for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { 632243830Sdim Record *PRDef = ProcModel.ProcResourceDefs[i]; 633243830Sdim 634249423Sdim Record *SuperDef = 0; 635243830Sdim unsigned SuperIdx = 0; 636249423Sdim unsigned NumUnits = 0; 637263508Sdim int BufferSize = PRDef->getValueAsInt("BufferSize"); 638249423Sdim if (PRDef->isSubClassOf("ProcResGroup")) { 639249423Sdim RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); 640249423Sdim for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end(); 641249423Sdim RUI != RUE; ++RUI) { 642249423Sdim NumUnits += (*RUI)->getValueAsInt("NumUnits"); 643249423Sdim } 644243830Sdim } 645249423Sdim else { 646249423Sdim // Find the SuperIdx 647249423Sdim if (PRDef->getValueInit("Super")->isComplete()) { 648249423Sdim SuperDef = SchedModels.findProcResUnits( 649249423Sdim PRDef->getValueAsDef("Super"), ProcModel); 650249423Sdim SuperIdx = ProcModel.getProcResourceIdx(SuperDef); 651249423Sdim } 652249423Sdim NumUnits = PRDef->getValueAsInt("NumUnits"); 653249423Sdim } 654243830Sdim // Emit the ProcResourceDesc 655243830Sdim if (i+1 == e) 656243830Sdim Sep = ' '; 657243830Sdim OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; 658243830Sdim if (PRDef->getName().size() < 15) 659243830Sdim OS.indent(15 - PRDef->getName().size()); 660249423Sdim OS << NumUnits << ", " << SuperIdx << ", " 661263508Sdim << BufferSize << "}" << Sep << " // #" << i+1; 662243830Sdim if (SuperDef) 663243830Sdim OS << ", Super=" << SuperDef->getName(); 664243830Sdim OS << "\n"; 665243830Sdim } 666243830Sdim OS << "};\n"; 667243830Sdim} 668243830Sdim 669243830Sdim// Find the WriteRes Record that defines processor resources for this 670243830Sdim// SchedWrite. 671243830SdimRecord *SubtargetEmitter::FindWriteResources( 672243830Sdim const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { 673243830Sdim 674243830Sdim // Check if the SchedWrite is already subtarget-specific and directly 675243830Sdim // specifies a set of processor resources. 676243830Sdim if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) 677243830Sdim return SchedWrite.TheDef; 678243830Sdim 679243830Sdim Record *AliasDef = 0; 680243830Sdim for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); 681243830Sdim AI != AE; ++AI) { 682243830Sdim const CodeGenSchedRW &AliasRW = 683243830Sdim SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); 684243830Sdim if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 685243830Sdim Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 686243830Sdim if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 687243830Sdim continue; 688243830Sdim } 689243830Sdim if (AliasDef) 690243830Sdim PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 691243830Sdim "defined for processor " + ProcModel.ModelName + 692243830Sdim " Ensure only one SchedAlias exists per RW."); 693243830Sdim AliasDef = AliasRW.TheDef; 694243830Sdim } 695243830Sdim if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) 696243830Sdim return AliasDef; 697243830Sdim 698243830Sdim // Check this processor's list of write resources. 699243830Sdim Record *ResDef = 0; 700243830Sdim for (RecIter WRI = ProcModel.WriteResDefs.begin(), 701243830Sdim WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) { 702243830Sdim if (!(*WRI)->isSubClassOf("WriteRes")) 703243830Sdim continue; 704243830Sdim if (AliasDef == (*WRI)->getValueAsDef("WriteType") 705243830Sdim || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) { 706243830Sdim if (ResDef) { 707243830Sdim PrintFatalError((*WRI)->getLoc(), "Resources are defined for both " 708243830Sdim "SchedWrite and its alias on processor " + 709243830Sdim ProcModel.ModelName); 710243830Sdim } 711243830Sdim ResDef = *WRI; 712243830Sdim } 713243830Sdim } 714243830Sdim // TODO: If ProcModel has a base model (previous generation processor), 715243830Sdim // then call FindWriteResources recursively with that model here. 716243830Sdim if (!ResDef) { 717243830Sdim PrintFatalError(ProcModel.ModelDef->getLoc(), 718243830Sdim std::string("Processor does not define resources for ") 719243830Sdim + SchedWrite.TheDef->getName()); 720243830Sdim } 721243830Sdim return ResDef; 722243830Sdim} 723243830Sdim 724243830Sdim/// Find the ReadAdvance record for the given SchedRead on this processor or 725243830Sdim/// return NULL. 726243830SdimRecord *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, 727243830Sdim const CodeGenProcModel &ProcModel) { 728243830Sdim // Check for SchedReads that directly specify a ReadAdvance. 729243830Sdim if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) 730243830Sdim return SchedRead.TheDef; 731243830Sdim 732243830Sdim // Check this processor's list of aliases for SchedRead. 733243830Sdim Record *AliasDef = 0; 734243830Sdim for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end(); 735243830Sdim AI != AE; ++AI) { 736243830Sdim const CodeGenSchedRW &AliasRW = 737243830Sdim SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); 738243830Sdim if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { 739243830Sdim Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); 740243830Sdim if (&SchedModels.getProcModel(ModelDef) != &ProcModel) 741243830Sdim continue; 742243830Sdim } 743243830Sdim if (AliasDef) 744243830Sdim PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " 745243830Sdim "defined for processor " + ProcModel.ModelName + 746243830Sdim " Ensure only one SchedAlias exists per RW."); 747243830Sdim AliasDef = AliasRW.TheDef; 748243830Sdim } 749243830Sdim if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) 750243830Sdim return AliasDef; 751243830Sdim 752243830Sdim // Check this processor's ReadAdvanceList. 753243830Sdim Record *ResDef = 0; 754243830Sdim for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(), 755243830Sdim RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) { 756243830Sdim if (!(*RAI)->isSubClassOf("ReadAdvance")) 757243830Sdim continue; 758243830Sdim if (AliasDef == (*RAI)->getValueAsDef("ReadType") 759243830Sdim || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) { 760243830Sdim if (ResDef) { 761243830Sdim PrintFatalError((*RAI)->getLoc(), "Resources are defined for both " 762243830Sdim "SchedRead and its alias on processor " + 763243830Sdim ProcModel.ModelName); 764243830Sdim } 765243830Sdim ResDef = *RAI; 766243830Sdim } 767243830Sdim } 768243830Sdim // TODO: If ProcModel has a base model (previous generation processor), 769243830Sdim // then call FindReadAdvance recursively with that model here. 770243830Sdim if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { 771243830Sdim PrintFatalError(ProcModel.ModelDef->getLoc(), 772243830Sdim std::string("Processor does not define resources for ") 773243830Sdim + SchedRead.TheDef->getName()); 774243830Sdim } 775243830Sdim return ResDef; 776243830Sdim} 777243830Sdim 778249423Sdim// Expand an explicit list of processor resources into a full list of implied 779251662Sdim// resource groups and super resources that cover them. 780249423Sdimvoid SubtargetEmitter::ExpandProcResources(RecVec &PRVec, 781249423Sdim std::vector<int64_t> &Cycles, 782251662Sdim const CodeGenProcModel &PM) { 783249423Sdim // Default to 1 resource cycle. 784249423Sdim Cycles.resize(PRVec.size(), 1); 785249423Sdim for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { 786251662Sdim Record *PRDef = PRVec[i]; 787249423Sdim RecVec SubResources; 788251662Sdim if (PRDef->isSubClassOf("ProcResGroup")) 789251662Sdim SubResources = PRDef->getValueAsListOfDefs("Resources"); 790249423Sdim else { 791251662Sdim SubResources.push_back(PRDef); 792251662Sdim PRDef = SchedModels.findProcResUnits(PRVec[i], PM); 793251662Sdim for (Record *SubDef = PRDef; 794251662Sdim SubDef->getValueInit("Super")->isComplete();) { 795251662Sdim if (SubDef->isSubClassOf("ProcResGroup")) { 796251662Sdim // Disallow this for simplicitly. 797251662Sdim PrintFatalError(SubDef->getLoc(), "Processor resource group " 798251662Sdim " cannot be a super resources."); 799251662Sdim } 800251662Sdim Record *SuperDef = 801251662Sdim SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM); 802251662Sdim PRVec.push_back(SuperDef); 803251662Sdim Cycles.push_back(Cycles[i]); 804251662Sdim SubDef = SuperDef; 805251662Sdim } 806249423Sdim } 807251662Sdim for (RecIter PRI = PM.ProcResourceDefs.begin(), 808251662Sdim PRE = PM.ProcResourceDefs.end(); 809249423Sdim PRI != PRE; ++PRI) { 810251662Sdim if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup")) 811249423Sdim continue; 812249423Sdim RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); 813249423Sdim RecIter SubI = SubResources.begin(), SubE = SubResources.end(); 814251662Sdim for( ; SubI != SubE; ++SubI) { 815251662Sdim if (std::find(SuperResources.begin(), SuperResources.end(), *SubI) 816251662Sdim == SuperResources.end()) { 817249423Sdim break; 818251662Sdim } 819249423Sdim } 820249423Sdim if (SubI == SubE) { 821249423Sdim PRVec.push_back(*PRI); 822249423Sdim Cycles.push_back(Cycles[i]); 823249423Sdim } 824249423Sdim } 825249423Sdim } 826249423Sdim} 827249423Sdim 828243830Sdim// Generate the SchedClass table for this processor and update global 829243830Sdim// tables. Must be called for each processor in order. 830243830Sdimvoid SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, 831243830Sdim SchedClassTables &SchedTables) { 832243830Sdim SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1); 833243830Sdim if (!ProcModel.hasInstrSchedModel()) 834243830Sdim return; 835243830Sdim 836243830Sdim std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); 837243830Sdim for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), 838243830Sdim SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { 839243830Sdim DEBUG(SCI->dump(&SchedModels)); 840243830Sdim 841243830Sdim SCTab.resize(SCTab.size() + 1); 842243830Sdim MCSchedClassDesc &SCDesc = SCTab.back(); 843243830Sdim // SCDesc.Name is guarded by NDEBUG 844243830Sdim SCDesc.NumMicroOps = 0; 845243830Sdim SCDesc.BeginGroup = false; 846243830Sdim SCDesc.EndGroup = false; 847243830Sdim SCDesc.WriteProcResIdx = 0; 848243830Sdim SCDesc.WriteLatencyIdx = 0; 849243830Sdim SCDesc.ReadAdvanceIdx = 0; 850243830Sdim 851243830Sdim // A Variant SchedClass has no resources of its own. 852249423Sdim bool HasVariants = false; 853249423Sdim for (std::vector<CodeGenSchedTransition>::const_iterator 854249423Sdim TI = SCI->Transitions.begin(), TE = SCI->Transitions.end(); 855249423Sdim TI != TE; ++TI) { 856249423Sdim if (TI->ProcIndices[0] == 0) { 857249423Sdim HasVariants = true; 858249423Sdim break; 859249423Sdim } 860249423Sdim IdxIter PIPos = std::find(TI->ProcIndices.begin(), 861249423Sdim TI->ProcIndices.end(), ProcModel.Index); 862249423Sdim if (PIPos != TI->ProcIndices.end()) { 863249423Sdim HasVariants = true; 864249423Sdim break; 865249423Sdim } 866249423Sdim } 867249423Sdim if (HasVariants) { 868243830Sdim SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; 869243830Sdim continue; 870243830Sdim } 871243830Sdim 872243830Sdim // Determine if the SchedClass is actually reachable on this processor. If 873243830Sdim // not don't try to locate the processor resources, it will fail. 874243830Sdim // If ProcIndices contains 0, this class applies to all processors. 875243830Sdim assert(!SCI->ProcIndices.empty() && "expect at least one procidx"); 876243830Sdim if (SCI->ProcIndices[0] != 0) { 877243830Sdim IdxIter PIPos = std::find(SCI->ProcIndices.begin(), 878243830Sdim SCI->ProcIndices.end(), ProcModel.Index); 879243830Sdim if (PIPos == SCI->ProcIndices.end()) 880243830Sdim continue; 881243830Sdim } 882243830Sdim IdxVec Writes = SCI->Writes; 883243830Sdim IdxVec Reads = SCI->Reads; 884249423Sdim if (!SCI->InstRWs.empty()) { 885249423Sdim // This class has a default ReadWrite list which can be overriden by 886243830Sdim // InstRW definitions. 887243830Sdim Record *RWDef = 0; 888243830Sdim for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); 889243830Sdim RWI != RWE; ++RWI) { 890243830Sdim Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel"); 891243830Sdim if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { 892243830Sdim RWDef = *RWI; 893243830Sdim break; 894243830Sdim } 895243830Sdim } 896243830Sdim if (RWDef) { 897243830Sdim Writes.clear(); 898243830Sdim Reads.clear(); 899243830Sdim SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), 900243830Sdim Writes, Reads); 901243830Sdim } 902243830Sdim } 903249423Sdim if (Writes.empty()) { 904249423Sdim // Check this processor's itinerary class resources. 905249423Sdim for (RecIter II = ProcModel.ItinRWDefs.begin(), 906249423Sdim IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { 907249423Sdim RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); 908249423Sdim if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) 909249423Sdim != Matched.end()) { 910249423Sdim SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), 911249423Sdim Writes, Reads); 912249423Sdim break; 913249423Sdim } 914249423Sdim } 915249423Sdim if (Writes.empty()) { 916249423Sdim DEBUG(dbgs() << ProcModel.ModelName 917249423Sdim << " does not have resources for class " << SCI->Name << '\n'); 918249423Sdim } 919249423Sdim } 920243830Sdim // Sum resources across all operand writes. 921243830Sdim std::vector<MCWriteProcResEntry> WriteProcResources; 922243830Sdim std::vector<MCWriteLatencyEntry> WriteLatencies; 923243830Sdim std::vector<std::string> WriterNames; 924243830Sdim std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; 925243830Sdim for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) { 926243830Sdim IdxVec WriteSeq; 927243830Sdim SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false, 928243830Sdim ProcModel); 929243830Sdim 930243830Sdim // For each operand, create a latency entry. 931243830Sdim MCWriteLatencyEntry WLEntry; 932243830Sdim WLEntry.Cycles = 0; 933243830Sdim unsigned WriteID = WriteSeq.back(); 934243830Sdim WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); 935243830Sdim // If this Write is not referenced by a ReadAdvance, don't distinguish it 936243830Sdim // from other WriteLatency entries. 937249423Sdim if (!SchedModels.hasReadOfWrite( 938249423Sdim SchedModels.getSchedWrite(WriteID).TheDef)) { 939243830Sdim WriteID = 0; 940243830Sdim } 941243830Sdim WLEntry.WriteResourceID = WriteID; 942243830Sdim 943243830Sdim for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end(); 944243830Sdim WSI != WSE; ++WSI) { 945243830Sdim 946243830Sdim Record *WriteRes = 947243830Sdim FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel); 948243830Sdim 949243830Sdim // Mark the parent class as invalid for unsupported write types. 950243830Sdim if (WriteRes->getValueAsBit("Unsupported")) { 951243830Sdim SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 952243830Sdim break; 953243830Sdim } 954243830Sdim WLEntry.Cycles += WriteRes->getValueAsInt("Latency"); 955243830Sdim SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps"); 956243830Sdim SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup"); 957243830Sdim SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup"); 958243830Sdim 959243830Sdim // Create an entry for each ProcResource listed in WriteRes. 960243830Sdim RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); 961243830Sdim std::vector<int64_t> Cycles = 962243830Sdim WriteRes->getValueAsListOfInts("ResourceCycles"); 963249423Sdim 964249423Sdim ExpandProcResources(PRVec, Cycles, ProcModel); 965249423Sdim 966243830Sdim for (unsigned PRIdx = 0, PREnd = PRVec.size(); 967243830Sdim PRIdx != PREnd; ++PRIdx) { 968243830Sdim MCWriteProcResEntry WPREntry; 969243830Sdim WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); 970243830Sdim assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); 971249423Sdim WPREntry.Cycles = Cycles[PRIdx]; 972249423Sdim // If this resource is already used in this sequence, add the current 973249423Sdim // entry's cycles so that the same resource appears to be used 974249423Sdim // serially, rather than multiple parallel uses. This is important for 975249423Sdim // in-order machine where the resource consumption is a hazard. 976249423Sdim unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); 977249423Sdim for( ; WPRIdx != WPREnd; ++WPRIdx) { 978249423Sdim if (WriteProcResources[WPRIdx].ProcResourceIdx 979249423Sdim == WPREntry.ProcResourceIdx) { 980249423Sdim WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles; 981249423Sdim break; 982249423Sdim } 983249423Sdim } 984249423Sdim if (WPRIdx == WPREnd) 985249423Sdim WriteProcResources.push_back(WPREntry); 986243830Sdim } 987243830Sdim } 988243830Sdim WriteLatencies.push_back(WLEntry); 989243830Sdim } 990243830Sdim // Create an entry for each operand Read in this SchedClass. 991243830Sdim // Entries must be sorted first by UseIdx then by WriteResourceID. 992243830Sdim for (unsigned UseIdx = 0, EndIdx = Reads.size(); 993243830Sdim UseIdx != EndIdx; ++UseIdx) { 994243830Sdim Record *ReadAdvance = 995243830Sdim FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); 996243830Sdim if (!ReadAdvance) 997243830Sdim continue; 998243830Sdim 999243830Sdim // Mark the parent class as invalid for unsupported write types. 1000243830Sdim if (ReadAdvance->getValueAsBit("Unsupported")) { 1001243830Sdim SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; 1002243830Sdim break; 1003243830Sdim } 1004243830Sdim RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites"); 1005243830Sdim IdxVec WriteIDs; 1006243830Sdim if (ValidWrites.empty()) 1007243830Sdim WriteIDs.push_back(0); 1008243830Sdim else { 1009243830Sdim for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end(); 1010243830Sdim VWI != VWE; ++VWI) { 1011243830Sdim WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false)); 1012243830Sdim } 1013243830Sdim } 1014243830Sdim std::sort(WriteIDs.begin(), WriteIDs.end()); 1015243830Sdim for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) { 1016243830Sdim MCReadAdvanceEntry RAEntry; 1017243830Sdim RAEntry.UseIdx = UseIdx; 1018243830Sdim RAEntry.WriteResourceID = *WI; 1019243830Sdim RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); 1020243830Sdim ReadAdvanceEntries.push_back(RAEntry); 1021243830Sdim } 1022243830Sdim } 1023243830Sdim if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 1024243830Sdim WriteProcResources.clear(); 1025243830Sdim WriteLatencies.clear(); 1026243830Sdim ReadAdvanceEntries.clear(); 1027243830Sdim } 1028243830Sdim // Add the information for this SchedClass to the global tables using basic 1029243830Sdim // compression. 1030243830Sdim // 1031243830Sdim // WritePrecRes entries are sorted by ProcResIdx. 1032243830Sdim std::sort(WriteProcResources.begin(), WriteProcResources.end(), 1033243830Sdim LessWriteProcResources()); 1034243830Sdim 1035243830Sdim SCDesc.NumWriteProcResEntries = WriteProcResources.size(); 1036243830Sdim std::vector<MCWriteProcResEntry>::iterator WPRPos = 1037243830Sdim std::search(SchedTables.WriteProcResources.begin(), 1038243830Sdim SchedTables.WriteProcResources.end(), 1039243830Sdim WriteProcResources.begin(), WriteProcResources.end()); 1040243830Sdim if (WPRPos != SchedTables.WriteProcResources.end()) 1041243830Sdim SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin(); 1042243830Sdim else { 1043243830Sdim SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size(); 1044243830Sdim SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(), 1045243830Sdim WriteProcResources.end()); 1046243830Sdim } 1047243830Sdim // Latency entries must remain in operand order. 1048243830Sdim SCDesc.NumWriteLatencyEntries = WriteLatencies.size(); 1049243830Sdim std::vector<MCWriteLatencyEntry>::iterator WLPos = 1050243830Sdim std::search(SchedTables.WriteLatencies.begin(), 1051243830Sdim SchedTables.WriteLatencies.end(), 1052243830Sdim WriteLatencies.begin(), WriteLatencies.end()); 1053243830Sdim if (WLPos != SchedTables.WriteLatencies.end()) { 1054243830Sdim unsigned idx = WLPos - SchedTables.WriteLatencies.begin(); 1055243830Sdim SCDesc.WriteLatencyIdx = idx; 1056243830Sdim for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i) 1057243830Sdim if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) == 1058243830Sdim std::string::npos) { 1059243830Sdim SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i]; 1060243830Sdim } 1061243830Sdim } 1062243830Sdim else { 1063243830Sdim SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); 1064243830Sdim SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), 1065243830Sdim WriteLatencies.begin(), 1066243830Sdim WriteLatencies.end()); 1067243830Sdim SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), 1068243830Sdim WriterNames.begin(), WriterNames.end()); 1069243830Sdim } 1070243830Sdim // ReadAdvanceEntries must remain in operand order. 1071243830Sdim SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); 1072243830Sdim std::vector<MCReadAdvanceEntry>::iterator RAPos = 1073243830Sdim std::search(SchedTables.ReadAdvanceEntries.begin(), 1074243830Sdim SchedTables.ReadAdvanceEntries.end(), 1075243830Sdim ReadAdvanceEntries.begin(), ReadAdvanceEntries.end()); 1076243830Sdim if (RAPos != SchedTables.ReadAdvanceEntries.end()) 1077243830Sdim SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); 1078243830Sdim else { 1079243830Sdim SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); 1080243830Sdim SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(), 1081243830Sdim ReadAdvanceEntries.end()); 1082243830Sdim } 1083243830Sdim } 1084243830Sdim} 1085243830Sdim 1086243830Sdim// Emit SchedClass tables for all processors and associated global tables. 1087243830Sdimvoid SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, 1088243830Sdim raw_ostream &OS) { 1089243830Sdim // Emit global WriteProcResTable. 1090243830Sdim OS << "\n// {ProcResourceIdx, Cycles}\n" 1091243830Sdim << "extern const llvm::MCWriteProcResEntry " 1092243830Sdim << Target << "WriteProcResTable[] = {\n" 1093243830Sdim << " { 0, 0}, // Invalid\n"; 1094243830Sdim for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); 1095243830Sdim WPRIdx != WPREnd; ++WPRIdx) { 1096243830Sdim MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; 1097243830Sdim OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " 1098243830Sdim << format("%2d", WPREntry.Cycles) << "}"; 1099243830Sdim if (WPRIdx + 1 < WPREnd) 1100243830Sdim OS << ','; 1101243830Sdim OS << " // #" << WPRIdx << '\n'; 1102243830Sdim } 1103243830Sdim OS << "}; // " << Target << "WriteProcResTable\n"; 1104243830Sdim 1105243830Sdim // Emit global WriteLatencyTable. 1106243830Sdim OS << "\n// {Cycles, WriteResourceID}\n" 1107243830Sdim << "extern const llvm::MCWriteLatencyEntry " 1108243830Sdim << Target << "WriteLatencyTable[] = {\n" 1109243830Sdim << " { 0, 0}, // Invalid\n"; 1110243830Sdim for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); 1111243830Sdim WLIdx != WLEnd; ++WLIdx) { 1112243830Sdim MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; 1113243830Sdim OS << " {" << format("%2d", WLEntry.Cycles) << ", " 1114243830Sdim << format("%2d", WLEntry.WriteResourceID) << "}"; 1115243830Sdim if (WLIdx + 1 < WLEnd) 1116243830Sdim OS << ','; 1117243830Sdim OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; 1118243830Sdim } 1119243830Sdim OS << "}; // " << Target << "WriteLatencyTable\n"; 1120243830Sdim 1121243830Sdim // Emit global ReadAdvanceTable. 1122243830Sdim OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" 1123243830Sdim << "extern const llvm::MCReadAdvanceEntry " 1124243830Sdim << Target << "ReadAdvanceTable[] = {\n" 1125243830Sdim << " {0, 0, 0}, // Invalid\n"; 1126243830Sdim for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); 1127243830Sdim RAIdx != RAEnd; ++RAIdx) { 1128243830Sdim MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; 1129243830Sdim OS << " {" << RAEntry.UseIdx << ", " 1130243830Sdim << format("%2d", RAEntry.WriteResourceID) << ", " 1131243830Sdim << format("%2d", RAEntry.Cycles) << "}"; 1132243830Sdim if (RAIdx + 1 < RAEnd) 1133243830Sdim OS << ','; 1134243830Sdim OS << " // #" << RAIdx << '\n'; 1135243830Sdim } 1136243830Sdim OS << "}; // " << Target << "ReadAdvanceTable\n"; 1137243830Sdim 1138243830Sdim // Emit a SchedClass table for each processor. 1139243830Sdim for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1140243830Sdim PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1141243830Sdim if (!PI->hasInstrSchedModel()) 1142243830Sdim continue; 1143243830Sdim 1144243830Sdim std::vector<MCSchedClassDesc> &SCTab = 1145243830Sdim SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; 1146243830Sdim 1147243830Sdim OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup," 1148243830Sdim << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; 1149243830Sdim OS << "static const llvm::MCSchedClassDesc " 1150243830Sdim << PI->ModelName << "SchedClasses[] = {\n"; 1151243830Sdim 1152243830Sdim // The first class is always invalid. We no way to distinguish it except by 1153243830Sdim // name and position. 1154249423Sdim assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" 1155243830Sdim && "invalid class not first"); 1156243830Sdim OS << " {DBGFIELD(\"InvalidSchedClass\") " 1157243830Sdim << MCSchedClassDesc::InvalidNumMicroOps 1158243830Sdim << ", 0, 0, 0, 0, 0, 0, 0, 0},\n"; 1159243830Sdim 1160243830Sdim for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { 1161243830Sdim MCSchedClassDesc &MCDesc = SCTab[SCIdx]; 1162243830Sdim const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); 1163243830Sdim OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; 1164243830Sdim if (SchedClass.Name.size() < 18) 1165243830Sdim OS.indent(18 - SchedClass.Name.size()); 1166243830Sdim OS << MCDesc.NumMicroOps 1167243830Sdim << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup 1168243830Sdim << ", " << format("%2d", MCDesc.WriteProcResIdx) 1169243830Sdim << ", " << MCDesc.NumWriteProcResEntries 1170243830Sdim << ", " << format("%2d", MCDesc.WriteLatencyIdx) 1171243830Sdim << ", " << MCDesc.NumWriteLatencyEntries 1172243830Sdim << ", " << format("%2d", MCDesc.ReadAdvanceIdx) 1173243830Sdim << ", " << MCDesc.NumReadAdvanceEntries << "}"; 1174243830Sdim if (SCIdx + 1 < SCEnd) 1175243830Sdim OS << ','; 1176243830Sdim OS << " // #" << SCIdx << '\n'; 1177243830Sdim } 1178243830Sdim OS << "}; // " << PI->ModelName << "SchedClasses\n"; 1179243830Sdim } 1180243830Sdim} 1181243830Sdim 1182239462Sdimvoid SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { 1183239462Sdim // For each processor model. 1184239462Sdim for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1185239462Sdim PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1186243830Sdim // Emit processor resource table. 1187243830Sdim if (PI->hasInstrSchedModel()) 1188243830Sdim EmitProcessorResources(*PI, OS); 1189243830Sdim else if(!PI->ProcResourceDefs.empty()) 1190243830Sdim PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines " 1191243830Sdim "ProcResources without defining WriteRes SchedWriteRes"); 1192243830Sdim 1193239462Sdim // Begin processor itinerary properties 1194239462Sdim OS << "\n"; 1195239462Sdim OS << "static const llvm::MCSchedModel " << PI->ModelName << "(\n"; 1196239462Sdim EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ','); 1197263508Sdim EmitProcessorProp(OS, PI->ModelDef, "MicroOpBufferSize", ','); 1198239462Sdim EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); 1199239462Sdim EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); 1200239462Sdim EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); 1201263508Sdim 1202263508Sdim OS << " " << (bool)(PI->ModelDef ? 1203263508Sdim PI->ModelDef->getValueAsBit("CompleteModel") : 0) 1204263508Sdim << ", // " << "CompleteModel\n"; 1205263508Sdim 1206243830Sdim OS << " " << PI->Index << ", // Processor ID\n"; 1207243830Sdim if (PI->hasInstrSchedModel()) 1208243830Sdim OS << " " << PI->ModelName << "ProcResources" << ",\n" 1209243830Sdim << " " << PI->ModelName << "SchedClasses" << ",\n" 1210243830Sdim << " " << PI->ProcResourceDefs.size()+1 << ",\n" 1211243830Sdim << " " << (SchedModels.schedClassEnd() 1212243830Sdim - SchedModels.schedClassBegin()) << ",\n"; 1213243830Sdim else 1214243830Sdim OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; 1215249423Sdim if (SchedModels.hasItineraries()) 1216243830Sdim OS << " " << PI->ItinsDef->getName() << ");\n"; 1217239462Sdim else 1218243830Sdim OS << " 0); // No Itinerary\n"; 1219239462Sdim } 1220239462Sdim} 1221239462Sdim 1222193323Sed// 1223193323Sed// EmitProcessorLookup - generate cpu name to itinerary lookup table. 1224193323Sed// 1225195340Sedvoid SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { 1226193323Sed // Gather and sort processor information 1227193323Sed std::vector<Record*> ProcessorList = 1228193323Sed Records.getAllDerivedDefinitions("Processor"); 1229193323Sed std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); 1230193323Sed 1231193323Sed // Begin processor table 1232193323Sed OS << "\n"; 1233193323Sed OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" 1234234353Sdim << "extern const llvm::SubtargetInfoKV " 1235239462Sdim << Target << "ProcSchedKV[] = {\n"; 1236221345Sdim 1237193323Sed // For each processor 1238193323Sed for (unsigned i = 0, N = ProcessorList.size(); i < N;) { 1239193323Sed // Next processor 1240193323Sed Record *Processor = ProcessorList[i]; 1241193323Sed 1242193323Sed const std::string &Name = Processor->getValueAsString("Name"); 1243239462Sdim const std::string &ProcModelName = 1244243830Sdim SchedModels.getModelForProc(Processor).ModelName; 1245221345Sdim 1246193323Sed // Emit as { "cpu", procinit }, 1247243830Sdim OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " }"; 1248221345Sdim 1249193323Sed // Depending on ''if more in the list'' emit comma 1250193323Sed if (++i < N) OS << ","; 1251221345Sdim 1252193323Sed OS << "\n"; 1253193323Sed } 1254221345Sdim 1255193323Sed // End processor table 1256193323Sed OS << "};\n"; 1257193323Sed} 1258193323Sed 1259193323Sed// 1260239462Sdim// EmitSchedModel - Emits all scheduling model tables, folding common patterns. 1261193323Sed// 1262239462Sdimvoid SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { 1263243830Sdim OS << "#ifdef DBGFIELD\n" 1264243830Sdim << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" 1265243830Sdim << "#endif\n" 1266243830Sdim << "#ifndef NDEBUG\n" 1267243830Sdim << "#define DBGFIELD(x) x,\n" 1268243830Sdim << "#else\n" 1269243830Sdim << "#define DBGFIELD(x)\n" 1270243830Sdim << "#endif\n"; 1271243830Sdim 1272249423Sdim if (SchedModels.hasItineraries()) { 1273239462Sdim std::vector<std::vector<InstrItinerary> > ProcItinLists; 1274193323Sed // Emit the stage data 1275239462Sdim EmitStageAndOperandCycleData(OS, ProcItinLists); 1276239462Sdim EmitItineraries(OS, ProcItinLists); 1277193323Sed } 1278243830Sdim OS << "\n// ===============================================================\n" 1279243830Sdim << "// Data tables for the new per-operand machine model.\n"; 1280243830Sdim 1281243830Sdim SchedClassTables SchedTables; 1282243830Sdim for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), 1283243830Sdim PE = SchedModels.procModelEnd(); PI != PE; ++PI) { 1284243830Sdim GenSchedClassTables(*PI, SchedTables); 1285243830Sdim } 1286243830Sdim EmitSchedClassTables(SchedTables, OS); 1287243830Sdim 1288239462Sdim // Emit the processor machine model 1289239462Sdim EmitProcessorModels(OS); 1290239462Sdim // Emit the processor lookup data 1291239462Sdim EmitProcessorLookup(OS); 1292243830Sdim 1293243830Sdim OS << "#undef DBGFIELD"; 1294193323Sed} 1295193323Sed 1296243830Sdimvoid SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, 1297243830Sdim raw_ostream &OS) { 1298243830Sdim OS << "unsigned " << ClassName 1299243830Sdim << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," 1300243830Sdim << " const TargetSchedModel *SchedModel) const {\n"; 1301243830Sdim 1302243830Sdim std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); 1303243830Sdim std::sort(Prologs.begin(), Prologs.end(), LessRecord()); 1304243830Sdim for (std::vector<Record*>::const_iterator 1305243830Sdim PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) { 1306243830Sdim OS << (*PI)->getValueAsString("Code") << '\n'; 1307243830Sdim } 1308243830Sdim IdxVec VariantClasses; 1309243830Sdim for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), 1310243830Sdim SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { 1311243830Sdim if (SCI->Transitions.empty()) 1312243830Sdim continue; 1313249423Sdim VariantClasses.push_back(SCI->Index); 1314243830Sdim } 1315243830Sdim if (!VariantClasses.empty()) { 1316243830Sdim OS << " switch (SchedClass) {\n"; 1317243830Sdim for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end(); 1318243830Sdim VCI != VCE; ++VCI) { 1319243830Sdim const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI); 1320243830Sdim OS << " case " << *VCI << ": // " << SC.Name << '\n'; 1321243830Sdim IdxVec ProcIndices; 1322243830Sdim for (std::vector<CodeGenSchedTransition>::const_iterator 1323243830Sdim TI = SC.Transitions.begin(), TE = SC.Transitions.end(); 1324243830Sdim TI != TE; ++TI) { 1325243830Sdim IdxVec PI; 1326243830Sdim std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(), 1327243830Sdim ProcIndices.begin(), ProcIndices.end(), 1328243830Sdim std::back_inserter(PI)); 1329243830Sdim ProcIndices.swap(PI); 1330243830Sdim } 1331243830Sdim for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); 1332243830Sdim PI != PE; ++PI) { 1333243830Sdim OS << " "; 1334243830Sdim if (*PI != 0) 1335243830Sdim OS << "if (SchedModel->getProcessorID() == " << *PI << ") "; 1336243830Sdim OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName 1337243830Sdim << '\n'; 1338243830Sdim for (std::vector<CodeGenSchedTransition>::const_iterator 1339243830Sdim TI = SC.Transitions.begin(), TE = SC.Transitions.end(); 1340243830Sdim TI != TE; ++TI) { 1341243830Sdim if (*PI != 0 && !std::count(TI->ProcIndices.begin(), 1342243830Sdim TI->ProcIndices.end(), *PI)) { 1343243830Sdim continue; 1344243830Sdim } 1345263508Sdim OS << " if ("; 1346243830Sdim for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end(); 1347243830Sdim RI != RE; ++RI) { 1348243830Sdim if (RI != TI->PredTerm.begin()) 1349243830Sdim OS << "\n && "; 1350243830Sdim OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; 1351243830Sdim } 1352243830Sdim OS << ")\n" 1353243830Sdim << " return " << TI->ToClassIdx << "; // " 1354243830Sdim << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n'; 1355243830Sdim } 1356243830Sdim OS << " }\n"; 1357243830Sdim if (*PI == 0) 1358243830Sdim break; 1359243830Sdim } 1360249423Sdim if (SC.isInferred()) 1361249423Sdim OS << " return " << SC.Index << ";\n"; 1362243830Sdim OS << " break;\n"; 1363243830Sdim } 1364243830Sdim OS << " };\n"; 1365243830Sdim } 1366243830Sdim OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" 1367243830Sdim << "} // " << ClassName << "::resolveSchedClass\n"; 1368243830Sdim} 1369243830Sdim 1370193323Sed// 1371193323Sed// ParseFeaturesFunction - Produces a subtarget specific function for parsing 1372193323Sed// the subtarget features string. 1373193323Sed// 1374224145Sdimvoid SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, 1375224145Sdim unsigned NumFeatures, 1376224145Sdim unsigned NumProcs) { 1377193323Sed std::vector<Record*> Features = 1378193323Sed Records.getAllDerivedDefinitions("SubtargetFeature"); 1379193323Sed std::sort(Features.begin(), Features.end(), LessRecord()); 1380193323Sed 1381221345Sdim OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" 1382221345Sdim << "// subtarget options.\n" 1383224145Sdim << "void llvm::"; 1384193323Sed OS << Target; 1385224145Sdim OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" 1386202375Srdivacky << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" 1387239462Sdim << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; 1388193323Sed 1389224145Sdim if (Features.empty()) { 1390224145Sdim OS << "}\n"; 1391224145Sdim return; 1392224145Sdim } 1393224145Sdim 1394243830Sdim OS << " InitMCProcessorInfo(CPU, FS);\n" 1395243830Sdim << " uint64_t Bits = getFeatureBits();\n"; 1396224145Sdim 1397193323Sed for (unsigned i = 0; i < Features.size(); i++) { 1398193323Sed // Next record 1399193323Sed Record *R = Features[i]; 1400193323Sed const std::string &Instance = R->getName(); 1401193323Sed const std::string &Value = R->getValueAsString("Value"); 1402193323Sed const std::string &Attribute = R->getValueAsString("Attribute"); 1403193323Sed 1404193323Sed if (Value=="true" || Value=="false") 1405224145Sdim OS << " if ((Bits & " << Target << "::" 1406224145Sdim << Instance << ") != 0) " 1407193323Sed << Attribute << " = " << Value << ";\n"; 1408193323Sed else 1409224145Sdim OS << " if ((Bits & " << Target << "::" 1410224145Sdim << Instance << ") != 0 && " 1411224145Sdim << Attribute << " < " << Value << ") " 1412224145Sdim << Attribute << " = " << Value << ";\n"; 1413193323Sed } 1414193323Sed 1415224145Sdim OS << "}\n"; 1416193323Sed} 1417193323Sed 1418193323Sed// 1419193323Sed// SubtargetEmitter::run - Main subtarget enumeration emitter. 1420193323Sed// 1421195340Sedvoid SubtargetEmitter::run(raw_ostream &OS) { 1422239462Sdim emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); 1423193323Sed 1424224145Sdim OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; 1425224145Sdim OS << "#undef GET_SUBTARGETINFO_ENUM\n"; 1426224145Sdim 1427224145Sdim OS << "namespace llvm {\n"; 1428224145Sdim Enumeration(OS, "SubtargetFeature", true); 1429224145Sdim OS << "} // End llvm namespace \n"; 1430224145Sdim OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; 1431224145Sdim 1432224145Sdim OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; 1433224145Sdim OS << "#undef GET_SUBTARGETINFO_MC_DESC\n"; 1434224145Sdim 1435224145Sdim OS << "namespace llvm {\n"; 1436224145Sdim#if 0 1437224145Sdim OS << "namespace {\n"; 1438224145Sdim#endif 1439224145Sdim unsigned NumFeatures = FeatureKeyValues(OS); 1440224145Sdim OS << "\n"; 1441224145Sdim unsigned NumProcs = CPUKeyValues(OS); 1442224145Sdim OS << "\n"; 1443239462Sdim EmitSchedModel(OS); 1444224145Sdim OS << "\n"; 1445224145Sdim#if 0 1446224145Sdim OS << "}\n"; 1447224145Sdim#endif 1448224145Sdim 1449224145Sdim // MCInstrInfo initialization routine. 1450224145Sdim OS << "static inline void Init" << Target 1451224145Sdim << "MCSubtargetInfo(MCSubtargetInfo *II, " 1452224145Sdim << "StringRef TT, StringRef CPU, StringRef FS) {\n"; 1453224145Sdim OS << " II->InitMCSubtargetInfo(TT, CPU, FS, "; 1454224145Sdim if (NumFeatures) 1455224145Sdim OS << Target << "FeatureKV, "; 1456224145Sdim else 1457224145Sdim OS << "0, "; 1458224145Sdim if (NumProcs) 1459224145Sdim OS << Target << "SubTypeKV, "; 1460224145Sdim else 1461224145Sdim OS << "0, "; 1462243830Sdim OS << '\n'; OS.indent(22); 1463243830Sdim OS << Target << "ProcSchedKV, " 1464243830Sdim << Target << "WriteProcResTable, " 1465243830Sdim << Target << "WriteLatencyTable, " 1466243830Sdim << Target << "ReadAdvanceTable, "; 1467249423Sdim if (SchedModels.hasItineraries()) { 1468243830Sdim OS << '\n'; OS.indent(22); 1469243830Sdim OS << Target << "Stages, " 1470224145Sdim << Target << "OperandCycles, " 1471239462Sdim << Target << "ForwardingPaths, "; 1472224145Sdim } else 1473243830Sdim OS << "0, 0, 0, "; 1474224145Sdim OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; 1475224145Sdim 1476224145Sdim OS << "} // End llvm namespace \n"; 1477224145Sdim 1478224145Sdim OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; 1479224145Sdim 1480224145Sdim OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; 1481224145Sdim OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n"; 1482224145Sdim 1483199481Srdivacky OS << "#include \"llvm/Support/Debug.h\"\n"; 1484199481Srdivacky OS << "#include \"llvm/Support/raw_ostream.h\"\n"; 1485224145Sdim ParseFeaturesFunction(OS, NumFeatures, NumProcs); 1486207618Srdivacky 1487224145Sdim OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; 1488224145Sdim 1489224145Sdim // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. 1490224145Sdim OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; 1491224145Sdim OS << "#undef GET_SUBTARGETINFO_HEADER\n"; 1492224145Sdim 1493224145Sdim std::string ClassName = Target + "GenSubtargetInfo"; 1494224145Sdim OS << "namespace llvm {\n"; 1495234353Sdim OS << "class DFAPacketizer;\n"; 1496224145Sdim OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" 1497224145Sdim << " explicit " << ClassName << "(StringRef TT, StringRef CPU, " 1498224145Sdim << "StringRef FS);\n" 1499234353Sdim << "public:\n" 1500243830Sdim << " unsigned resolveSchedClass(unsigned SchedClass, const MachineInstr *DefMI," 1501243830Sdim << " const TargetSchedModel *SchedModel) const;\n" 1502234353Sdim << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" 1503234353Sdim << " const;\n" 1504224145Sdim << "};\n"; 1505224145Sdim OS << "} // End llvm namespace \n"; 1506224145Sdim 1507224145Sdim OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; 1508224145Sdim 1509224145Sdim OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; 1510224145Sdim OS << "#undef GET_SUBTARGETINFO_CTOR\n"; 1511224145Sdim 1512243830Sdim OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; 1513224145Sdim OS << "namespace llvm {\n"; 1514234353Sdim OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; 1515234353Sdim OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; 1516243830Sdim OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; 1517243830Sdim OS << "extern const llvm::MCWriteProcResEntry " 1518243830Sdim << Target << "WriteProcResTable[];\n"; 1519243830Sdim OS << "extern const llvm::MCWriteLatencyEntry " 1520243830Sdim << Target << "WriteLatencyTable[];\n"; 1521243830Sdim OS << "extern const llvm::MCReadAdvanceEntry " 1522243830Sdim << Target << "ReadAdvanceTable[];\n"; 1523243830Sdim 1524249423Sdim if (SchedModels.hasItineraries()) { 1525234353Sdim OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; 1526234353Sdim OS << "extern const unsigned " << Target << "OperandCycles[];\n"; 1527239462Sdim OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; 1528224145Sdim } 1529224145Sdim 1530224145Sdim OS << ClassName << "::" << ClassName << "(StringRef TT, StringRef CPU, " 1531224145Sdim << "StringRef FS)\n" 1532224145Sdim << " : TargetSubtargetInfo() {\n" 1533224145Sdim << " InitMCSubtargetInfo(TT, CPU, FS, "; 1534224145Sdim if (NumFeatures) 1535224145Sdim OS << Target << "FeatureKV, "; 1536224145Sdim else 1537224145Sdim OS << "0, "; 1538224145Sdim if (NumProcs) 1539224145Sdim OS << Target << "SubTypeKV, "; 1540224145Sdim else 1541224145Sdim OS << "0, "; 1542243830Sdim OS << '\n'; OS.indent(22); 1543243830Sdim OS << Target << "ProcSchedKV, " 1544243830Sdim << Target << "WriteProcResTable, " 1545243830Sdim << Target << "WriteLatencyTable, " 1546243830Sdim << Target << "ReadAdvanceTable, "; 1547243830Sdim OS << '\n'; OS.indent(22); 1548249423Sdim if (SchedModels.hasItineraries()) { 1549243830Sdim OS << Target << "Stages, " 1550224145Sdim << Target << "OperandCycles, " 1551239462Sdim << Target << "ForwardingPaths, "; 1552224145Sdim } else 1553243830Sdim OS << "0, 0, 0, "; 1554224145Sdim OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; 1555243830Sdim 1556243830Sdim EmitSchedModelHelpers(ClassName, OS); 1557243830Sdim 1558224145Sdim OS << "} // End llvm namespace \n"; 1559224145Sdim 1560224145Sdim OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; 1561193323Sed} 1562239462Sdim 1563239462Sdimnamespace llvm { 1564239462Sdim 1565239462Sdimvoid EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { 1566239462Sdim CodeGenTarget CGTarget(RK); 1567239462Sdim SubtargetEmitter(RK, CGTarget).run(OS); 1568239462Sdim} 1569239462Sdim 1570239462Sdim} // End llvm namespace 1571