3.5. 指令信息的生成
选项-gen-instr-info使得TableGen根据TD文件的描述,生成目标机器的指令描述代码。比如,前面指令选择成功时生成的MachineSDNode的操作码就是在这一步生成的。
3.5.1. CodeGenSchedModels对象
一如既往,TableGen对这个选项的入口函数看起来很简单。参数RK就是保存了所有class与def定义的Record实例的容器。
608 void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) {
609 InstrInfoEmitter(RK).run(OS);
610 EmitMapTable(RK, OS);
611 }
609行的InstrInfoEmitter是用于生成相关代码的外覆类,它的构造函数定义如下:
38 InstrInfoEmitter(RecordKeeper &R):
39 Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {}
CDP是一个CodeGenDAGPatterns实例,因此CDP(R)所引发的一系列处理正是前面一节所看过的过程,即从指令定义生成指令的DAG,但不涉及指令选择代码的生成。
InstrInfoEmitter的成员SchedModels是CodeGenSchedModels类型的引用,这个类定义了以下的数据成员。它用作目标机器模型数据的顶层容器的封装类。所有从.td文件里相关定义解析出来的对象都将保存在相应的容器中。其他协作类将使用这些对象在容器里的索引进行工作。
219 class CodeGenSchedModels {
220 RecordKeeper &Records;
221 const CodeGenTarget &Target;
222
223 // Map dag expressions to Instruction lists.
224 SetTheory Sets;
225
226 // List of unique processor models.
227 std::vector<CodeGenProcModel> ProcModels;
228
229 // Map Processor's MachineModel or ProcItin to a CodeGenProcModel index.
230 typedef DenseMap<Record*, unsigned> ProcModelMapTy;
231 ProcModelMapTy ProcModelMap;
232
233 // Per-operand SchedReadWrite types.
234 std::vector<CodeGenSchedRW> SchedWrites;
235 std::vector<CodeGenSchedRW> SchedReads;
236
237 // List of unique SchedClasses.
238 std::vector<CodeGenSchedClass> SchedClasses;
239
240 // Any inferred SchedClass has an index greater than NumInstrSchedClassses.
241 unsigned NumInstrSchedClasses;
RecVec ProcResourceDefs; <- v7.0增加
RecVec ProcResGroups;
242
243 // Map each instruction to its unique SchedClass index considering the
244 // combination of it's itinerary class, SchedRW list, and InstRW records.
245 typedef DenseMap<Record*, unsigned> InstClassMapTy;
246 InstClassMapTy InstrClassMap;
CodeGenTarget::getSchedModels()调用CodeGenSchedModels构造函数创建CodeGenSchedModels对象,参数RK也就是EmitInstrInfo()的参数RK。
88 CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
89 const CodeGenTarget &TGT):
90 Records(RK), Target(TGT) {
91
92 Sets.addFieldExpander("InstRW", "Instrs");
93
94 // Allow Set evaluation to recognize the dags used in InstRW records:
95 // (instrs Op1, Op1...)
96 Sets.addOperator("instrs", llvm::make_unique<InstrsOp>());
97 Sets.addOperator("instregex", llvm::make_unique<InstRegexOp>(Target));
98
99 // Instantiate a CodeGenProcModel for each SchedMachineModel with the values
100 // that are explicitly referenced in tablegen records. Resources associated
101 // with each processor will be derived later. Populate ProcModelMap with the
102 // CodeGenProcModel instances.
103 collectProcModels();
104
105 // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly
106 // defined, and populate SchedReads and SchedWrites vectors. Implicit
107 // SchedReadWrites that represent sequences derived from expanded variant will
108 // be inferred later.
109 collectSchedRW();
110
111 // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly
112 // required by an instruction definition, and populate SchedClassIdxMap. Set
113 // NumItineraryClasses to the number of explicit itinerary classes referenced
114 // by instructions. Set NumInstrSchedClasses to the number of itinerary
115 // classes plus any classes implied by instructions that derive from class
116 // Sched and provide SchedRW list. This does not infer any new classes from
117 // SchedVariant.
118 collectSchedClasses();
119
120 // Find instruction itineraries for each processor. Sort and populate
121 // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires
122 // all itinerary classes to be discovered.
123 collectProcItins();
124
125 // Find ItinRW records for each processor and itinerary class.
126 // (For per-operand resources mapped to itinerary classes).
127 collectProcItinRW();
// Find UnsupportedFeatures records for each processor. <- v7.0增加
// (For per-operand resources mapped to itinerary classes).
collectProcUnsupportedFeatures();
128
129 // Infer new SchedClasses from SchedVariant.
130 inferSchedClasses();
131
132 // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and
133 // ProcResourceDefs.
134 collectProcResources();
// Collect optional processor description. <- v7.0增加
collectOptionalProcessorInfo();
135 }
首先,InstRW具有一个dag的成员Instrs,这是需要特别处理的。其次,还有两个特殊的dag操作符需要注意。一个是instrs,表示它的操作数应该解释为指令定义。另一个是instregex,表示它的操作数是用于匹配指令操作码名字的正则模式。
3.5.1.1. SchedMachineModel定义
CodeGenSchedModels构造函数首先处理SchedMachineModel定义。前面看到对Atom这样依赖Itinerary来描述指令执行的处理器,从SchedMachineModel派生的定义是这个描述最重要的部分(在v7.0里,Atom已经不用Itinerary来描述了)。而对SandyBridge这样通过资源占用来描述指令执行的处理器,SchedMachineModel派生定义则通常给出处理器的全局信息。处理器在自己的Processor定义中指出所需的SchedMachineModel。因此,通过Processor定义找出所有使用的SchedMachineModel是很自然的的方式。140行首先通过方法LessRecordFieldName()以字母序对所有的Processor定义排序。
138 void CodeGenSchedModels::collectProcModels() {
139 RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor");
140 std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName());
141
142 // Reserve space because we can. Reallocation would be ok.
143 ProcModels.reserve(ProcRecords.size()+1);
144
145 // Use idx=0 for NoModel/NoItineraries.
146 Record *NoModelDef = Records.getDef("NoSchedModel");
147 Record *NoItinsDef = Records.getDef("NoItineraries");
148 ProcModels.emplace_back(0, "NoSchedModel", NoModelDef, NoItinsDef);
149 ProcModelMap[NoModelDef] = 0;
150
151 // For each processor, find a unique machine model.
152 for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i)
153 addProcModel(ProcRecords[i]);
154 }
CodeGenSchedModels容器ProcModels的类型是std::vector<CodeGenProcModel>。其中的类型CodeGenProcModel用于描述处理器的调度模型,它近似于TD文件的SchedMachineModel定义,有如下的数据成员与构造函数。其中175行的Index是该CodeGenProcModel实例在ProcModels容器中的索引。
174 struct CodeGenProcModel {
175 unsigned Index;
176 std::string ModelName;
177 Record *ModelDef;
178 Record *ItinsDef;
179
180 // Derived members...
181
182 // Array of InstrItinData records indexed by a CodeGenSchedClass index.
183 // This list is empty if the Processor has no value for Itineraries.
184 // Initialized by collectProcItins().
185 RecVec ItinDefList;
186
187 // Map itinerary classes to per-operand resources.
188 // This list is empty if no ItinRW refers to this Processor.
189 RecVec ItinRWDefs;
// List of unsupported feature. <- v7.0增加
// This list is empty if the Processor has no UnsupportedFeatures.
RecVec UnsupportedFeaturesDefs;
190
191 // All read/write resources associated with this processor.
192 RecVec WriteResDefs;
193 RecVec ReadAdvanceDefs;
194
195 // Per-operand machine model resources associated with this processor.
196 RecVec ProcResourceDefs;
197 RecVec ProcResGroupDefs;
// List of Register Files. <- v7.0增加
std::vector<CodeGenRegisterFile> RegisterFiles;
// Optional Retire Control Unit definition.
Record *RetireControlUnit;
// List of PfmCounters.
RecVec PfmIssueCounterDefs;
Record *PfmCycleCounterDef = nullptr;
198
199 CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef,
200 Record *IDef) :
201 Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {}
collectProcModels() 149行的ProcModelMap是DenseMap<Record*, unsigned>的typedef,用于将CodeGenProcModel对象在ProcModels容器的序号与对应调度模型的Record对象关联起来。第一个调度模型是缺省模型,它的地位相当于空指针。
这些CodeGenSchedModels实例由CodeGenSchedModels::addProcModel()方法来获取。
158 void CodeGenSchedModels::addProcModel(Record *ProcDef) {
159 Record *ModelKey = getModelOrItinDef(ProcDef);
160 if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second)
161 return;
162
163 std::string Name = ModelKey->getName();
164 if (ModelKey->isSubClassOf("SchedMachineModel")) {
165 Record *ItinsDef = ModelKey->getValueAsDef("Itineraries");
166 ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef);
167 }
168 else {
169 // An itinerary is defined without a machine model. Infer a new model.
170 if (!ModelKey->getValueAsListOfDefs("IID").empty())
171 Name = Name + "Model";
172 ProcModels.emplace_back(ProcModels.size(), Name,
173 ProcDef->getValueAsDef("SchedModel"), ModelKey);
174 }
175 DEBUG(ProcModels.back().dump());
176 }
方法getModelOrItinDef()返回以下数据:Processor->SchedModel(类型SchedMachineModel)以及Processor->ProcItin(类型ProcessorItineraries)->IID(类型list<InstrItinData>)。
273 Record *getModelOrItinDef(Record *ProcDef) const {
274 Record *ModelDef = ProcDef->getValueAsDef("SchedModel");
275 Record *ItinsDef = ProcDef->getValueAsDef("ProcItin");
276 if (!ItinsDef->getValueAsListOfDefs("IID").empty()) {
277 assert(ModelDef->getValueAsBit("NoModel")
278 && "Itineraries must be defined within SchedMachineModel");
279 return ItinsDef;
280 }
281 return ModelDef;
282 }
从getModelOrItinDef()定义可以看出,如果同时出现,后者的优先程度高于前者。它们可生成这些CodeGenProcModel对象:(ModelDef: Processor->SchedModel, ItinsDef: Processor->SchedModel-> Itineraries),(ModelDef: Processor->ProcItin->IID, ItinsDef: Processor->ProcItin)。
245 CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef,
246 Record *IDef) :
247 Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef),
248 RetireControlUnit(nullptr) {}
其中Itineraries与Procltin的类型都是ProcessorItineraries的定义(ItinsDef)。
3.5.1.2. SchedReadWrite的处理
接下来由CodeGenSchedModels::collectSchedRW()方法为TD文件中的SchedReadWrite定义生成CodeGenSchedRW对象。TD文件中SchedReadWrite有复杂的派生体系与来源,需要一个一个处理。在v7.0里比较大的改动是用getInstructionsByEnumValue()替代了instructions()方法,前者将以操作码的大小序返回指令的CodeGenInstruction实例。
204 void CodeGenSchedModels::collectSchedRW() {
205 // Reserve idx=0 for invalid writes/reads.
206 SchedWrites.resize(1);
207 SchedReads.resize(1);
208
209 SmallPtrSet<Record*, 16> RWSet;
210
211 // Find all SchedReadWrites referenced by instruction defs.
212 RecVec SWDefs, SRDefs;
213 for (const CodeGenInstruction *Inst : Target.instructions()) { <- v7.0删除
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { <- v7.0增加
214 Record *SchedDef = Inst->TheDef;
215 if (SchedDef->isValueUnset("SchedRW"))
216 continue;
217 RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW");
218 for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) {
219 if ((*RWI)->isSubClassOf("SchedWrite"))
220 scanSchedRW(*RWI, SWDefs, RWSet);
221 else {
222 assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
223 scanSchedRW(*RWI, SRDefs, RWSet);
224 }
225 }
226 }
227 // Find all ReadWrites referenced by InstRW.
228 RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
229 for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) {
230 // For all OperandReadWrites.
231 RecVec RWDefs = (*OI)->getValueAsListOfDefs("OperandReadWrites");
232 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
233 RWI != RWE; ++RWI) {
234 if ((*RWI)->isSubClassOf("SchedWrite"))
235 scanSchedRW(*RWI, SWDefs, RWSet);
236 else {
237 assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
238 scanSchedRW(*RWI, SRDefs, RWSet);
239 }
240 }
241 }
242 // Find all ReadWrites referenced by ItinRW.
243 RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
244 for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) {
245 // For all OperandReadWrites.
246 RecVec RWDefs = (*II)->getValueAsListOfDefs("OperandReadWrites");
247 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
248 RWI != RWE; ++RWI) {
249 if ((*RWI)->isSubClassOf("SchedWrite"))
250 scanSchedRW(*RWI, SWDefs, RWSet);
251 else {
252 assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
253 scanSchedRW(*RWI, SRDefs, RWSet);
254 }
255 }
256 }
257 // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted
258 // for the loop below that initializes Alias vectors.
259 RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias");
260 std::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord());
261 for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) {
262 Record *MatchDef = (*AI)->getValueAsDef("MatchRW");
263 Record *AliasDef = (*AI)->getValueAsDef("AliasRW");
264 if (MatchDef->isSubClassOf("SchedWrite")) {
265 if (!AliasDef->isSubClassOf("SchedWrite"))
266 PrintFatalError((*AI)->getLoc(), "SchedWrite Alias must be SchedWrite");
267 scanSchedRW(AliasDef, SWDefs, RWSet);
268 }
269 else {
270 assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
271 if (!AliasDef->isSubClassOf("SchedRead"))
272 PrintFatalError((*AI)->getLoc(), "SchedRead Alias must be SchedRead");
273 scanSchedRW(AliasDef, SRDefs, RWSet);
274 }
275 }
276 // Sort and add the SchedReadWrites directly referenced by instructions or
277 // itinerary resources. Index reads and writes in separate domains.
278 std::sort(SWDefs.begin(), SWDefs.end(), LessRecord());
279 for (RecIter SWI = SWDefs.begin(), SWE = SWDefs.end(); SWI != SWE; ++SWI) {
280 assert(!getSchedRWIdx(*SWI, /*IsRead=*/false) && "duplicate SchedWrite");
281 SchedWrites.emplace_back(SchedWrites.size(), *SWI);
282 }
283 std::sort(SRDefs.begin(), SRDefs.end(), LessRecord());
284 for (RecIter SRI = SRDefs.begin(), SRE = SRDefs.end(); SRI != SRE; ++SRI) {
285 assert(!getSchedRWIdx(*SRI, /*IsRead-*/true) && "duplicate SchedWrite");
286 SchedReads.emplace_back(SchedReads.size(), *SRI);
287 }
288 // Initialize WriteSequence vectors.
289 for (std::vector<CodeGenSchedRW>::iterator WI = SchedWrites.begin(),
290 WE = SchedWrites.end(); WI != WE; ++WI) {
291 if (!WI->IsSequence)
292 continue;
293 findRWs(WI->TheDef->getValueAsListOfDefs("Writes"), WI->Sequence,
294 /*IsRead=*/false);
295 }
296 // Initialize Aliases vectors.
297 for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) {
298 Record *AliasDef = (*AI)->getValueAsDef("AliasRW");
299 getSchedRW(AliasDef).IsAlias = true;
300 Record *MatchDef = (*AI)->getValueAsDef("MatchRW");
301 CodeGenSchedRW &RW = getSchedRW(MatchDef);
302 if (RW.IsAlias)
303 PrintFatalError((*AI)->getLoc(), "Cannot Alias an Alias");
304 RW.Aliases.push_back(*AI);
305 }
306 DEBUG(
307 for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) {
308 dbgs() << WIdx << ": ";
309 SchedWrites[WIdx].dump();
310 dbgs() << '\n';
311 }
312 for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; ++RIdx) {
313 dbgs() << RIdx << ": ";
314 SchedReads[RIdx].dump();
315 dbgs() << '\n';
316 }
317 RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite");
318 for (RecIter RI = RWDefs.begin(), RE = RWDefs.end();
319 RI != RE; ++RI) {
320 if (!getSchedRWIdx(*RI, (*RI)->isSubClassOf("SchedRead"))) {
321 const std::string &Name = (*RI)->getName();
322 if (Name != "NoWrite" && Name != "ReadDefault")
323 dbgs() << "Unused SchedReadWrite " << (*RI)->getName() << '\n';
324 }
325 });
326 }
SchedReadWrite各派生类型所对应的对象都是CodeGenSchedRW实例,它是这样的一个定义:
46 struct CodeGenSchedRW {
47 unsigned Index;
48 std::string Name;
49 Record *TheDef;
50 bool IsRead;
51 bool IsAlias;
52 bool HasVariants;
53 bool IsVariadic;
54 bool IsSequence;
55 IdxVec Sequence;
56 RecVec Aliases;
57
58 CodeGenSchedRW()
59 : Index(0), TheDef(nullptr), IsRead(false), IsAlias(false),
60 HasVariants(false), IsVariadic(false), IsSequence(false) {}
61 CodeGenSchedRW(unsigned Idx, Record *Def)
62 : Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) {
63 Name = Def->getName();
64 IsRead = Def->isSubClassOf("SchedRead");
65 HasVariants = Def->isSubClassOf("SchedVariant");
66 if (HasVariants)
67 IsVariadic = Def->getValueAsBit("Variadic");
68
69 // Read records don't currently have sequences, but it can be easily
70 // added. Note that implicit Reads (from ReadVariant) may have a Sequence
71 // (but no record).
72 IsSequence = Def->isSubClassOf("WriteSequence");
73 }
74
75 CodeGenSchedRW(unsigned Idx, bool Read, const IdxVec &Seq,
76 const std::string &Name)
77 : Index(Idx), Name(Name), TheDef(nullptr), IsRead(Read), IsAlias(false),
78 HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) {
79 assert(Sequence.size() > 1 && "implied sequence needs >1 RWs");
80 }
81
82 bool isValid() const {
83 assert((!HasVariants || TheDef) && "Variant write needs record def");
84 assert((!IsVariadic || HasVariants) && "Variadic write needs variants");
85 assert((!IsSequence || !HasVariants) && "Sequence can't have variant");
86 assert((!IsSequence || !Sequence.empty()) && "Sequence should be nonempty");
87 assert((!IsAlias || Aliases.empty()) && "Alias cannot have aliases");
88 return TheDef || !Sequence.empty();
89 }
90
91 #ifndef NDEBUG
92 void dump() const;
93 #endif
94 };
其中类型IdxVec是std::vector<unsigned>的typdef,类型RecVec是std::vector<Record*>的typedef。
CodeGenSchedModels的容器SchedWrites与SchedReads用于保存CodeGenSchedRW对象,47行的成员Index是CodeGenSchedRW对象在这些容器里的索引。
collectSchedRW()首先调用scanSchedRW()方法将SchedRead或SchedWrites定义记录在临时容器RWSet里。SchedRead或SchedWrites用在以下各处:Instruction->SchedRW,SchedAlias->AliasRW,InstRW->OperandReadWrites,以及ItinRW->OperandReadWrites。
179 static void scanSchedRW(Record *RWDef, RecVec &RWDefs,
180 SmallPtrSet<Record*, 16> &RWSet) {
181 if (!RWSet.insert(RWDef).second)
182 return;
183 RWDefs.push_back(RWDef);
184 // Reads don't current have sequence records, but it can be added later.
185 if (RWDef->isSubClassOf("WriteSequence")) {
186 RecVec Seq = RWDef->getValueAsListOfDefs("Writes");
187 for (RecIter I = Seq.begin(), E = Seq.end(); I != E; ++I)
188 scanSchedRW(*I, RWDefs, RWSet);
189 }
190 else if (RWDef->isSubClassOf("SchedVariant")) {
191 // Visit each variant (guarded by a different predicate).
192 RecVec Vars = RWDef->getValueAsListOfDefs("Variants");
193 for (RecIter VI = Vars.begin(), VE = Vars.end(); VI != VE; ++VI) {
194 // Visit each RW in the sequence selected by the current variant.
195 RecVec Selected = (*VI)->getValueAsListOfDefs("Selected");
196 for (RecIter I = Selected.begin(), E = Selected.end(); I != E; ++I)
197 scanSchedRW(*I, RWDefs, RWSet);
198 }
199 }
200 }
因为WriteSequence与SchedVariant还包含list<SchedWrite>类型的成员(即Writes与Variants),这些SchedWrite定义也需要包括进来。临时容器SWDefs保存的是这些SchedWrite定义的Record对象。类似的,SchedRead定义的Record对象则记录在SRDefs中。
在获得所有使用的SchedRead与SchedWrite定义后,在collectSchedRW()的278与283行将这些Record对象按名字排序。然后在279与284行循环对这些的Record对象构建对应的CodeGenSchedRW对象,并保存在SchedWrites与SchedReads容器中。
只有从WriteSequence定义产生的CodeGenSchedRW对象的IsSequence是true,它援引一组重复指定次数的SchedWrite定义。我们需要知道这些SchedWrite定义对应的CodeGenSchedRW对象。这里通过CodeGenSchedModels::findRWs()方法将这些CodeGenSchedRW对象在容器中的索引记录在这些WriteSequence的CodeGenSchedRW对象的Sequence容器里。
392 void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs,
393 bool IsRead) const {
394 for (RecIter RI = RWDefs.begin(), RE = RWDefs.end(); RI != RE; ++RI) {
395 unsigned Idx = getSchedRWIdx(*RI, IsRead);
396 assert(Idx && "failed to collect SchedReadWrite");
397 RWs.push_back(Idx);
398 }
399 }
getSchedRWIdx()的参数After缺省为0,指定SchedReads或SchedWrites容器开始查找的位置。它返回参数Def对应的CodeGenSchedRW对象在SchedReads或SchedWrites容器中的索引。
340 unsigned CodeGenSchedModels::getSchedRWIdx(Record *Def, bool IsRead,
341 unsigned After) const {
342 const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
343 assert(After < RWVec.size() && "start position out of bounds");
344 for (std::vector<CodeGenSchedRW>::const_iterator I = RWVec.begin() + After,
345 E = RWVec.end(); I != E; ++I) {
346 if (I->TheDef == Def)
347 return I - RWVec.begin();
348 }
349 return 0;
350 }
V7.0版本的CodeGenSchedModels::getSchedRWIdx()得到了比较大的简化,而且不再从指定位置开始搜索:
458 unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def,
459 bool IsRead) const {
460 const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
461 const auto I = find_if(
462 RWVec, [Def](const CodeGenSchedRW &RW) { return RW.TheDef == Def; });
463 return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I);
464 }
SchedAlias使用AliasRW记录MatchRW的别名(参见SchedAlias的定义),因此从MatchRW构建的CodeGenSchedRW对象的Aliases容器将记录下AliasRW的CodeGenSchedRW对象(297行循环)。