3.6.2.5. 输出代码与数据结构
3.6.2.5.1. 资源使用与时延
SchedTables保存在WriteProcResources,WriteLatencies,ReadAdvanceEntries以及WriterNames容器里的数据是所有处理器公用的,因此下面的方法首先输出包含这些公用数据的数组。
1070 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
1071 raw_ostream &OS) {
1072 // Emit global WriteProcResTable.
1073 OS << "\n// {ProcResourceIdx, Cycles}\n"
1074 << "extern const llvm::MCWriteProcResEntry "
1075 << Target << "WriteProcResTable[] = {\n"
1076 << " { 0, 0}, // Invalid\n";
1077 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
1078 WPRIdx != WPREnd; ++WPRIdx) {
1079 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
1080 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
1081 << format("%2d", WPREntry.Cycles) << "}";
1082 if (WPRIdx + 1 < WPREnd)
1083 OS << ',';
1084 OS << " // #" << WPRIdx << '\n';
1085 }
1086 OS << "}; // " << Target << "WriteProcResTable\n";
1087
1088 // Emit global WriteLatencyTable.
1089 OS << "\n// {Cycles, WriteResourceID}\n"
1090 << "extern const llvm::MCWriteLatencyEntry "
1091 << Target << "WriteLatencyTable[] = {\n"
1092 << " { 0, 0}, // Invalid\n";
1093 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
1094 WLIdx != WLEnd; ++WLIdx) {
1095 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
1096 OS << " {" << format("%2d", WLEntry.Cycles) << ", "
1097 << format("%2d", WLEntry.WriteResourceID) << "}";
1098 if (WLIdx + 1 < WLEnd)
1099 OS << ',';
1100 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
1101 }
1102 OS << "}; // " << Target << "WriteLatencyTable\n";
1103
1104 // Emit global ReadAdvanceTable.
1105 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
1106 << "extern const llvm::MCReadAdvanceEntry "
1107 << Target << "ReadAdvanceTable[] = {\n"
1108 << " {0, 0, 0}, // Invalid\n";
1109 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
1110 RAIdx != RAEnd; ++RAIdx) {
1111 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
1112 OS << " {" << RAEntry.UseIdx << ", "
1113 << format("%2d", RAEntry.WriteResourceID) << ", "
1114 << format("%2d", RAEntry.Cycles) << "}";
1115 if (RAIdx + 1 < RAEnd)
1116 OS << ',';
1117 OS << " // #" << RAIdx << '\n';
1118 }
1119 OS << "}; // " << Target << "ReadAdvanceTable\n";
1120
1121 // Emit a SchedClass table for each processor.
1122 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1123 PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1124 if (!PI->hasInstrSchedModel())
1125 continue;
1126
1127 std::vector<MCSchedClassDesc> &SCTab =
1128 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
1129
1130 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup,"
1131 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
1132 OS << "static const llvm::MCSchedClassDesc "
1133 << PI->ModelName << "SchedClasses[] = {\n";
1134
1135 // The first class is always invalid. We no way to distinguish it except by
1136 // name and position.
1137 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
1138 && "invalid class not first");
1139 OS << " {DBGFIELD(\"InvalidSchedClass\") "
1140 << MCSchedClassDesc::InvalidNumMicroOps
1141 << ", 0, 0, 0, 0, 0, 0, 0, 0},\n";
1142
1143 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
1144 MCSchedClassDesc &MCDesc = SCTab[SCIdx];
1145 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
1146 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";
1147 if (SchedClass.Name.size() < 18)
1148 OS.indent(18 - SchedClass.Name.size());
1149 OS << MCDesc.NumMicroOps
1150 << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup
1151 << ", " << format("%2d", MCDesc.WriteProcResIdx)
1152 << ", " << MCDesc.NumWriteProcResEntries
1153 << ", " << format("%2d", MCDesc.WriteLatencyIdx)
1154 << ", " << MCDesc.NumWriteLatencyEntries
1155 << ", " << format("%2d", MCDesc.ReadAdvanceIdx)