diff options
author | Andrew Trick <atrick@apple.com> | 2012-07-07 04:00:00 +0000 |
---|---|---|
committer | Andrew Trick <atrick@apple.com> | 2012-07-07 04:00:00 +0000 |
commit | 2661b411ccc81b1fe19194d3f43b2630cbef3f28 (patch) | |
tree | 0decaebaee6c3a1a9d42df6b5619de1ffb2fac7d /utils/TableGen | |
parent | 06495cd7f2a91c4f659eac5e55b1c08b014d0a08 (diff) | |
download | external_llvm-2661b411ccc81b1fe19194d3f43b2630cbef3f28.zip external_llvm-2661b411ccc81b1fe19194d3f43b2630cbef3f28.tar.gz external_llvm-2661b411ccc81b1fe19194d3f43b2630cbef3f28.tar.bz2 |
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
Diffstat (limited to 'utils/TableGen')
-rw-r--r-- | utils/TableGen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | utils/TableGen/CodeGenSchedule.cpp | 151 | ||||
-rw-r--r-- | utils/TableGen/CodeGenSchedule.h | 172 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.cpp | 12 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.h | 8 | ||||
-rw-r--r-- | utils/TableGen/InstrInfoEmitter.cpp | 32 | ||||
-rw-r--r-- | utils/TableGen/SubtargetEmitter.cpp | 361 |
7 files changed, 508 insertions, 229 deletions
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index c5585f5..0e14cba 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -11,6 +11,7 @@ add_tablegen(llvm-tblgen LLVM CodeGenDAGPatterns.cpp CodeGenInstruction.cpp CodeGenRegisters.cpp + CodeGenSchedule.cpp CodeGenTarget.cpp DAGISelEmitter.cpp DAGISelMatcherEmitter.cpp diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp new file mode 100644 index 0000000..f57fd18 --- /dev/null +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -0,0 +1,151 @@ +//===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines structures to encapsulate the machine model as decribed in +// the target description. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "subtarget-emitter" + +#include "CodeGenSchedule.h" +#include "CodeGenTarget.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +// CodeGenModels ctor interprets machine model records and populates maps. +CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, + const CodeGenTarget &TGT): + Records(RK), Target(TGT), NumItineraryClasses(0), HasProcItineraries(false) { + + // Populate SchedClassIdxMap and set NumItineraryClasses. + CollectSchedClasses(); + + // Populate ProcModelMap. + CollectProcModels(); +} + +// Visit all the instruction definitions for this target to gather and enumerate +// the itinerary classes. These are the explicitly specified SchedClasses. More +// SchedClasses may be inferred. +void CodeGenSchedModels::CollectSchedClasses() { + + // NoItinerary is always the first class at Index=0 + SchedClasses.resize(1); + SchedClasses.back().Name = "NoItinerary"; + SchedClassIdxMap[SchedClasses.back().Name] = 0; + + // Gather and sort all itinerary classes used by instruction descriptions. + std::vector<Record*> ItinClassList; + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + Record *SchedDef = (*I)->TheDef->getValueAsDef("Itinerary"); + // Map a new SchedClass with no index. + if (!SchedClassIdxMap.count(SchedDef->getName())) { + SchedClassIdxMap[SchedDef->getName()] = 0; + ItinClassList.push_back(SchedDef); + } + } + // Assign each itinerary class unique number, skipping NoItinerary==0 + NumItineraryClasses = ItinClassList.size(); + std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); + for (unsigned i = 0, N = NumItineraryClasses; i < N; i++) { + Record *ItinDef = ItinClassList[i]; + SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size(); + SchedClasses.push_back(CodeGenSchedClass(ItinDef)); + } + + // TODO: Infer classes from non-itinerary scheduler resources. +} + +// Gather all processor models. +void CodeGenSchedModels::CollectProcModels() { + std::vector<Record*> ProcRecords = + Records.getAllDerivedDefinitions("Processor"); + std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); + + // Reserve space because we can. Reallocation would be ok. + ProcModels.reserve(ProcRecords.size()); + + // For each processor, find a unique machine model. + for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i) + addProcModel(ProcRecords[i]); +} + +// Get a unique processor model based on the defined MachineModel and +// ProcessorItineraries. +void CodeGenSchedModels::addProcModel(Record *ProcDef) { + unsigned Idx = getProcModelIdx(ProcDef); + if (Idx < ProcModels.size()) + return; + + Record *ModelDef = ProcDef->getValueAsDef("SchedModel"); + Record *ItinsDef = ProcDef->getValueAsDef("ProcItin"); + + std::string ModelName = ModelDef->getName(); + const std::string &ItinName = ItinsDef->getName(); + + bool NoModel = ModelDef->getValueAsBit("NoModel"); + bool hasTopLevelItin = !ItinsDef->getValueAsListOfDefs("IID").empty(); + if (NoModel) { + // If an itinerary is defined without a machine model, infer a new model. + if (NoModel && hasTopLevelItin) { + ModelName = ItinName + "Model"; + ModelDef = NULL; + } + } + else { + // If a machine model is defined, the itinerary must be defined within it + // rather than in the Processor definition itself. + assert(!hasTopLevelItin && "Itinerary must be defined in SchedModel"); + ItinsDef = ModelDef->getValueAsDef("Itineraries"); + } + + ProcModelMap[getProcModelKey(ProcDef)]= ProcModels.size(); + + ProcModels.push_back(CodeGenProcModel(ModelName, ModelDef, ItinsDef)); + + std::vector<Record*> ItinRecords = ItinsDef->getValueAsListOfDefs("IID"); + CollectProcItin(ProcModels.back(), ItinRecords); +} + +// Gather the processor itineraries. +void CodeGenSchedModels::CollectProcItin(CodeGenProcModel &ProcModel, + std::vector<Record*> ItinRecords) { + // Skip empty itinerary. + if (ItinRecords.empty()) + return; + + HasProcItineraries = true; + + ProcModel.ItinDefList.resize(NumItineraryClasses+1); + + // Insert each itinerary data record in the correct position within + // the processor model's ItinDefList. + for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { + Record *ItinData = ItinRecords[i]; + Record *ItinDef = ItinData->getValueAsDef("TheClass"); + if (!SchedClassIdxMap.count(ItinDef->getName())) { + DEBUG(dbgs() << ProcModel.ItinsDef->getName() + << " has unused itinerary class " << ItinDef->getName() << '\n'); + continue; + } + ProcModel.ItinDefList[getItinClassIdx(ItinDef)] = ItinData; + } +#ifndef NDEBUG + // Check for missing itinerary entries. + assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); + for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { + if (!ProcModel.ItinDefList[i]) + DEBUG(dbgs() << ProcModel.ItinsDef->getName() + << " missing itinerary for class " << SchedClasses[i].Name << '\n'); + } +#endif +} diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h new file mode 100644 index 0000000..9da0145 --- /dev/null +++ b/utils/TableGen/CodeGenSchedule.h @@ -0,0 +1,172 @@ +//===- CodeGenSchedule.h - Scheduling Machine Models ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines structures to encapsulate the machine model as decribed in +// the target description. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_SCHEDULE_H +#define CODEGEN_SCHEDULE_H + +#include "llvm/TableGen/Record.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" + +namespace llvm { + +class CodeGenTarget; + +// Scheduling class. +// +// Each instruction description will be mapped to a scheduling class. It may be +// an explicitly defined itinerary class, or an inferred class in which case +// ItinClassDef == NULL. +struct CodeGenSchedClass { + std::string Name; + unsigned Index; + Record *ItinClassDef; + + CodeGenSchedClass(): Index(0), ItinClassDef(0) {} + CodeGenSchedClass(Record *rec): Index(0), ItinClassDef(rec) { + Name = rec->getName(); + } +}; + +// Processor model. +// +// ModelName is a unique name used to name an instantiation of MCSchedModel. +// +// ModelDef is NULL for inferred Models. This happens when a processor defines +// an itinerary but no machine model. If the processer defines neither a machine +// model nor itinerary, then ModelDef remains pointing to NoModel. NoModel has +// the special "NoModel" field set to true. +// +// ItinsDef always points to a valid record definition, but may point to the +// default NoItineraries. NoItineraries has an empty list of InstrItinData +// records. +// +// ItinDefList orders this processor's InstrItinData records by SchedClass idx. +struct CodeGenProcModel { + std::string ModelName; + Record *ModelDef; + Record *ItinsDef; + + // Array of InstrItinData records indexed by CodeGenSchedClass::Index. + // The list is empty if the subtarget has no itineraries. + std::vector<Record *> ItinDefList; + + CodeGenProcModel(const std::string &Name, Record *MDef, Record *IDef): + ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} +}; + +// Top level container for machine model data. +class CodeGenSchedModels { + RecordKeeper &Records; + const CodeGenTarget &Target; + + // List of unique SchedClasses. + std::vector<CodeGenSchedClass> SchedClasses; + + // Map SchedClass name to itinerary index. + // These are either explicit itinerary classes or inferred classes. + StringMap<unsigned> SchedClassIdxMap; + + // SchedClass indices 1 up to and including NumItineraryClasses identify + // itinerary classes that are explicitly used for this target's instruction + // definitions. NoItinerary always has index 0 regardless of whether it is + // explicitly referenced. + // + // Any inferred SchedClass have a index greater than NumItineraryClasses. + unsigned NumItineraryClasses; + + // List of unique processor models. + std::vector<CodeGenProcModel> ProcModels; + + // Map Processor's MachineModel + ProcItin fields to a CodeGenProcModel index. + typedef DenseMap<std::pair<Record*, Record*>, unsigned> ProcModelMapTy; + ProcModelMapTy ProcModelMap; + + // True if any processors have nonempty itineraries. + bool HasProcItineraries; + +public: + CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT); + + // Check if any instructions are assigned to an explicit itinerary class other + // than NoItinerary. + bool hasItineraryClasses() const { return NumItineraryClasses > 0; } + + // Return the number of itinerary classes in use by this target's instruction + // descriptions, not including "NoItinerary". + unsigned numItineraryClasses() const { + return NumItineraryClasses; + } + + // Get a SchedClass from its index. + const CodeGenSchedClass &getSchedClass(unsigned Idx) { + assert(Idx < SchedClasses.size() && "bad SchedClass index"); + return SchedClasses[Idx]; + } + + // Get an itinerary class's index. Value indices are '0' for NoItinerary up to + // and including numItineraryClasses(). + unsigned getItinClassIdx(Record *ItinDef) const { + assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); + unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); + assert(Idx <= NumItineraryClasses && "bad ItinClass index"); + return Idx; + } + + bool hasProcessorItineraries() const { + return HasProcItineraries; + } + + // Get an existing machine model for a processor definition. + const CodeGenProcModel &getProcModel(Record *ProcDef) const { + unsigned idx = getProcModelIdx(ProcDef); + assert(idx < ProcModels.size() && "missing machine model"); + return ProcModels[idx]; + } + + // Iterate over the unique processor models. + typedef std::vector<CodeGenProcModel>::const_iterator ProcIter; + ProcIter procModelBegin() const { return ProcModels.begin(); } + ProcIter procModelEnd() const { return ProcModels.end(); } + +private: + // Get a key that can uniquely identify a machine model. + ProcModelMapTy::key_type getProcModelKey(Record *ProcDef) const { + Record *ModelDef = ProcDef->getValueAsDef("SchedModel"); + Record *ItinsDef = ProcDef->getValueAsDef("ProcItin"); + return std::make_pair(ModelDef, ItinsDef); + } + + // Get the unique index of a machine model. + unsigned getProcModelIdx(Record *ProcDef) const { + ProcModelMapTy::const_iterator I = + ProcModelMap.find(getProcModelKey(ProcDef)); + if (I == ProcModelMap.end()) + return ProcModels.size(); + return I->second; + } + + // Initialize a new processor model if it is unique. + void addProcModel(Record *ProcDef); + + void CollectSchedClasses(); + void CollectProcModels(); + void CollectProcItin(CodeGenProcModel &ProcModel, + std::vector<Record*> ItinRecords); +}; + +} // namespace llvm + +#endif diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index 4bc4c54..1dd2efc 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -16,6 +16,7 @@ #include "CodeGenTarget.h" #include "CodeGenIntrinsics.h" +#include "CodeGenSchedule.h" #include "llvm/TableGen/Record.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" @@ -112,7 +113,7 @@ std::string llvm::getQualifiedName(const Record *R) { /// getTarget - Return the current instance of the Target class. /// CodeGenTarget::CodeGenTarget(RecordKeeper &records) - : Records(records), RegBank(0) { + : Records(records), RegBank(0), SchedModels(0) { std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target"); if (Targets.size() == 0) throw std::string("ERROR: No 'Target' subclasses defined!"); @@ -121,6 +122,10 @@ CodeGenTarget::CodeGenTarget(RecordKeeper &records) TargetRec = Targets[0]; } +CodeGenTarget::~CodeGenTarget() { + delete RegBank; + delete SchedModels; +} const std::string &CodeGenTarget::getName() const { return TargetRec->getName(); @@ -235,6 +240,11 @@ void CodeGenTarget::ReadLegalValueTypes() const { LegalValueTypes.end()); } +CodeGenSchedModels &CodeGenTarget::getSchedModels() const { + if (!SchedModels) + SchedModels = new CodeGenSchedModels(Records, *this); + return *SchedModels; +} void CodeGenTarget::ReadInstructions() const { std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 85463da..2f8cee4 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -26,6 +26,7 @@ namespace llvm { struct CodeGenRegister; +class CodeGenSchedModels; class CodeGenTarget; // SelectionDAG node properties. @@ -72,9 +73,12 @@ class CodeGenTarget { void ReadInstructions() const; void ReadLegalValueTypes() const; + mutable CodeGenSchedModels *SchedModels; + mutable std::vector<const CodeGenInstruction*> InstrsByEnum; public: CodeGenTarget(RecordKeeper &Records); + ~CodeGenTarget(); Record *getTargetRecord() const { return TargetRec; } const std::string &getName() const; @@ -96,7 +100,7 @@ public: /// Record *getAsmParserVariant(unsigned i) const; - /// getAsmParserVariantCount - Return the AssmblyParserVariant definition + /// getAsmParserVariantCount - Return the AssmblyParserVariant definition /// available for this target. /// unsigned getAsmParserVariantCount() const; @@ -139,6 +143,8 @@ public: return false; } + CodeGenSchedModels &getSchedModels() const; + private: DenseMap<const Record*, CodeGenInstruction*> &getInstructions() const { if (Instructions.empty()) ReadInstructions(); diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 600586f..3adb869 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -14,6 +14,7 @@ #include "CodeGenDAGPatterns.h" +#include "CodeGenSchedule.h" #include "CodeGenTarget.h" #include "SequenceToOffsetTable.h" #include "llvm/ADT/StringExtras.h" @@ -29,10 +30,11 @@ namespace { class InstrInfoEmitter { RecordKeeper &Records; CodeGenDAGPatterns CDP; - std::map<std::string, unsigned> ItinClassMap; + const CodeGenSchedModels &SchedModels; public: - InstrInfoEmitter(RecordKeeper &R) : Records(R), CDP(R) { } + InstrInfoEmitter(RecordKeeper &R): + Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {} // run - Output the instruction set description. void run(raw_ostream &OS); @@ -47,10 +49,6 @@ private: const OperandInfoMapTy &OpInfo, raw_ostream &OS); - // Itinerary information. - void GatherItinClasses(); - unsigned getItinClassNumber(const Record *InstRec); - // Operand information. void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs); std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst); @@ -66,23 +64,6 @@ static void PrintDefList(const std::vector<Record*> &Uses, } //===----------------------------------------------------------------------===// -// Instruction Itinerary Information. -//===----------------------------------------------------------------------===// - -void InstrInfoEmitter::GatherItinClasses() { - std::vector<Record*> DefList = - Records.getAllDerivedDefinitions("InstrItinClass"); - std::sort(DefList.begin(), DefList.end(), LessRecord()); - - for (unsigned i = 0, N = DefList.size(); i < N; i++) - ItinClassMap[DefList[i]->getName()] = i; -} - -unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) { - return ItinClassMap[InstRec->getValueAsDef("Itinerary")->getName()]; -} - -//===----------------------------------------------------------------------===// // Operand Info Emission. //===----------------------------------------------------------------------===// @@ -202,8 +183,6 @@ void InstrInfoEmitter::run(raw_ostream &OS) { emitSourceFileHeader("Target Instruction Enum Values", OS); emitEnums(OS); - GatherItinClasses(); - emitSourceFileHeader("Target Instruction Descriptors", OS); OS << "\n#ifdef GET_INSTRINFO_MC_DESC\n"; @@ -325,10 +304,11 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, MinOperands = Inst.Operands.back().MIOperandNo + Inst.Operands.back().MINumOperands; + Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary"); OS << " { "; OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t" - << getItinClassNumber(Inst.TheDef) << ",\t" + << SchedModels.getItinClassIdx(ItinDef) << ",\t" << Inst.TheDef->getValueAsInt("Size") << ",\t0"; // Emit all of the target indepedent flags... diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 1c37d15..48dbdc2 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<std::string,unsigned> &ItinClassesMap, - std::vector<Record*> &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<std::string, unsigned> &ItinClassesMap, - std::vector<Record*> &ItinClassList, - std::vector<std::vector<InstrItinerary> > &ProcList); - void EmitItineraryProp(raw_ostream &OS, const Record *R, const char *Name, + 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 EmitProcessorData(raw_ostream &OS, - std::vector<Record*> &ItinClassList, - std::vector<std::vector<InstrItinerary> > &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); @@ -243,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. @@ -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<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) { // 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<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) @@ -384,7 +354,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"; @@ -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<std::string, unsigned> 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<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID"); - std::vector<InstrItinerary> 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<InstrItinerary> &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<Record*> &ItinClassList, - std::vector<std::vector<InstrItinerary> > &ProcList) { +EmitItineraries(raw_ostream &OS, + std::vector<std::vector<InstrItinerary> > &ProcItinLists) { - // Get an iterator for processor itinerary stages + // For each processor's machine model std::vector<std::vector<InstrItinerary> >::iterator - ProcListIter = ProcList.begin(); - - // 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]; + 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<InstrItinerary> &ItinList = *ProcItinListsIter++; - // For each itinerary class - std::vector<InstrItinerary> &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<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); } // @@ -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 |