X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FSubtargetEmitter.cpp;h=3b7d006fd1dcae7f71990de06ebce6734fb05737;hb=22bd64173981bf1251c4b3bfc684207340534ba3;hp=073d3ab0af7d410b13392b4b1acd714af4727b01;hpb=e1b53287179b4b9b5c3c549586f688d3fa2ae8ef;p=oota-llvm.git diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 073d3ab0af7..3b7d006fd1d 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,16 @@ 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 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); @@ -617,10 +623,10 @@ 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]; @@ -639,8 +645,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 << PRDef->getValueAsInt("NumUnits") << ", " << SuperIdx << ", " + << PRDef->getValueAsBit("Buffered") << "}" << Sep << " // #" << i+1; if (SuperDef) OS << ", Super=" << SuperDef->getName(); OS << "\n"; @@ -651,48 +657,110 @@ 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 NULL; + return ResDef; } // Generate the SchedClass table for this processor and update global @@ -706,9 +774,11 @@ 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 = SCI->Name.c_str(); + // SCDesc.Name is guarded by NDEBUG SCDesc.NumMicroOps = 0; SCDesc.BeginGroup = false; SCDesc.EndGroup = false; @@ -754,8 +824,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } } else if (!SCI->InstRWs.empty()) { - assert(SCI->Writes.empty() && SCI->Reads.empty() && - "InstRW class should not have its own ReadWrites"); + // This class may have 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,6 +836,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } } if (RWDef) { + Writes.clear(); + Reads.clear(); SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); } @@ -773,21 +845,30 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, // 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")) { @@ -821,8 +902,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 +961,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 +1025,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 +1053,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"; @@ -1008,7 +1098,7 @@ 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 @@ -1019,6 +1109,15 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); + OS << " " << PI->Index << ", // Processor ID\n"; + if (PI->hasInstrSchedModel()) + OS << " " << PI->ModelName << "ProcResources" << ",\n" + << " " << PI->ModelName << "SchedClasses" << ",\n" + << " " << PI->ProcResourceDefs.size()+1 << ",\n" + << " " << (SchedModels.schedClassEnd() + - SchedModels.schedClassBegin()) << ",\n"; + else + OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; if (SchedModels.hasItineraryClasses()) OS << " " << PI->ItinsDef->getName() << ");\n"; else @@ -1100,6 +1199,85 @@ 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 - SchedModels.schedClassBegin()); + } + 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) { + OS << " if ("; + if (*PI != 0 && !std::count(TI->ProcIndices.begin(), + TI->ProcIndices.end(), *PI)) { + continue; + } + 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; + } + unsigned SCIdx = 0; + if (SC.ItinClassDef) + SCIdx = SchedModels.getSchedClassIdxForItin(SC.ItinClassDef); + else + SCIdx = SchedModels.findSchedClassIdx(SC.Writes, SC.Reads); + if (SCIdx != *VCI) + OS << " return " << SCIdx << ";\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. @@ -1124,7 +1302,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 @@ -1192,13 +1371,17 @@ void SubtargetEmitter::run(raw_ostream &OS) { else OS << "0, "; OS << '\n'; OS.indent(22); + OS << Target << "ProcSchedKV, " + << Target << "WriteProcResTable, " + << Target << "WriteLatencyTable, " + << Target << "ReadAdvanceTable, "; if (SchedModels.hasItineraryClasses()) { - OS << Target << "ProcSchedKV, " - << Target << "Stages, " + OS << '\n'; OS.indent(22); + OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; } else - OS << "0, 0, 0, 0, "; + OS << "0, 0, 0, "; OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; OS << "} // End llvm namespace \n"; @@ -1225,6 +1408,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"; @@ -1235,6 +1420,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"; @@ -1264,15 +1450,22 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << Target << "SubTypeKV, "; else OS << "0, "; + OS << '\n'; OS.indent(22); + OS << Target << "ProcSchedKV, " + << Target << "WriteProcResTable, " + << Target << "WriteLatencyTable, " + << Target << "ReadAdvanceTable, "; + OS << '\n'; OS.indent(22); if (SchedModels.hasItineraryClasses()) { - OS << Target << "ProcSchedKV, " - << Target << "Stages, " + OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; } else - OS << "0, 0, 0, 0, "; + 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";