X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FSubtargetEmitter.cpp;h=b9f9d060394066abe55b08533218cb7660cf447e;hb=c50299bab64d9232d992ec3c42b9d5ddf03e5001;hp=cd034ef2e908e051fd52678411a90d74f2838e73;hpb=e127dfd0b175b5a336e61fecaad7fc2aec65d95c;p=oota-llvm.git diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index cd034ef2e90..b9f9d060394 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -11,16 +11,18 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "subtarget-emitter" + #include "CodeGenTarget.h" #include "CodeGenSchedule.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCInstrItineraries.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" #include #include #include @@ -36,6 +38,7 @@ class SubtargetEmitter { std::vector > ProcSchedClasses; std::vector WriteProcResources; std::vector WriteLatencies; + std::vector WriterNames; std::vector ReadAdvanceEntries; // Reserve an invalid entry at index 0 @@ -43,6 +46,7 @@ class SubtargetEmitter { ProcSchedClasses.resize(1); WriteProcResources.resize(1); WriteLatencies.resize(1); + WriterNames.push_back("InvalidWrite"); ReadAdvanceEntries.resize(1); } }; @@ -79,14 +83,18 @@ class SubtargetEmitter { char Separator); void EmitProcessorResources(const CodeGenProcModel &ProcModel, raw_ostream &OS); - Record *FindWriteResources(Record *WriteDef, + Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel); - Record *FindReadAdvance(Record *ReadDef, const CodeGenProcModel &ProcModel); + Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, + const CodeGenProcModel &ProcModel); + void ExpandProcResources(RecVec &PRVec, std::vector &Cycles, + const CodeGenProcModel &ProcModel); void GenSchedClassTables(const CodeGenProcModel &ProcModel, SchedClassTables &SchedTables); void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); + void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS); void EmitSchedModel(raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, unsigned NumProcs); @@ -439,17 +447,15 @@ EmitStageAndOperandCycleData(raw_ostream &OS, // If this processor defines no itineraries, then leave the itinerary list // empty. std::vector &ItinList = ProcItinLists.back(); - if (ProcModel.ItinDefList.empty()) + if (!ProcModel.hasItineraries()) continue; - // Reserve index==0 for NoItinerary. - ItinList.resize(SchedModels.numItineraryClasses()+1); - const std::string &Name = ProcModel.ItinsDef->getName(); - // For each itinerary data - for (unsigned SchedClassIdx = 0, - SchedClassEnd = ProcModel.ItinDefList.size(); + ItinList.resize(SchedModels.numInstrSchedClasses()); + assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); + + for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size(); SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { // Next itinerary data @@ -617,21 +623,33 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, raw_ostream &OS) { char Sep = ProcModel.ProcResourceDefs.empty() ? ' ' : ','; - OS << "\n// {Name, NumUnits, SuperIdx}\n"; + OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n"; OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName << "ProcResources" << "[] = {\n" - << " {DBGFIELD(\"InvalidUnit\") 0, 0}" << Sep << "\n"; + << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0}" << Sep << "\n"; for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { Record *PRDef = ProcModel.ProcResourceDefs[i]; - // Find the SuperIdx - unsigned SuperIdx = 0; Record *SuperDef = 0; - if (PRDef->getValueInit("Super")->isComplete()) { - SuperDef = - SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), ProcModel); - SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + unsigned SuperIdx = 0; + unsigned NumUnits = 0; + int BufferSize = PRDef->getValueAsInt("BufferSize"); + if (PRDef->isSubClassOf("ProcResGroup")) { + RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); + for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end(); + RUI != RUE; ++RUI) { + NumUnits += (*RUI)->getValueAsInt("NumUnits"); + } + } + else { + // Find the SuperIdx + if (PRDef->getValueInit("Super")->isComplete()) { + SuperDef = SchedModels.findProcResUnits( + PRDef->getValueAsDef("Super"), ProcModel); + SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + } + NumUnits = PRDef->getValueAsInt("NumUnits"); } // Emit the ProcResourceDesc if (i+1 == e) @@ -639,8 +657,8 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; if (PRDef->getName().size() < 15) OS.indent(15 - PRDef->getName().size()); - OS << PRDef->getValueAsInt("NumUnits") << ", " << SuperIdx - << "}" << Sep << " // #" << i+1; + OS << NumUnits << ", " << SuperIdx << ", " + << BufferSize << "}" << Sep << " // #" << i+1; if (SuperDef) OS << ", Super=" << SuperDef->getName(); OS << "\n"; @@ -651,48 +669,160 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, // Find the WriteRes Record that defines processor resources for this // SchedWrite. Record *SubtargetEmitter::FindWriteResources( - Record *WriteDef, const CodeGenProcModel &ProcModel) { + const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { // Check if the SchedWrite is already subtarget-specific and directly // specifies a set of processor resources. - if (WriteDef->isSubClassOf("SchedWriteRes")) - return WriteDef; + if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) + return SchedWrite.TheDef; + + Record *AliasDef = 0; + for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + if (&SchedModels.getProcModel(ModelDef) != &ProcModel) + continue; + } + if (AliasDef) + PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) + return AliasDef; // Check this processor's list of write resources. + Record *ResDef = 0; for (RecIter WRI = ProcModel.WriteResDefs.begin(), WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) { if (!(*WRI)->isSubClassOf("WriteRes")) continue; - if (WriteDef == (*WRI)->getValueAsDef("WriteType")) - return *WRI; + if (AliasDef == (*WRI)->getValueAsDef("WriteType") + || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) { + if (ResDef) { + PrintFatalError((*WRI)->getLoc(), "Resources are defined for both " + "SchedWrite and its alias on processor " + + ProcModel.ModelName); + } + ResDef = *WRI; + } + } + // TODO: If ProcModel has a base model (previous generation processor), + // then call FindWriteResources recursively with that model here. + if (!ResDef) { + PrintFatalError(ProcModel.ModelDef->getLoc(), + std::string("Processor does not define resources for ") + + SchedWrite.TheDef->getName()); } - throw TGError(ProcModel.ModelDef->getLoc(), - std::string("Processor does not define resources for ") - + WriteDef->getName()); + return ResDef; } /// Find the ReadAdvance record for the given SchedRead on this processor or /// return NULL. -Record *SubtargetEmitter::FindReadAdvance(Record *ReadDef, +Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, const CodeGenProcModel &ProcModel) { // Check for SchedReads that directly specify a ReadAdvance. - if (ReadDef->isSubClassOf("SchedReadAdvance")) - return ReadDef; + if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) + return SchedRead.TheDef; + + // Check this processor's list of aliases for SchedRead. + Record *AliasDef = 0; + for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + if (&SchedModels.getProcModel(ModelDef) != &ProcModel) + continue; + } + if (AliasDef) + PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) + return AliasDef; // Check this processor's ReadAdvanceList. + Record *ResDef = 0; for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(), RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) { if (!(*RAI)->isSubClassOf("ReadAdvance")) continue; - if (ReadDef == (*RAI)->getValueAsDef("ReadType")) - return *RAI; + if (AliasDef == (*RAI)->getValueAsDef("ReadType") + || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) { + if (ResDef) { + PrintFatalError((*RAI)->getLoc(), "Resources are defined for both " + "SchedRead and its alias on processor " + + ProcModel.ModelName); + } + ResDef = *RAI; + } } - if (ReadDef->getName() != "ReadDefault") { - throw TGError(ProcModel.ModelDef->getLoc(), + // TODO: If ProcModel has a base model (previous generation processor), + // then call FindReadAdvance recursively with that model here. + if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { + PrintFatalError(ProcModel.ModelDef->getLoc(), std::string("Processor does not define resources for ") - + ReadDef->getName()); + + SchedRead.TheDef->getName()); + } + return ResDef; +} + +// Expand an explicit list of processor resources into a full list of implied +// resource groups and super resources that cover them. +void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, + std::vector &Cycles, + const CodeGenProcModel &PM) { + // Default to 1 resource cycle. + Cycles.resize(PRVec.size(), 1); + for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { + Record *PRDef = PRVec[i]; + RecVec SubResources; + if (PRDef->isSubClassOf("ProcResGroup")) + SubResources = PRDef->getValueAsListOfDefs("Resources"); + else { + SubResources.push_back(PRDef); + PRDef = SchedModels.findProcResUnits(PRVec[i], PM); + for (Record *SubDef = PRDef; + SubDef->getValueInit("Super")->isComplete();) { + if (SubDef->isSubClassOf("ProcResGroup")) { + // Disallow this for simplicitly. + PrintFatalError(SubDef->getLoc(), "Processor resource group " + " cannot be a super resources."); + } + Record *SuperDef = + SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM); + PRVec.push_back(SuperDef); + Cycles.push_back(Cycles[i]); + SubDef = SuperDef; + } + } + for (RecIter PRI = PM.ProcResourceDefs.begin(), + PRE = PM.ProcResourceDefs.end(); + PRI != PRE; ++PRI) { + if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup")) + continue; + RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); + RecIter SubI = SubResources.begin(), SubE = SubResources.end(); + for( ; SubI != SubE; ++SubI) { + if (std::find(SuperResources.begin(), SuperResources.end(), *SubI) + == SuperResources.end()) { + break; + } + } + if (SubI == SubE) { + PRVec.push_back(*PRI); + Cycles.push_back(Cycles[i]); + } + } } - return NULL; } // Generate the SchedClass table for this processor and update global @@ -706,6 +836,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, std::vector &SCTab = SchedTables.ProcSchedClasses.back(); for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { + DEBUG(SCI->dump(&SchedModels)); + SCTab.resize(SCTab.size() + 1); MCSchedClassDesc &SCDesc = SCTab.back(); // SCDesc.Name is guarded by NDEBUG @@ -717,7 +849,22 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, SCDesc.ReadAdvanceIdx = 0; // A Variant SchedClass has no resources of its own. - if (!SCI->Transitions.empty()) { + bool HasVariants = false; + for (std::vector::const_iterator + TI = SCI->Transitions.begin(), TE = SCI->Transitions.end(); + TI != TE; ++TI) { + if (TI->ProcIndices[0] == 0) { + HasVariants = true; + break; + } + IdxIter PIPos = std::find(TI->ProcIndices.begin(), + TI->ProcIndices.end(), ProcModel.Index); + if (PIPos != TI->ProcIndices.end()) { + HasVariants = true; + break; + } + } + if (HasVariants) { SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; continue; } @@ -734,28 +881,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } IdxVec Writes = SCI->Writes; IdxVec Reads = SCI->Reads; - if (SCI->ItinClassDef) { - assert(SCI->InstRWs.empty() && "ItinClass should not have InstRWs"); - // Check this processor's itinerary class resources. - for (RecIter II = ProcModel.ItinRWDefs.begin(), - IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { - RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); - if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) - != Matched.end()) { - SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), - Writes, Reads); - break; - } - } - if (Writes.empty()) { - DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " does not have resources for itinerary class " - << SCI->ItinClassDef->getName() << '\n'); - } - } - else if (!SCI->InstRWs.empty()) { - assert(SCI->Writes.empty() && SCI->Reads.empty() && - "InstRW class should not have its own ReadWrites"); + if (!SCI->InstRWs.empty()) { + // This class has a default ReadWrite list which can be overriden by + // InstRW definitions. Record *RWDef = 0; for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); RWI != RWE; ++RWI) { @@ -766,28 +894,57 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } } if (RWDef) { + Writes.clear(); + Reads.clear(); SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); } } + if (Writes.empty()) { + // Check this processor's itinerary class resources. + for (RecIter II = ProcModel.ItinRWDefs.begin(), + IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { + RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) + != Matched.end()) { + SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + break; + } + } + if (Writes.empty()) { + DEBUG(dbgs() << ProcModel.ModelName + << " does not have resources for class " << SCI->Name << '\n'); + } + } // Sum resources across all operand writes. std::vector WriteProcResources; std::vector WriteLatencies; + std::vector WriterNames; std::vector ReadAdvanceEntries; for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) { IdxVec WriteSeq; - SchedModels.expandRWSequence(*WI, WriteSeq, /*IsRead=*/false); + SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false, + ProcModel); // For each operand, create a latency entry. MCWriteLatencyEntry WLEntry; WLEntry.Cycles = 0; - WLEntry.WriteResourceID = WriteSeq.back(); + unsigned WriteID = WriteSeq.back(); + WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); + // If this Write is not referenced by a ReadAdvance, don't distinguish it + // from other WriteLatency entries. + if (!SchedModels.hasReadOfWrite( + SchedModels.getSchedWrite(WriteID).TheDef)) { + WriteID = 0; + } + WLEntry.WriteResourceID = WriteID; for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end(); WSI != WSE; ++WSI) { - Record *WriteDef = SchedModels.getSchedWrite(*WSI).TheDef; - Record *WriteRes = FindWriteResources(WriteDef, ProcModel); + Record *WriteRes = + FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel); // Mark the parent class as invalid for unsupported write types. if (WriteRes->getValueAsBit("Unsupported")) { @@ -803,16 +960,29 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); std::vector Cycles = WriteRes->getValueAsListOfInts("ResourceCycles"); + + ExpandProcResources(PRVec, Cycles, ProcModel); + for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd; ++PRIdx) { MCWriteProcResEntry WPREntry; WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); - if (Cycles.size() > PRIdx) - WPREntry.Cycles = Cycles[PRIdx]; - else - WPREntry.Cycles = 1; - WriteProcResources.push_back(WPREntry); + WPREntry.Cycles = Cycles[PRIdx]; + // If this resource is already used in this sequence, add the current + // entry's cycles so that the same resource appears to be used + // serially, rather than multiple parallel uses. This is important for + // in-order machine where the resource consumption is a hazard. + unsigned WPRIdx = 0, WPREnd = WriteProcResources.size(); + for( ; WPRIdx != WPREnd; ++WPRIdx) { + if (WriteProcResources[WPRIdx].ProcResourceIdx + == WPREntry.ProcResourceIdx) { + WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles; + break; + } + } + if (WPRIdx == WPREnd) + WriteProcResources.push_back(WPREntry); } } WriteLatencies.push_back(WLEntry); @@ -821,8 +991,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, // Entries must be sorted first by UseIdx then by WriteResourceID. for (unsigned UseIdx = 0, EndIdx = Reads.size(); UseIdx != EndIdx; ++UseIdx) { - Record *ReadDef = SchedModels.getSchedRead(Reads[UseIdx]).TheDef; - Record *ReadAdvance = FindReadAdvance(ReadDef, ProcModel); + Record *ReadAdvance = + FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); if (!ReadAdvance) continue; @@ -880,12 +1050,22 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, std::search(SchedTables.WriteLatencies.begin(), SchedTables.WriteLatencies.end(), WriteLatencies.begin(), WriteLatencies.end()); - if (WLPos != SchedTables.WriteLatencies.end()) - SCDesc.WriteLatencyIdx = WLPos - SchedTables.WriteLatencies.begin(); + if (WLPos != SchedTables.WriteLatencies.end()) { + unsigned idx = WLPos - SchedTables.WriteLatencies.begin(); + SCDesc.WriteLatencyIdx = idx; + for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i) + if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) == + std::string::npos) { + SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i]; + } + } else { SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); - SchedTables.WriteLatencies.insert(WLPos, WriteLatencies.begin(), - WriteLatencies.end()); + SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), + WriteLatencies.begin(), + WriteLatencies.end()); + SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), + WriterNames.begin(), WriterNames.end()); } // ReadAdvanceEntries must remain in operand order. SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); @@ -934,8 +1114,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, << format("%2d", WLEntry.WriteResourceID) << "}"; if (WLIdx + 1 < WLEnd) OS << ','; - OS << " // #" << WLIdx << " " - << SchedModels.getSchedWrite(WLEntry.WriteResourceID).Name << '\n'; + OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; } OS << "}; // " << Target << "WriteLatencyTable\n"; @@ -963,7 +1142,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, continue; std::vector &SCTab = - SchedTables.ProcSchedClasses[1 + PI - SchedModels.procModelBegin()]; + SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup," << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; @@ -972,7 +1151,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, // The first class is always invalid. We no way to distinguish it except by // name and position. - assert(SchedModels.getSchedClass(0).Name == "NoItinerary" + assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" && "invalid class not first"); OS << " {DBGFIELD(\"InvalidSchedClass\") " << MCSchedClassDesc::InvalidNumMicroOps @@ -1008,17 +1187,22 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { if (PI->hasInstrSchedModel()) EmitProcessorResources(*PI, OS); else if(!PI->ProcResourceDefs.empty()) - throw TGError(PI->ModelDef->getLoc(), "SchedMachineModel defines " + PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines " "ProcResources without defining WriteRes SchedWriteRes"); // 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, "MicroOpBufferSize", ','); EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); + + OS << " " << (bool)(PI->ModelDef ? + PI->ModelDef->getValueAsBit("CompleteModel") : 0) + << ", // " << "CompleteModel\n"; + OS << " " << PI->Index << ", // Processor ID\n"; if (PI->hasInstrSchedModel()) OS << " " << PI->ModelName << "ProcResources" << ",\n" @@ -1028,7 +1212,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { - SchedModels.schedClassBegin()) << ",\n"; else OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; - if (SchedModels.hasItineraryClasses()) + if (SchedModels.hasItineraries()) OS << " " << PI->ItinsDef->getName() << ");\n"; else OS << " 0); // No Itinerary\n"; @@ -1085,7 +1269,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { << "#define DBGFIELD(x)\n" << "#endif\n"; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { std::vector > ProcItinLists; // Emit the stage data EmitStageAndOperandCycleData(OS, ProcItinLists); @@ -1109,6 +1293,80 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { OS << "#undef DBGFIELD"; } +void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, + raw_ostream &OS) { + OS << "unsigned " << ClassName + << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," + << " const TargetSchedModel *SchedModel) const {\n"; + + std::vector Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); + std::sort(Prologs.begin(), Prologs.end(), LessRecord()); + for (std::vector::const_iterator + PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) { + OS << (*PI)->getValueAsString("Code") << '\n'; + } + IdxVec VariantClasses; + for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), + SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { + if (SCI->Transitions.empty()) + continue; + VariantClasses.push_back(SCI->Index); + } + if (!VariantClasses.empty()) { + OS << " switch (SchedClass) {\n"; + for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end(); + VCI != VCE; ++VCI) { + const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI); + OS << " case " << *VCI << ": // " << SC.Name << '\n'; + IdxVec ProcIndices; + for (std::vector::const_iterator + TI = SC.Transitions.begin(), TE = SC.Transitions.end(); + TI != TE; ++TI) { + IdxVec PI; + std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(), + ProcIndices.begin(), ProcIndices.end(), + std::back_inserter(PI)); + ProcIndices.swap(PI); + } + for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); + PI != PE; ++PI) { + OS << " "; + if (*PI != 0) + OS << "if (SchedModel->getProcessorID() == " << *PI << ") "; + OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName + << '\n'; + for (std::vector::const_iterator + TI = SC.Transitions.begin(), TE = SC.Transitions.end(); + TI != TE; ++TI) { + if (*PI != 0 && !std::count(TI->ProcIndices.begin(), + TI->ProcIndices.end(), *PI)) { + continue; + } + OS << " if ("; + for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end(); + RI != RE; ++RI) { + if (RI != TI->PredTerm.begin()) + OS << "\n && "; + OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; + } + OS << ")\n" + << " return " << TI->ToClassIdx << "; // " + << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n'; + } + OS << " }\n"; + if (*PI == 0) + break; + } + if (SC.isInferred()) + OS << " return " << SC.Index << ";\n"; + OS << " break;\n"; + } + OS << " };\n"; + } + OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" + << "} // " << ClassName << "::resolveSchedClass\n"; +} + // // ParseFeaturesFunction - Produces a subtarget specific function for parsing // the subtarget features string. @@ -1133,7 +1391,8 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, return; } - OS << " uint64_t Bits = ReInitMCSubtargetInfo(CPU, FS);\n"; + OS << " InitMCProcessorInfo(CPU, FS);\n" + << " uint64_t Bits = getFeatureBits();\n"; for (unsigned i = 0; i < Features.size(); i++) { // Next record @@ -1205,7 +1464,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << '\n'; OS.indent(22); OS << Target << "Stages, " << Target << "OperandCycles, " @@ -1238,6 +1497,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { << " explicit " << ClassName << "(StringRef TT, StringRef CPU, " << "StringRef FS);\n" << "public:\n" + << " unsigned resolveSchedClass(unsigned SchedClass, const MachineInstr *DefMI," + << " const TargetSchedModel *SchedModel) const;\n" << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n" << "};\n"; @@ -1248,6 +1509,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; OS << "#undef GET_SUBTARGETINFO_CTOR\n"; + OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; OS << "namespace llvm {\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; @@ -1259,7 +1521,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "extern const llvm::MCReadAdvanceEntry " << Target << "ReadAdvanceTable[];\n"; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; OS << "extern const unsigned " << Target << "OperandCycles[];\n"; OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; @@ -1283,7 +1545,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; OS << '\n'; OS.indent(22); - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; @@ -1291,6 +1553,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "0, 0, 0, "; OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; + EmitSchedModelHelpers(ClassName, OS); + OS << "} // End llvm namespace \n"; OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";