diff options
Diffstat (limited to 'utils/TableGen/SubtargetEmitter.cpp')
-rw-r--r-- | utils/TableGen/SubtargetEmitter.cpp | 370 |
1 files changed, 215 insertions, 155 deletions
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 986c50f..3472343 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -11,14 +11,60 @@ // //===----------------------------------------------------------------------===// -#include "SubtargetEmitter.h" #include "CodeGenTarget.h" -#include "llvm/TableGen/Record.h" +#include "CodeGenSchedule.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/MC/MCInstrItineraries.h" #include "llvm/Support/Debug.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" #include <algorithm> +#include <map> +#include <string> +#include <vector> using namespace llvm; +namespace { +class SubtargetEmitter { + + RecordKeeper &Records; + CodeGenSchedModels &SchedModels; + std::string Target; + + void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits); + unsigned FeatureKeyValues(raw_ostream &OS); + unsigned CPUKeyValues(raw_ostream &OS); + void FormItineraryStageString(const std::string &Names, + Record *ItinData, std::string &ItinString, + unsigned &NStages); + void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, + unsigned &NOperandCycles); + void FormItineraryBypassString(const std::string &Names, + Record *ItinData, + std::string &ItinString, unsigned NOperandCycles); + void EmitStageAndOperandCycleData(raw_ostream &OS, + std::vector<std::vector<InstrItinerary> > + &ProcItinLists); + void EmitItineraries(raw_ostream &OS, + std::vector<std::vector<InstrItinerary> > + &ProcItinLists); + void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name, + char Separator); + void EmitProcessorModels(raw_ostream &OS); + void EmitProcessorLookup(raw_ostream &OS); + void EmitSchedModel(raw_ostream &OS); + void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, + unsigned NumProcs); + +public: + SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT): + Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {} + + void run(raw_ostream &o); + +}; +} // End anonymous namespace + // // Enumeration - Emit the specified class as an enumeration. // @@ -196,28 +242,6 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { } // -// CollectAllItinClasses - Gathers and enumerates all the itinerary classes. -// Returns itinerary class count. -// -unsigned SubtargetEmitter:: -CollectAllItinClasses(raw_ostream &OS, - std::map<std::string, unsigned> &ItinClassesMap, - std::vector<Record*> &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 // of stages. @@ -303,32 +327,31 @@ 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<std::string, unsigned> &ItinClassesMap, - std::vector<Record*> &ItinClassList, - std::vector<std::vector<InstrItinerary> > &ProcList) { - // Gather processor iteraries - std::vector<Record*> 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<std::vector<InstrItinerary> > + &ProcItinLists) { + + // Multiple processor models may share an itinerary record. Emit it once. + SmallPtrSet<Record*, 8> ItinsDefSet; // 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) { + + if (!ItinsDefSet.insert(PI->ItinsDef)) + continue; - std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU"); + std::vector<Record*> 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) @@ -337,7 +360,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, OS << "}\n"; - std::vector<Record*> BPs = Proc->getValueAsListOfDefs("BP"); + std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP"); if (BPs.size()) { OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name << "\"\n" << "namespace " << Name << "Bypass {\n"; @@ -363,47 +386,57 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, // Begin pipeline bypass table std::string BypassTable = "extern const unsigned " + Target + - "ForwardingPathes[] = {\n"; - BypassTable += " 0, // No itinerary\n"; + "ForwardingPaths[] = {\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<std::string, unsigned> ItinStageMap, ItinOperandMap; - 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) { + const CodeGenProcModel &ProcModel = *PI; - // Get processor itinerary name - const std::string &Name = Proc->getName(); + // Add process itinerary to the list. + ProcItinLists.resize(ProcItinLists.size()+1); - // Skip default - if (Name == "NoItineraries") continue; + // If this processor defines no itineraries, then leave the itinerary list + // empty. + std::vector<InstrItinerary> &ItinList = ProcItinLists.back(); + if (ProcModel.ItinDefList.empty()) + continue; - // Create and expand processor itinerary to cover all itinerary classes - std::vector<InstrItinerary> ItinList; - ItinList.resize(NItinClasses); + // Reserve index==0 for NoItinerary. + ItinList.resize(SchedModels.numItineraryClasses()+1); - // Get itinerary data list - std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID"); + 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; @@ -443,33 +476,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 - unsigned NumUOps = ItinClassList[Find]->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. @@ -479,61 +505,100 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, } // -// 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<Record*> &ItinClassList, - std::vector<std::vector<InstrItinerary> > &ProcList) { - // Get an iterator for processor itinerary stages +EmitItineraries(raw_ostream &OS, + std::vector<std::vector<InstrItinerary> > &ProcItinLists) { + + // Multiple processor models may share an itinerary record. Emit it once. + SmallPtrSet<Record*, 8> ItinsDefSet; + + // For each processor's machine model std::vector<std::vector<InstrItinerary> >::iterator - ProcListIter = ProcList.begin(); + ProcItinListsIter = ProcItinLists.begin(); + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { - // For each processor itinerary - std::vector<Record*> Itins = - Records.getAllDerivedDefinitions("ProcessorItineraries"); - for (unsigned i = 0, N = Itins.size(); i < N; i++) { - // Next record - Record *Itin = Itins[i]; + Record *ItinsDef = PI->ItinsDef; + if (!ItinsDefSet.insert(ItinsDef)) + continue; // Get processor itinerary name - const std::string &Name = Itin->getName(); + const std::string &Name = ItinsDef->getName(); - // Skip default - if (Name == "NoItineraries") continue; + // Get the itinerary list for the processor. + assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator"); + std::vector<InstrItinerary> &ItinList = *ProcItinListsIter++; - // Begin processor itinerary table OS << "\n"; - OS << "static const llvm::InstrItinerary " << Name << "[] = {\n"; + OS << "static const llvm::InstrItinerary "; + if (ItinList.empty()) { + OS << '*' << Name << " = 0;\n"; + continue; + } - // For each itinerary class - std::vector<InstrItinerary> &ItinList = *ProcListIter++; - assert(ItinList.size() == ItinClassList.size() && "bad itinerary"); + // 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 in the form of + // Emit Itinerary 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"; + OS << " { " << + Intinerary.NumMicroOps << ", " << + Intinerary.FirstStage << ", " << + Intinerary.LastStage << ", " << + Intinerary.FirstOperandCycle << ", " << + Intinerary.LastOperandCycle << " }" << + ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; } - // End processor itinerary table - OS << " { 1, ~0U, ~0U, ~0U, ~0U } // end marker\n"; + OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n"; OS << "};\n"; } } +// Emit either 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", ','); + EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); + if (SchedModels.hasItineraryClasses()) + OS << " " << PI->ItinsDef->getName(); + else + OS << " 0"; + OS << ");\n"; + } +} + // // EmitProcessorLookup - generate cpu name to itinerary lookup table. // @@ -547,7 +612,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;) { @@ -555,13 +620,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 << " }"; @@ -576,31 +641,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<std::string, unsigned> ItinClassesMap; - // Gather and sort all itinerary classes - std::vector<Record*> 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<std::vector<InstrItinerary> > ProcList; +void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { + if (SchedModels.hasItineraryClasses()) { + std::vector<std::vector<InstrItinerary> > 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); } // @@ -620,7 +673,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, OS << Target; OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" - << " DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n"; + << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; if (Features.empty()) { OS << "}\n"; @@ -654,9 +707,7 @@ 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); + emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; OS << "#undef GET_SUBTARGETINFO_ENUM\n"; @@ -677,7 +728,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"; @@ -696,11 +747,11 @@ 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 << "ForwardingPathes, "; + << Target << "ForwardingPaths, "; } else OS << "0, 0, 0, 0, "; OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; @@ -742,11 +793,11 @@ 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 << "ForwardingPathes[];\n"; + OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; } OS << ClassName << "::" << ClassName << "(StringRef TT, StringRef CPU, " @@ -761,11 +812,11 @@ 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 << "ForwardingPathes, "; + << Target << "ForwardingPaths, "; } else OS << "0, 0, 0, 0, "; OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; @@ -773,3 +824,12 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; } + +namespace llvm { + +void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { + CodeGenTarget CGTarget(RK); + SubtargetEmitter(RK, CGTarget).run(OS); +} + +} // End llvm namespace |