From 2661b411ccc81b1fe19194d3f43b2630cbef3f28 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Sat, 7 Jul 2012 04:00:00 +0000 Subject: I'm introducing a new machine model to simultaneously allow simple subtarget CPU descriptions and support new features of MachineScheduler. MachineModel has three categories of data: 1) Basic properties for coarse grained instruction cost model. 2) Scheduler Read/Write resources for simple per-opcode and operand cost model (TBD). 3) Instruction itineraties for detailed per-cycle reservation tables. These will all live side-by-side. Any subtarget can use any combination of them. Instruction itineraries will not change in the near term. In the long run, I expect them to only be relevant for in-order VLIW machines that have complex contraints and require a precise scheduling/bundling model. Once itineraries are only actively used by VLIW-ish targets, they could be replaced by something more appropriate for those targets. This tablegen backend rewrite sets things up for introducing MachineModel type #2: per opcode/operand cost model. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159891 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/SubtargetEmitter.cpp | 361 ++++++++++++++++-------------------- 1 file changed, 160 insertions(+), 201 deletions(-) (limited to 'utils/TableGen/SubtargetEmitter.cpp') diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 1c37d15fe8..48dbdc2c7c 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenTarget.h" +#include "CodeGenSchedule.h" #include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/Support/Debug.h" @@ -27,15 +28,12 @@ namespace { class SubtargetEmitter { RecordKeeper &Records; + CodeGenSchedModels &SchedModels; std::string Target; - bool HasItineraries; void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits); unsigned FeatureKeyValues(raw_ostream &OS); unsigned CPUKeyValues(raw_ostream &OS); - unsigned CollectAllItinClasses(raw_ostream &OS, - std::map &ItinClassesMap, - std::vector &ItinClassList); void FormItineraryStageString(const std::string &Names, Record *ItinData, std::string &ItinString, unsigned &NStages); @@ -44,22 +42,23 @@ class SubtargetEmitter { void FormItineraryBypassString(const std::string &Names, Record *ItinData, std::string &ItinString, unsigned NOperandCycles); - void EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses, - std::map &ItinClassesMap, - std::vector &ItinClassList, - std::vector > &ProcList); - void EmitItineraryProp(raw_ostream &OS, const Record *R, const char *Name, + void EmitStageAndOperandCycleData(raw_ostream &OS, + std::vector > + &ProcItinLists); + void EmitItineraries(raw_ostream &OS, + std::vector > + &ProcItinLists); + void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name, char Separator); - void EmitProcessorData(raw_ostream &OS, - std::vector &ItinClassList, - std::vector > &ProcList); + void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); - void EmitData(raw_ostream &OS); + void EmitSchedModel(raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, unsigned NumProcs); public: - SubtargetEmitter(RecordKeeper &R) : Records(R), HasItineraries(false) {} + SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT): + Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {} void run(raw_ostream &o); @@ -242,28 +241,6 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { return ProcessorList.size(); } -// -// CollectAllItinClasses - Gathers and enumerates all the itinerary classes. -// Returns itinerary class count. -// -unsigned SubtargetEmitter:: -CollectAllItinClasses(raw_ostream &OS, - std::map &ItinClassesMap, - std::vector &ItinClassList) { - // For each itinerary class - unsigned N = ItinClassList.size(); - for (unsigned i = 0; i < N; i++) { - // Next itinerary class - const Record *ItinClass = ItinClassList[i]; - // Get name of itinerary class - // Assign itinerary class a unique number - ItinClassesMap[ItinClass->getName()] = i; - } - - // Return itinerary class count - return N; -} - // // FormItineraryStageString - Compose a string containing the stage // data initialization for the specified itinerary. N is the number @@ -350,32 +327,25 @@ void SubtargetEmitter::FormItineraryBypassString(const std::string &Name, } // -// EmitStageAndOperandCycleData - Generate unique itinerary stages and -// operand cycle tables. Record itineraries for processors. +// EmitStageAndOperandCycleData - Generate unique itinerary stages and operand +// cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed +// by CodeGenSchedClass::Index. // -void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, - unsigned NItinClasses, - std::map &ItinClassesMap, - std::vector &ItinClassList, - std::vector > &ProcList) { - // Gather processor iteraries - std::vector ProcItinList = - Records.getAllDerivedDefinitions("ProcessorItineraries"); - - // If just no itinerary then don't bother - if (ProcItinList.size() < 2) return; +void SubtargetEmitter:: +EmitStageAndOperandCycleData(raw_ostream &OS, + std::vector > + &ProcItinLists) { // Emit functional units for all the itineraries. - for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) { - // Next record - Record *Proc = ProcItinList[i]; + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { - std::vector FUs = Proc->getValueAsListOfDefs("FU"); + std::vector FUs = PI->ItinsDef->getValueAsListOfDefs("FU"); if (FUs.empty()) continue; - const std::string &Name = Proc->getName(); - OS << "\n// Functional units for itineraries \"" << Name << "\"\n" + const std::string &Name = PI->ItinsDef->getName(); + OS << "\n// Functional units for \"" << Name << "\"\n" << "namespace " << Name << "FU {\n"; for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j) @@ -384,7 +354,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, OS << "}\n"; - std::vector BPs = Proc->getValueAsListOfDefs("BP"); + std::vector BPs = PI->ItinsDef->getValueAsListOfDefs("BP"); if (BPs.size()) { OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name << "\"\n" << "namespace " << Name << "Bypass {\n"; @@ -411,49 +381,56 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, // Begin pipeline bypass table std::string BypassTable = "extern const unsigned " + Target + "ForwardingPaths[] = {\n"; - BypassTable += " 0, // No itinerary\n"; + BypassTable += " 0, // No itinerary\n"; + // For each Itinerary across all processors, add a unique entry to the stages, + // operand cycles, and pipepine bypess tables. Then add the new Itinerary + // object with computed offsets to the ProcItinLists result. unsigned StageCount = 1, OperandCycleCount = 1; std::map ItinStageMap, ItinOperandMap; - for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) { - // Next record - Record *Proc = ProcItinList[i]; - - // Get processor itinerary name - const std::string &Name = Proc->getName(); + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + const CodeGenProcModel &ProcModel = *PI; - // Get itinerary data list - std::vector ItinDataList = Proc->getValueAsListOfDefs("IID"); - std::vector ItinList; + // Add process itinerary to the list. + ProcItinLists.resize(ProcItinLists.size()+1); - // Add an empty itinerary. - if (ItinDataList.empty()) { - ProcList.push_back(ItinList); + // If this processor defines no itineraries, then leave the itinerary list + // empty. + std::vector &ItinList = ProcItinLists.back(); + if (ProcModel.ItinDefList.empty()) continue; - } - // Expand processor itinerary to cover all itinerary classes - ItinList.resize(NItinClasses); + // Reserve index==0 for NoItinerary. + ItinList.resize(SchedModels.numItineraryClasses()+1); + + const std::string &Name = ProcModel.ItinsDef->getName(); // For each itinerary data - for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) { + for (unsigned SchedClassIdx = 0, + SchedClassEnd = ProcModel.ItinDefList.size(); + SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { + // Next itinerary data - Record *ItinData = ItinDataList[j]; + Record *ItinData = ProcModel.ItinDefList[SchedClassIdx]; // Get string and stage count std::string ItinStageString; - unsigned NStages; - FormItineraryStageString(Name, ItinData, ItinStageString, NStages); + unsigned NStages = 0; + if (ItinData) + FormItineraryStageString(Name, ItinData, ItinStageString, NStages); // Get string and operand cycle count std::string ItinOperandCycleString; - unsigned NOperandCycles; - FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, - NOperandCycles); - + unsigned NOperandCycles = 0; std::string ItinBypassString; - FormItineraryBypassString(Name, ItinData, ItinBypassString, - NOperandCycles); + if (ItinData) { + FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, + NOperandCycles); + + FormItineraryBypassString(Name, ItinData, ItinBypassString, + NOperandCycles); + } // Check to see if stage already exists and create if it doesn't unsigned FindStage = 0; @@ -493,33 +470,26 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, } } - // Locate where to inject into processor itinerary table - const std::string &Name = ItinData->getValueAsDef("TheClass")->getName(); - unsigned Find = ItinClassesMap[Name]; - // Set up itinerary as location and location + stage count - int NumUOps = ItinData->getValueAsInt("NumMicroOps"); + int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, FindOperandCycle, FindOperandCycle + NOperandCycles}; // Inject - empty slots will be 0, 0 - ItinList[Find] = Intinerary; + ItinList[SchedClassIdx] = Intinerary; } - - // Add process itinerary to list - ProcList.push_back(ItinList); } // Closing stage - StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n"; + StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n"; StageTable += "};\n"; // Closing operand cycles - OperandCycleTable += " 0 // End itinerary\n"; + OperandCycleTable += " 0 // End operand cycles\n"; OperandCycleTable += "};\n"; - BypassTable += " 0 // End itinerary\n"; + BypassTable += " 0 // End bypass tables\n"; BypassTable += "};\n"; // Emit tables. @@ -528,92 +498,94 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, OS << BypassTable; } -void SubtargetEmitter::EmitItineraryProp(raw_ostream &OS, const Record *R, - const char *Name, char Separator) { - OS << " "; - int V = R->getValueAsInt(Name); - if (V >= 0) - OS << V << Separator << " // " << Name; - else - OS << "InstrItineraryProps::Default" << Name << Separator; - OS << '\n'; -} - // -// EmitProcessorData - Generate data for processor itineraries. +// EmitProcessorData - Generate data for processor itineraries that were +// computed during EmitStageAndOperandCycleData(). ProcItinLists lists all +// Itineraries for each processor. The Itinerary lists are indexed on +// CodeGenSchedClass::Index. // void SubtargetEmitter:: -EmitProcessorData(raw_ostream &OS, - std::vector &ItinClassList, - std::vector > &ProcList) { +EmitItineraries(raw_ostream &OS, + std::vector > &ProcItinLists) { - // Get an iterator for processor itinerary stages + // For each processor's machine model std::vector >::iterator - ProcListIter = ProcList.begin(); - - // For each processor itinerary - std::vector Itins = - Records.getAllDerivedDefinitions("ProcessorItineraries"); - for (unsigned i = 0, N = Itins.size(); i < N; i++) { - // Next record - Record *Itin = Itins[i]; + ProcItinListsIter = ProcItinLists.begin(); + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + Record *ItinsDef = PI->ItinsDef; // Get processor itinerary name - const std::string &Name = Itin->getName(); + const std::string &Name = ItinsDef->getName(); - // Skip default - // Begin processor itinerary properties - OS << "\n"; - OS << "static const llvm::InstrItineraryProps " << Name << "Props(\n"; - EmitItineraryProp(OS, Itin, "IssueWidth", ','); - EmitItineraryProp(OS, Itin, "MinLatency", ','); - EmitItineraryProp(OS, Itin, "LoadLatency", ','); - EmitItineraryProp(OS, Itin, "HighLatency", ' '); - OS << ");\n"; + // Get the itinerary list for the processor. + assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator"); + std::vector &ItinList = *ProcItinListsIter++; - // For each itinerary class - std::vector &ItinList = *ProcListIter++; - if (!ItinList.empty()) { - assert(ItinList.size() == ItinClassList.size() && "bad itinerary"); + OS << "\n"; + OS << "static const llvm::InstrItinerary "; + if (ItinList.empty()) { + OS << '*' << Name << " = 0;\n"; + continue; + } - // Begin processor itinerary table - OS << "\n"; - OS << "static const llvm::InstrItinerary " << Name << "Entries" - << "[] = {\n"; - - for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { - InstrItinerary &Intinerary = ItinList[j]; - - // Emit in the form of - // { firstStage, lastStage, firstCycle, lastCycle } // index - if (Intinerary.FirstStage == 0) { - OS << " { 1, 0, 0, 0, 0 }"; - } else { - OS << " { " << - Intinerary.NumMicroOps << ", " << - Intinerary.FirstStage << ", " << - Intinerary.LastStage << ", " << - Intinerary.FirstOperandCycle << ", " << - Intinerary.LastOperandCycle << " }"; - } - OS << ", // " << j << " " << ItinClassList[j]->getName() << "\n"; - } - // End processor itinerary table - OS << " { 1, ~0U, ~0U, ~0U, ~0U } // end marker\n"; - OS << "};\n"; + // Begin processor itinerary table + OS << Name << "[] = {\n"; + + // For each itinerary class in CodeGenSchedClass::Index order. + for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { + InstrItinerary &Intinerary = ItinList[j]; + + // Emit Itinerary in the form of + // { firstStage, lastStage, firstCycle, lastCycle } // index + OS << " { " << + Intinerary.NumMicroOps << ", " << + Intinerary.FirstStage << ", " << + Intinerary.LastStage << ", " << + Intinerary.FirstOperandCycle << ", " << + Intinerary.LastOperandCycle << " }" << + ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; } - OS << '\n'; - OS << "static const llvm::InstrItinerarySubtargetValue " - << Name << " = {\n"; - OS << " &" << Name << "Props,\n"; - if (ItinList.empty()) - OS << " 0\n"; - else - OS << " " << Name << "Entries\n"; + // End processor itinerary table + OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n"; OS << "};\n"; } } +// Emit either the the value defined in the TableGen Record, or the default +// value defined in the C++ header. The Record is null if the processor does not +// define a model. +void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, + const char *Name, char Separator) { + OS << " "; + int V = R ? R->getValueAsInt(Name) : -1; + if (V >= 0) + OS << V << Separator << " // " << Name; + else + OS << "MCSchedModel::Default" << Name << Separator; + OS << '\n'; +} + +void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { + // For each processor model. + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + // Skip default + // Begin processor itinerary properties + OS << "\n"; + OS << "static const llvm::MCSchedModel " << PI->ModelName << "(\n"; + EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ','); + EmitProcessorProp(OS, PI->ModelDef, "MinLatency", ','); + EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); + EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); + if (SchedModels.hasItineraryClasses()) + OS << " " << PI->ItinsDef->getName(); + else + OS << " 0"; + OS << ");\n"; + } +} + // // EmitProcessorLookup - generate cpu name to itinerary lookup table. // @@ -627,7 +599,7 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { OS << "\n"; OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" << "extern const llvm::SubtargetInfoKV " - << Target << "ProcItinKV[] = {\n"; + << Target << "ProcSchedKV[] = {\n"; // For each processor for (unsigned i = 0, N = ProcessorList.size(); i < N;) { @@ -635,13 +607,13 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { Record *Processor = ProcessorList[i]; const std::string &Name = Processor->getValueAsString("Name"); - const std::string &ProcItin = - Processor->getValueAsDef("ProcItin")->getName(); + const std::string &ProcModelName = + SchedModels.getProcModel(Processor).ModelName; // Emit as { "cpu", procinit }, OS << " { " << "\"" << Name << "\", " - << "(void *)&" << ProcItin; + << "(void *)&" << ProcModelName; OS << " }"; @@ -656,31 +628,19 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { } // -// EmitData - Emits all stages and itineries, folding common patterns. +// EmitSchedModel - Emits all scheduling model tables, folding common patterns. // -void SubtargetEmitter::EmitData(raw_ostream &OS) { - std::map ItinClassesMap; - // Gather and sort all itinerary classes - std::vector ItinClassList = - Records.getAllDerivedDefinitions("InstrItinClass"); - std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); - - // Enumerate all the itinerary classes - unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap, - ItinClassList); - // Make sure the rest is worth the effort - HasItineraries = NItinClasses != 1; // Ignore NoItinerary. - - if (HasItineraries) { - std::vector > ProcList; +void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { + if (SchedModels.hasItineraryClasses()) { + std::vector > ProcItinLists; // Emit the stage data - EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap, - ItinClassList, ProcList); - // Emit the processor itinerary data - EmitProcessorData(OS, ItinClassList, ProcList); - // Emit the processor lookup data - EmitProcessorLookup(OS); + EmitStageAndOperandCycleData(OS, ProcItinLists); + EmitItineraries(OS, ProcItinLists); } + // Emit the processor machine model + EmitProcessorModels(OS); + // Emit the processor lookup data + EmitProcessorLookup(OS); } // @@ -734,8 +694,6 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, // SubtargetEmitter::run - Main subtarget enumeration emitter. // void SubtargetEmitter::run(raw_ostream &OS) { - Target = CodeGenTarget(Records).getName(); - emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; @@ -757,7 +715,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "\n"; unsigned NumProcs = CPUKeyValues(OS); OS << "\n"; - EmitData(OS); + EmitSchedModel(OS); OS << "\n"; #if 0 OS << "}\n"; @@ -776,8 +734,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << Target << "SubTypeKV, "; else OS << "0, "; - if (HasItineraries) { - OS << Target << "ProcItinKV, " + if (SchedModels.hasItineraryClasses()) { + OS << Target << "ProcSchedKV, " << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; @@ -822,8 +780,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; - if (HasItineraries) { - OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcItinKV[];\n"; + if (SchedModels.hasItineraryClasses()) { + OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; OS << "extern const unsigned " << Target << "OperandCycles[];\n"; OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; @@ -841,8 +799,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << Target << "SubTypeKV, "; else OS << "0, "; - if (HasItineraries) { - OS << Target << "ProcItinKV, " + if (SchedModels.hasItineraryClasses()) { + OS << Target << "ProcSchedKV, " << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; @@ -857,7 +815,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { namespace llvm { void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { - SubtargetEmitter(RK).run(OS); + CodeGenTarget CGTarget(RK); + SubtargetEmitter(RK, CGTarget).run(OS); } } // End llvm namespace -- cgit v1.2.3