3.6.2.4. 资源描述的调度
3.6.2.4.1. SchedReadWrite数据的收集
描述类似SandyBridge处理器指令执行细节的方法不同于Atom这样的处理器,上面的处理对这些处理器不适用。这些处理器使用WriteRes或SchedWriteRes描述SchedWrite对资源的使用,依靠ReadAdvance或SchedReadAdvance来描述对特定的SchedWrite以及特定SchedRead的预读情况。为了处理这些定义,首先需要找出与当前处理的调度类型相关的SchedWrite与SchedRead定义。
SubtargetEmitter::EmitSchedModel(续)
1266 OS << "\n// ===============================================================\n"
1267 << "// Data tables for the new per-operand machine model.\n";
1268
1269 SchedClassTables SchedTables;
1270 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1271 PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1272 GenSchedClassTables(*PI, SchedTables);
1273 }
1274 EmitSchedClassTables(SchedTables, OS);
1275
1276 // Emit the processor machine model
1277 EmitProcessorModels(OS);
1278 // Emit the processor lookup data
1279 EmitProcessorLookup(OS);
1280
1281 OS << "#undef DBGFIELD";
1282 }
1269行的SchedClassTables是SubtargetEmitter的内嵌类,在SchedClassDesc表中每个处理器的每个调度类型都有一个对应项。
38 struct SchedClassTables {
39 std::vector<std::vector<MCSchedClassDesc> > ProcSchedClasses;
40 std::vector<MCWriteProcResEntry> WriteProcResources;
41 std::vector<MCWriteLatencyEntry> WriteLatencies;
42 std::vector<std::string> WriterNames;
43 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
44
45 // Reserve an invalid entry at index 0
46 SchedClassTables() {
47 ProcSchedClasses.resize(1);
48 WriteProcResources.resize(1);
49 WriteLatencies.resize(1);
50 WriterNames.push_back("InvalidWrite");
51 ReadAdvanceEntries.resize(1);
52 }
53 };
其中MCSchedClassDesc的定义如下。它是MC对资源调度的描述方式。
101 struct MCSchedClassDesc {
102 static const unsigned short InvalidNumMicroOps = UINT16_MAX;
103 static const unsigned short VariantNumMicroOps = UINT16_MAX - 1;
104
105 #ifndef NDEBUG
106 const char* Name;
107 #endif
108 unsigned short NumMicroOps;
109 bool BeginGroup;
110 bool EndGroup;
111 unsigned WriteProcResIdx; // First index into WriteProcResTable.
112 unsigned NumWriteProcResEntries;
113 unsigned WriteLatencyIdx; // First index into WriteLatencyTable.
114 unsigned NumWriteLatencyEntries;
115 unsigned ReadAdvanceIdx; // First index into ReadAdvanceTable.
116 unsigned NumReadAdvanceEntries;
117
118 bool isValid() const {
119 return NumMicroOps != InvalidNumMicroOps;
120 }
121 bool isVariant() const {
122 return NumMicroOps == VariantNumMicroOps;
123 }
124 };
类型MCWriteProcResEntry用于描述指定调度类型在指定周期数里消耗指定处理器资源。
55 struct MCWriteProcResEntry {
56 unsigned ProcResourceIdx;
57 unsigned Cycles;
58
59 bool operator==(const MCWriteProcResEntry &Other) const {
60 return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles;
61 }
62 };
类型MCWriteLatencyEntry用于记录执行一个指定的SchedWrite定义所需的处理器周期。
69 struct MCWriteLatencyEntry {
70 int Cycles;
71 unsigned WriteResourceID;
72
73 bool operator==(const MCWriteLatencyEntry &Other) const {
74 return Cycles == Other.Cycles && WriteResourceID == Other.WriteResourceID;
75 }
76 };
MCReadAdvanceEntry由ReadAdvance定义创建,用于描述处理器的流水线旁路,这时写操作的结果可提前若干周期(在ReadAdvance定义中给出)传给后续的读操作。这时UseIdx是这个ReadAdvance定义的索引,WriteResourceID则是旁路支持的SchedWrite的索引,Cycles是缩短的周期(如果是负数则是延长)。
86 struct MCReadAdvanceEntry {
87 unsigned UseIdx;
88 unsigned WriteResourceID;
89 int Cycles;
90
91 bool operator==(const MCReadAdvanceEntry &Other) const {
92 return UseIdx == Other.UseIdx && WriteResourceID == Other.WriteResourceID
93 && Cycles == Other.Cycles;
94 }
95 };
1272行的GenSchedClassTables()方法就是为特定的处理器生成对应的MCSchedClassDesc实例。在816行CodeGenProcModel::hasInstrSchedModel()在容器WriteResDefs或ItinRWDefs不为空时返回true。这意味着对该处理器而言,存在援引它的WriteRes定义或ItinRW定义。注意815行,不管怎么样,SchedTables的ProcSchedClasses容器与CodeGenSchedModels的ProcModels容器最终将同一大小。
813 void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
814 SchedClassTables &SchedTables) {
815 SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1);
816 if (!ProcModel.hasInstrSchedModel())
817 return;
818
819 std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back();
820 for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(),
821 SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
822 DEBUG(SCI->dump(&SchedModels));
823
824 SCTab.resize(SCTab.size() + 1);
825 MCSchedClassDesc &SCDesc = SCTab.back();
826 // SCDesc.Name is guarded by NDEBUG
827 SCDesc.NumMicroOps = 0;
828 SCDesc.BeginGroup = false;
829 SCDesc.EndGroup = false;
830 SCDesc.WriteProcResIdx = 0;
831 SCDesc.WriteLatencyIdx = 0;
832 SCDesc.ReadAdvanceIdx = 0;
833
834 // A Variant SchedClass has no resources of its own.
835 bool HasVariants = false;
836 for (std::vector<CodeGenSchedTransition>::const_iterator
837 TI = SCI->Transitions.begin(), TE = SCI->Transitions.end();
838 TI != TE; ++TI) {
839 if (TI->ProcIndices[0] == 0) {
840