+ // Determine if the SchedClass is actually reachable on this processor. If
+ // not don't try to locate the processor resources, it will fail.
+ // If ProcIndices contains 0, this class applies to all processors.
+ assert(!SCI->ProcIndices.empty() && "expect at least one procidx");
+ if (SCI->ProcIndices[0] != 0) {
+ IdxIter PIPos = std::find(SCI->ProcIndices.begin(),
+ SCI->ProcIndices.end(), ProcModel.Index);
+ if (PIPos == SCI->ProcIndices.end())
+ continue;
+ }
+ 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()) {
+ // 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) {
+ Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");
+ if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {
+ RWDef = *RWI;
+ break;
+ }
+ }
+ if (RWDef) {
+ Writes.clear();
+ Reads.clear();
+ SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
+ Writes, Reads);
+ }
+ }
+ // Sum resources across all operand writes.
+ std::vector<MCWriteProcResEntry> WriteProcResources;
+ std::vector<MCWriteLatencyEntry> WriteLatencies;
+ std::vector<std::string> WriterNames;
+ std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
+ for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) {
+ IdxVec WriteSeq;
+ SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false,
+ ProcModel);
+
+ // For each operand, create a latency entry.
+ MCWriteLatencyEntry WLEntry;
+ WLEntry.Cycles = 0;
+ 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 *WriteRes =
+ FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel);
+
+ // Mark the parent class as invalid for unsupported write types.
+ if (WriteRes->getValueAsBit("Unsupported")) {
+ SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
+ break;
+ }
+ WLEntry.Cycles += WriteRes->getValueAsInt("Latency");
+ SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");
+ SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");
+ SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");
+
+ // Create an entry for each ProcResource listed in WriteRes.
+ RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
+ std::vector<int64_t> Cycles =
+ WriteRes->getValueAsListOfInts("ResourceCycles");
+ 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);
+ }
+ }
+ WriteLatencies.push_back(WLEntry);
+ }
+ // Create an entry for each operand Read in this SchedClass.
+ // Entries must be sorted first by UseIdx then by WriteResourceID.
+ for (unsigned UseIdx = 0, EndIdx = Reads.size();
+ UseIdx != EndIdx; ++UseIdx) {
+ Record *ReadAdvance =
+ FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
+ if (!ReadAdvance)
+ continue;
+
+ // Mark the parent class as invalid for unsupported write types.
+ if (ReadAdvance->getValueAsBit("Unsupported")) {
+ SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
+ break;
+ }
+ RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");
+ IdxVec WriteIDs;
+ if (ValidWrites.empty())
+ WriteIDs.push_back(0);
+ else {
+ for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end();
+ VWI != VWE; ++VWI) {
+ WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false));
+ }
+ }
+ std::sort(WriteIDs.begin(), WriteIDs.end());
+ for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) {
+ MCReadAdvanceEntry RAEntry;
+ RAEntry.UseIdx = UseIdx;
+ RAEntry.WriteResourceID = *WI;
+ RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
+ ReadAdvanceEntries.push_back(RAEntry);
+ }
+ }
+ if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
+ WriteProcResources.clear();
+ WriteLatencies.clear();
+ ReadAdvanceEntries.clear();
+ }
+ // Add the information for this SchedClass to the global tables using basic
+ // compression.
+ //
+ // WritePrecRes entries are sorted by ProcResIdx.
+ std::sort(WriteProcResources.begin(), WriteProcResources.end(),
+ LessWriteProcResources());
+
+ SCDesc.NumWriteProcResEntries = WriteProcResources.size();
+ std::vector<MCWriteProcResEntry>::iterator WPRPos =
+ std::search(SchedTables.WriteProcResources.begin(),
+ SchedTables.WriteProcResources.end(),
+ WriteProcResources.begin(), WriteProcResources.end());
+ if (WPRPos != SchedTables.WriteProcResources.end())
+ SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
+ else {
+ SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();
+ SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),
+ WriteProcResources.end());
+ }
+ // Latency entries must remain in operand order.
+ SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
+ std::vector<MCWriteLatencyEntry>::iterator WLPos =
+ std::search(SchedTables.WriteLatencies.begin(),
+ SchedTables.WriteLatencies.end(),
+ WriteLatencies.begin(), WriteLatencies.end());
+ 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(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();
+ std::vector<MCReadAdvanceEntry>::iterator RAPos =
+ std::search(SchedTables.ReadAdvanceEntries.begin(),
+ SchedTables.ReadAdvanceEntries.end(),
+ ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
+ if (RAPos != SchedTables.ReadAdvanceEntries.end())
+ SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
+ else {
+ SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
+ SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(),
+ ReadAdvanceEntries.end());
+ }
+ }
+}
+
+// Emit SchedClass tables for all processors and associated global tables.
+void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
+ raw_ostream &OS) {
+ // Emit global WriteProcResTable.
+ OS << "\n// {ProcResourceIdx, Cycles}\n"
+ << "extern const llvm::MCWriteProcResEntry "
+ << Target << "WriteProcResTable[] = {\n"
+ << " { 0, 0}, // Invalid\n";
+ for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
+ WPRIdx != WPREnd; ++WPRIdx) {
+ MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
+ OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
+ << format("%2d", WPREntry.Cycles) << "}";
+ if (WPRIdx + 1 < WPREnd)
+ OS << ',';
+ OS << " // #" << WPRIdx << '\n';
+ }
+ OS << "}; // " << Target << "WriteProcResTable\n";
+
+ // Emit global WriteLatencyTable.
+ OS << "\n// {Cycles, WriteResourceID}\n"
+ << "extern const llvm::MCWriteLatencyEntry "
+ << Target << "WriteLatencyTable[] = {\n"
+ << " { 0, 0}, // Invalid\n";
+ for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
+ WLIdx != WLEnd; ++WLIdx) {
+ MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
+ OS << " {" << format("%2d", WLEntry.Cycles) << ", "
+ << format("%2d", WLEntry.WriteResourceID) << "}";
+ if (WLIdx + 1 < WLEnd)
+ OS << ',';
+ OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
+ }
+ OS << "}; // " << Target << "WriteLatencyTable\n";
+
+ // Emit global ReadAdvanceTable.
+ OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
+ << "extern const llvm::MCReadAdvanceEntry "
+ << Target << "ReadAdvanceTable[] = {\n"
+ << " {0, 0, 0}, // Invalid\n";
+ for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
+ RAIdx != RAEnd; ++RAIdx) {
+ MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
+ OS << " {" << RAEntry.UseIdx << ", "
+ << format("%2d", RAEntry.WriteResourceID) << ", "
+ << format("%2d", RAEntry.Cycles) << "}";
+ if (RAIdx + 1 < RAEnd)
+ OS << ',';
+ OS << " // #" << RAIdx << '\n';
+ }
+ OS << "}; // " << Target << "ReadAdvanceTable\n";
+
+ // Emit a SchedClass table for each processor.
+ for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
+ PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+ if (!PI->hasInstrSchedModel())
+ continue;
+
+ std::vector<MCSchedClassDesc> &SCTab =
+ SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
+
+ OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup,"
+ << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
+ OS << "static const llvm::MCSchedClassDesc "
+ << PI->ModelName << "SchedClasses[] = {\n";
+
+ // The first class is always invalid. We no way to distinguish it except by
+ // name and position.
+ assert(SchedModels.getSchedClass(0).Name == "NoItinerary"
+ && "invalid class not first");
+ OS << " {DBGFIELD(\"InvalidSchedClass\") "
+ << MCSchedClassDesc::InvalidNumMicroOps
+ << ", 0, 0, 0, 0, 0, 0, 0, 0},\n";
+
+ for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
+ MCSchedClassDesc &MCDesc = SCTab[SCIdx];
+ const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
+ OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";
+ if (SchedClass.Name.size() < 18)
+ OS.indent(18 - SchedClass.Name.size());
+ OS << MCDesc.NumMicroOps
+ << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup
+ << ", " << format("%2d", MCDesc.WriteProcResIdx)
+ << ", " << MCDesc.NumWriteProcResEntries
+ << ", " << format("%2d", MCDesc.WriteLatencyIdx)
+ << ", " << MCDesc.NumWriteLatencyEntries
+ << ", " << format("%2d", MCDesc.ReadAdvanceIdx)
+ << ", " << MCDesc.NumReadAdvanceEntries << "}";
+ if (SCIdx + 1 < SCEnd)
+ OS << ',';
+ OS << " // #" << SCIdx << '\n';
+ }
+ OS << "}; // " << PI->ModelName << "SchedClasses\n";
+ }
+}
+
+void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
+ // For each processor model.
+ for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
+ PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+ // Emit processor resource table.
+ if (PI->hasInstrSchedModel())
+ EmitProcessorResources(*PI, OS);
+ else if(!PI->ProcResourceDefs.empty())
+ 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, "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
+ OS << " 0); // No Itinerary\n";