blob: d9095d7480674aef63330c0649664d2cdf19ca2e [file] [log] [blame]
Andrew Trick2661b412012-07-07 04:00:00 +00001//===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines structures to encapsulate the machine model as decribed in
11// the target description.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "subtarget-emitter"
16
17#include "CodeGenSchedule.h"
18#include "CodeGenTarget.h"
Andrew Trick48605c32012-09-15 00:19:57 +000019#include "llvm/TableGen/Error.h"
Andrew Trick2661b412012-07-07 04:00:00 +000020#include "llvm/Support/Debug.h"
21
22using namespace llvm;
23
Andrew Trick48605c32012-09-15 00:19:57 +000024#ifndef NDEBUG
25static void dumpIdxVec(const IdxVec &V) {
26 for (unsigned i = 0, e = V.size(); i < e; ++i) {
27 dbgs() << V[i] << ", ";
28 }
29}
30#endif
31
32/// CodeGenModels ctor interprets machine model records and populates maps.
Andrew Trick2661b412012-07-07 04:00:00 +000033CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
34 const CodeGenTarget &TGT):
Andrew Trick48605c32012-09-15 00:19:57 +000035 Records(RK), Target(TGT), NumItineraryClasses(0) {
Andrew Trick2661b412012-07-07 04:00:00 +000036
Andrew Trick48605c32012-09-15 00:19:57 +000037 // Instantiate a CodeGenProcModel for each SchedMachineModel with the values
38 // that are explicitly referenced in tablegen records. Resources associated
39 // with each processor will be derived later. Populate ProcModelMap with the
40 // CodeGenProcModel instances.
41 collectProcModels();
Andrew Trick2661b412012-07-07 04:00:00 +000042
Andrew Trick48605c32012-09-15 00:19:57 +000043 // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly
44 // defined, and populate SchedReads and SchedWrites vectors. Implicit
45 // SchedReadWrites that represent sequences derived from expanded variant will
46 // be inferred later.
47 collectSchedRW();
48
49 // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly
50 // required by an instruction definition, and populate SchedClassIdxMap. Set
51 // NumItineraryClasses to the number of explicit itinerary classes referenced
52 // by instructions. Set NumInstrSchedClasses to the number of itinerary
53 // classes plus any classes implied by instructions that derive from class
54 // Sched and provide SchedRW list. This does not infer any new classes from
55 // SchedVariant.
56 collectSchedClasses();
57
58 // Find instruction itineraries for each processor. Sort and populate
59 // CodeGenProcMode::ItinDefList. (Cycle-to-cycle itineraries). This requires
60 // all itinerary classes to be discovered.
61 collectProcItins();
62
63 // Find ItinRW records for each processor and itinerary class.
64 // (For per-operand resources mapped to itinerary classes).
65 collectProcItinRW();
Andrew Trick2661b412012-07-07 04:00:00 +000066}
67
Andrew Trick48605c32012-09-15 00:19:57 +000068/// Gather all processor models.
69void CodeGenSchedModels::collectProcModels() {
70 RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor");
71 std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName());
Andrew Trick2661b412012-07-07 04:00:00 +000072
Andrew Trick48605c32012-09-15 00:19:57 +000073 // Reserve space because we can. Reallocation would be ok.
74 ProcModels.reserve(ProcRecords.size()+1);
75
76 // Use idx=0 for NoModel/NoItineraries.
77 Record *NoModelDef = Records.getDef("NoSchedModel");
78 Record *NoItinsDef = Records.getDef("NoItineraries");
79 ProcModels.push_back(CodeGenProcModel(0, "NoSchedModel",
80 NoModelDef, NoItinsDef));
81 ProcModelMap[NoModelDef] = 0;
82
83 // For each processor, find a unique machine model.
84 for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i)
85 addProcModel(ProcRecords[i]);
86}
87
88/// Get a unique processor model based on the defined MachineModel and
89/// ProcessorItineraries.
90void CodeGenSchedModels::addProcModel(Record *ProcDef) {
91 Record *ModelKey = getModelOrItinDef(ProcDef);
92 if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second)
93 return;
94
95 std::string Name = ModelKey->getName();
96 if (ModelKey->isSubClassOf("SchedMachineModel")) {
97 Record *ItinsDef = ModelKey->getValueAsDef("Itineraries");
98 ProcModels.push_back(
99 CodeGenProcModel(ProcModels.size(), Name, ModelKey, ItinsDef));
100 }
101 else {
102 // An itinerary is defined without a machine model. Infer a new model.
103 if (!ModelKey->getValueAsListOfDefs("IID").empty())
104 Name = Name + "Model";
105 ProcModels.push_back(
106 CodeGenProcModel(ProcModels.size(), Name,
107 ProcDef->getValueAsDef("SchedModel"), ModelKey));
108 }
109 DEBUG(ProcModels.back().dump());
110}
111
112// Recursively find all reachable SchedReadWrite records.
113static void scanSchedRW(Record *RWDef, RecVec &RWDefs,
114 SmallPtrSet<Record*, 16> &RWSet) {
115 if (!RWSet.insert(RWDef))
116 return;
117 RWDefs.push_back(RWDef);
118 // Reads don't current have sequence records, but it can be added later.
119 if (RWDef->isSubClassOf("WriteSequence")) {
120 RecVec Seq = RWDef->getValueAsListOfDefs("Writes");
121 for (RecIter I = Seq.begin(), E = Seq.end(); I != E; ++I)
122 scanSchedRW(*I, RWDefs, RWSet);
123 }
124 else if (RWDef->isSubClassOf("SchedVariant")) {
125 // Visit each variant (guarded by a different predicate).
126 RecVec Vars = RWDef->getValueAsListOfDefs("Variants");
127 for (RecIter VI = Vars.begin(), VE = Vars.end(); VI != VE; ++VI) {
128 // Visit each RW in the sequence selected by the current variant.
129 RecVec Selected = (*VI)->getValueAsListOfDefs("Selected");
130 for (RecIter I = Selected.begin(), E = Selected.end(); I != E; ++I)
131 scanSchedRW(*I, RWDefs, RWSet);
132 }
133 }
134}
135
136// Collect and sort all SchedReadWrites reachable via tablegen records.
137// More may be inferred later when inferring new SchedClasses from variants.
138void CodeGenSchedModels::collectSchedRW() {
139 // Reserve idx=0 for invalid writes/reads.
140 SchedWrites.resize(1);
141 SchedReads.resize(1);
142
143 SmallPtrSet<Record*, 16> RWSet;
144
145 // Find all SchedReadWrites referenced by instruction defs.
146 RecVec SWDefs, SRDefs;
147 for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
148 E = Target.inst_end(); I != E; ++I) {
149 Record *SchedDef = (*I)->TheDef;
150 if (!SchedDef->isSubClassOf("Sched"))
151 continue;
152 RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW");
153 for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) {
154 if ((*RWI)->isSubClassOf("SchedWrite"))
155 scanSchedRW(*RWI, SWDefs, RWSet);
156 else {
157 assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
158 scanSchedRW(*RWI, SRDefs, RWSet);
159 }
160 }
161 }
162 // Find all ReadWrites referenced by InstRW.
163 RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
164 for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) {
165 // For all OperandReadWrites.
166 RecVec RWDefs = (*OI)->getValueAsListOfDefs("OperandReadWrites");
167 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
168 RWI != RWE; ++RWI) {
169 if ((*RWI)->isSubClassOf("SchedWrite"))
170 scanSchedRW(*RWI, SWDefs, RWSet);
171 else {
172 assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
173 scanSchedRW(*RWI, SRDefs, RWSet);
174 }
175 }
176 }
177 // Find all ReadWrites referenced by ItinRW.
178 RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
179 for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) {
180 // For all OperandReadWrites.
181 RecVec RWDefs = (*II)->getValueAsListOfDefs("OperandReadWrites");
182 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
183 RWI != RWE; ++RWI) {
184 if ((*RWI)->isSubClassOf("SchedWrite"))
185 scanSchedRW(*RWI, SWDefs, RWSet);
186 else {
187 assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
188 scanSchedRW(*RWI, SRDefs, RWSet);
189 }
190 }
191 }
192 // Sort and add the SchedReadWrites directly referenced by instructions or
193 // itinerary resources. Index reads and writes in separate domains.
194 std::sort(SWDefs.begin(), SWDefs.end(), LessRecord());
195 for (RecIter SWI = SWDefs.begin(), SWE = SWDefs.end(); SWI != SWE; ++SWI) {
196 assert(!getSchedRWIdx(*SWI, /*IsRead=*/false) && "duplicate SchedWrite");
197 SchedWrites.push_back(CodeGenSchedRW(*SWI));
198 }
199 std::sort(SRDefs.begin(), SRDefs.end(), LessRecord());
200 for (RecIter SRI = SRDefs.begin(), SRE = SRDefs.end(); SRI != SRE; ++SRI) {
201 assert(!getSchedRWIdx(*SRI, /*IsRead-*/true) && "duplicate SchedWrite");
202 SchedReads.push_back(CodeGenSchedRW(*SRI));
203 }
204 // Initialize WriteSequence vectors.
205 for (std::vector<CodeGenSchedRW>::iterator WI = SchedWrites.begin(),
206 WE = SchedWrites.end(); WI != WE; ++WI) {
207 if (!WI->IsSequence)
208 continue;
209 findRWs(WI->TheDef->getValueAsListOfDefs("Writes"), WI->Sequence,
210 /*IsRead=*/false);
211 }
212 DEBUG(
213 for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) {
214 dbgs() << WIdx << ": ";
215 SchedWrites[WIdx].dump();
216 dbgs() << '\n';
217 }
218 for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; ++RIdx) {
219 dbgs() << RIdx << ": ";
220 SchedReads[RIdx].dump();
221 dbgs() << '\n';
222 }
223 RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite");
224 for (RecIter RI = RWDefs.begin(), RE = RWDefs.end();
225 RI != RE; ++RI) {
226 if (!getSchedRWIdx(*RI, (*RI)->isSubClassOf("SchedRead"))) {
227 const std::string &Name = (*RI)->getName();
228 if (Name != "NoWrite" && Name != "ReadDefault")
229 dbgs() << "Unused SchedReadWrite " << (*RI)->getName() << '\n';
230 }
231 });
232}
233
234/// Compute a SchedWrite name from a sequence of writes.
235std::string CodeGenSchedModels::genRWName(const IdxVec& Seq, bool IsRead) {
236 std::string Name("(");
237 for (IdxIter I = Seq.begin(), E = Seq.end(); I != E; ++I) {
238 if (I != Seq.begin())
239 Name += '_';
240 Name += getSchedRW(*I, IsRead).Name;
241 }
242 Name += ')';
243 return Name;
244}
245
246unsigned CodeGenSchedModels::getSchedRWIdx(Record *Def, bool IsRead,
247 unsigned After) const {
248 const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
249 assert(After < RWVec.size() && "start position out of bounds");
250 for (std::vector<CodeGenSchedRW>::const_iterator I = RWVec.begin() + After,
251 E = RWVec.end(); I != E; ++I) {
252 if (I->TheDef == Def)
253 return I - RWVec.begin();
254 }
255 return 0;
256}
257
258namespace llvm {
259void splitSchedReadWrites(const RecVec &RWDefs,
260 RecVec &WriteDefs, RecVec &ReadDefs) {
261 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); RWI != RWE; ++RWI) {
262 if ((*RWI)->isSubClassOf("SchedWrite"))
263 WriteDefs.push_back(*RWI);
264 else {
265 assert((*RWI)->isSubClassOf("SchedRead") && "unknown SchedReadWrite");
266 ReadDefs.push_back(*RWI);
267 }
268 }
269}
270} // namespace llvm
271
272// Split the SchedReadWrites defs and call findRWs for each list.
273void CodeGenSchedModels::findRWs(const RecVec &RWDefs,
274 IdxVec &Writes, IdxVec &Reads) const {
275 RecVec WriteDefs;
276 RecVec ReadDefs;
277 splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs);
278 findRWs(WriteDefs, Writes, false);
279 findRWs(ReadDefs, Reads, true);
280}
281
282// Call getSchedRWIdx for all elements in a sequence of SchedRW defs.
283void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs,
284 bool IsRead) const {
285 for (RecIter RI = RWDefs.begin(), RE = RWDefs.end(); RI != RE; ++RI) {
286 unsigned Idx = getSchedRWIdx(*RI, IsRead);
287 assert(Idx && "failed to collect SchedReadWrite");
288 RWs.push_back(Idx);
289 }
290}
291
292/// Visit all the instruction definitions for this target to gather and
293/// enumerate the itinerary classes. These are the explicitly specified
294/// SchedClasses. More SchedClasses may be inferred.
295void CodeGenSchedModels::collectSchedClasses() {
296
297 // NoItinerary is always the first class at Idx=0
Andrew Trick2661b412012-07-07 04:00:00 +0000298 SchedClasses.resize(1);
299 SchedClasses.back().Name = "NoItinerary";
Andrew Trick48605c32012-09-15 00:19:57 +0000300 SchedClasses.back().ProcIndices.push_back(0);
Andrew Trick2661b412012-07-07 04:00:00 +0000301 SchedClassIdxMap[SchedClasses.back().Name] = 0;
302
303 // Gather and sort all itinerary classes used by instruction descriptions.
Andrew Trick48605c32012-09-15 00:19:57 +0000304 RecVec ItinClassList;
Andrew Trick2661b412012-07-07 04:00:00 +0000305 for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
306 E = Target.inst_end(); I != E; ++I) {
Andrew Trick48605c32012-09-15 00:19:57 +0000307 Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary");
Andrew Trick2661b412012-07-07 04:00:00 +0000308 // Map a new SchedClass with no index.
Andrew Trick48605c32012-09-15 00:19:57 +0000309 if (!SchedClassIdxMap.count(ItinDef->getName())) {
310 SchedClassIdxMap[ItinDef->getName()] = 0;
311 ItinClassList.push_back(ItinDef);
Andrew Trick2661b412012-07-07 04:00:00 +0000312 }
313 }
314 // Assign each itinerary class unique number, skipping NoItinerary==0
315 NumItineraryClasses = ItinClassList.size();
316 std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord());
317 for (unsigned i = 0, N = NumItineraryClasses; i < N; i++) {
318 Record *ItinDef = ItinClassList[i];
319 SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size();
320 SchedClasses.push_back(CodeGenSchedClass(ItinDef));
321 }
Andrew Trick48605c32012-09-15 00:19:57 +0000322 // Infer classes from SchedReadWrite resources listed for each
323 // instruction definition that inherits from class Sched.
324 for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
325 E = Target.inst_end(); I != E; ++I) {
326 if (!(*I)->TheDef->isSubClassOf("Sched"))
327 continue;
328 IdxVec Writes, Reads;
329 findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
330 // ProcIdx == 0 indicates the class applies to all processors.
331 IdxVec ProcIndices(1, 0);
332 addSchedClass(Writes, Reads, ProcIndices);
333 }
334 // Create classes for InstReadWrite defs.
335 RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
336 std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord());
337 for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI)
338 createInstRWClass(*OI);
Andrew Trick2661b412012-07-07 04:00:00 +0000339
Andrew Trick48605c32012-09-15 00:19:57 +0000340 NumInstrSchedClasses = SchedClasses.size();
Andrew Trick2661b412012-07-07 04:00:00 +0000341
Andrew Trick48605c32012-09-15 00:19:57 +0000342 bool EnableDump = false;
343 DEBUG(EnableDump = true);
344 if (!EnableDump)
Andrew Trick2661b412012-07-07 04:00:00 +0000345 return;
Andrew Trick48605c32012-09-15 00:19:57 +0000346 for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
347 E = Target.inst_end(); I != E; ++I) {
348 Record *SchedDef = (*I)->TheDef;
349 std::string InstName = (*I)->TheDef->getName();
350 if (SchedDef->isSubClassOf("Sched")) {
351 IdxVec Writes;
352 IdxVec Reads;
353 findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
354 dbgs() << "SchedRW machine model for " << InstName;
355 for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)
356 dbgs() << " " << SchedWrites[*WI].Name;
357 for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)
358 dbgs() << " " << SchedReads[*RI].Name;
359 dbgs() << '\n';
360 }
361 unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef);
362 if (SCIdx) {
363 const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
364 for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
365 RWI != RWE; ++RWI) {
366 const CodeGenProcModel &ProcModel =
367 getProcModel((*RWI)->getValueAsDef("SchedModel"));
368 dbgs() << "InstrRW on " << ProcModel.ModelName << " for " << InstName;
369 IdxVec Writes;
370 IdxVec Reads;
371 findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
372 Writes, Reads);
373 for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)
374 dbgs() << " " << SchedWrites[*WI].Name;
375 for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)
376 dbgs() << " " << SchedReads[*RI].Name;
377 dbgs() << '\n';
378 }
379 continue;
380 }
381 if (!SchedDef->isSubClassOf("Sched")
382 && (SchedDef->getValueAsDef("Itinerary")->getName() == "NoItinerary")) {
383 dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n';
Andrew Trick2661b412012-07-07 04:00:00 +0000384 }
385 }
Andrew Trick48605c32012-09-15 00:19:57 +0000386}
387
388unsigned CodeGenSchedModels::getSchedClassIdx(
389 const RecVec &RWDefs) const {
390
391 IdxVec Writes, Reads;
392 findRWs(RWDefs, Writes, Reads);
393 return findSchedClassIdx(Writes, Reads);
394}
395
396/// Find an SchedClass that has been inferred from a per-operand list of
397/// SchedWrites and SchedReads.
398unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes,
399 const IdxVec &Reads) const {
400 for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) {
401 // Classes with InstRWs may have the same Writes/Reads as a class originally
402 // produced by a SchedRW definition. We need to be able to recover the
403 // original class index for processors that don't match any InstRWs.
404 if (I->ItinClassDef || !I->InstRWs.empty())
405 continue;
406
407 if (I->Writes == Writes && I->Reads == Reads) {
408 return I - schedClassBegin();
409 }
Andrew Trick2661b412012-07-07 04:00:00 +0000410 }
Andrew Trick48605c32012-09-15 00:19:57 +0000411 return 0;
412}
Andrew Trick2661b412012-07-07 04:00:00 +0000413
Andrew Trick48605c32012-09-15 00:19:57 +0000414// Get the SchedClass index for an instruction.
415unsigned CodeGenSchedModels::getSchedClassIdx(
416 const CodeGenInstruction &Inst) const {
Andrew Trick2661b412012-07-07 04:00:00 +0000417
Andrew Trick48605c32012-09-15 00:19:57 +0000418 unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef);
419 if (SCIdx)
420 return SCIdx;
Andrew Trick2661b412012-07-07 04:00:00 +0000421
Andrew Trick48605c32012-09-15 00:19:57 +0000422 // If this opcode isn't mapped by the subtarget fallback to the instruction
423 // definition's SchedRW or ItinDef values.
424 if (Inst.TheDef->isSubClassOf("Sched")) {
425 RecVec RWs = Inst.TheDef->getValueAsListOfDefs("SchedRW");
426 return getSchedClassIdx(RWs);
427 }
428 Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary");
429 assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass");
430 unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName());
431 assert(Idx <= NumItineraryClasses && "bad ItinClass index");
432 return Idx;
433}
434
435std::string CodeGenSchedModels::createSchedClassName(
436 const IdxVec &OperWrites, const IdxVec &OperReads) {
437
438 std::string Name;
439 for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) {
440 if (WI != OperWrites.begin())
441 Name += '_';
442 Name += SchedWrites[*WI].Name;
443 }
444 for (IdxIter RI = OperReads.begin(), RE = OperReads.end(); RI != RE; ++RI) {
445 Name += '_';
446 Name += SchedReads[*RI].Name;
447 }
448 return Name;
449}
450
451std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) {
452
453 std::string Name;
454 for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) {
455 if (I != InstDefs.begin())
456 Name += '_';
457 Name += (*I)->getName();
458 }
459 return Name;
460}
461
462/// Add an inferred sched class from a per-operand list of SchedWrites and
463/// SchedReads. ProcIndices contains the set of IDs of processors that may
464/// utilize this class.
465unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites,
466 const IdxVec &OperReads,
467 const IdxVec &ProcIndices)
468{
469 assert(!ProcIndices.empty() && "expect at least one ProcIdx");
470
471 unsigned Idx = findSchedClassIdx(OperWrites, OperReads);
472 if (Idx) {
473 IdxVec PI;
474 std::set_union(SchedClasses[Idx].ProcIndices.begin(),
475 SchedClasses[Idx].ProcIndices.end(),
476 ProcIndices.begin(), ProcIndices.end(),
477 std::back_inserter(PI));
478 SchedClasses[Idx].ProcIndices.swap(PI);
479 return Idx;
480 }
481 Idx = SchedClasses.size();
482 SchedClasses.resize(Idx+1);
483 CodeGenSchedClass &SC = SchedClasses.back();
484 SC.Name = createSchedClassName(OperWrites, OperReads);
485 SC.Writes = OperWrites;
486 SC.Reads = OperReads;
487 SC.ProcIndices = ProcIndices;
488
489 return Idx;
490}
491
492// Create classes for each set of opcodes that are in the same InstReadWrite
493// definition across all processors.
494void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
495 // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that
496 // intersects with an existing class via a previous InstRWDef. Instrs that do
497 // not intersect with an existing class refer back to their former class as
498 // determined from ItinDef or SchedRW.
499 SmallVector<std::pair<unsigned, SmallVector<Record *, 8> >, 4> ClassInstrs;
500 // Sort Instrs into sets.
501 RecVec InstDefs = InstRWDef->getValueAsListOfDefs("Instrs");
502 std::sort(InstDefs.begin(), InstDefs.end(), LessRecord());
503 for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) {
504 unsigned SCIdx = 0;
505 InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I);
506 if (Pos != InstrClassMap.end())
507 SCIdx = Pos->second;
508 else {
509 // This instruction has not been mapped yet. Get the original class. All
510 // instructions in the same InstrRW class must be from the same original
511 // class because that is the fall-back class for other processors.
512 Record *ItinDef = (*I)->getValueAsDef("Itinerary");
513 SCIdx = SchedClassIdxMap.lookup(ItinDef->getName());
514 if (!SCIdx && (*I)->isSubClassOf("Sched"))
515 SCIdx = getSchedClassIdx((*I)->getValueAsListOfDefs("SchedRW"));
516 }
517 unsigned CIdx = 0, CEnd = ClassInstrs.size();
518 for (; CIdx != CEnd; ++CIdx) {
519 if (ClassInstrs[CIdx].first == SCIdx)
520 break;
521 }
522 if (CIdx == CEnd) {
523 ClassInstrs.resize(CEnd + 1);
524 ClassInstrs[CIdx].first = SCIdx;
525 }
526 ClassInstrs[CIdx].second.push_back(*I);
527 }
528 // For each set of Instrs, create a new class if necessary, and map or remap
529 // the Instrs to it.
530 unsigned CIdx = 0, CEnd = ClassInstrs.size();
531 for (; CIdx != CEnd; ++CIdx) {
532 unsigned OldSCIdx = ClassInstrs[CIdx].first;
533 ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second;
534 // If the all instrs in the current class are accounted for, then leave
535 // them mapped to their old class.
536 if (SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) {
537 assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
538 "expected a generic SchedClass");
539 continue;
540 }
541 unsigned SCIdx = SchedClasses.size();
542 SchedClasses.resize(SCIdx+1);
543 CodeGenSchedClass &SC = SchedClasses.back();
544 SC.Name = createSchedClassName(InstDefs);
545 // Preserve ItinDef and Writes/Reads for processors without an InstRW entry.
546 SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef;
547 SC.Writes = SchedClasses[OldSCIdx].Writes;
548 SC.Reads = SchedClasses[OldSCIdx].Reads;
549 SC.ProcIndices.push_back(0);
550 // Map each Instr to this new class.
551 // Note that InstDefs may be a smaller list than InstRWDef's "Instrs".
552 for (ArrayRef<Record*>::const_iterator
553 II = InstDefs.begin(), IE = InstDefs.end(); II != IE; ++II) {
554 unsigned OldSCIdx = InstrClassMap[*II];
555 if (OldSCIdx) {
556 SC.InstRWs.insert(SC.InstRWs.end(),
557 SchedClasses[OldSCIdx].InstRWs.begin(),
558 SchedClasses[OldSCIdx].InstRWs.end());
559 }
560 InstrClassMap[*II] = SCIdx;
561 }
562 SC.InstRWs.push_back(InstRWDef);
563 }
Andrew Trick2661b412012-07-07 04:00:00 +0000564}
565
566// Gather the processor itineraries.
Andrew Trick48605c32012-09-15 00:19:57 +0000567void CodeGenSchedModels::collectProcItins() {
568 for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(),
569 PE = ProcModels.end(); PI != PE; ++PI) {
570 CodeGenProcModel &ProcModel = *PI;
571 RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID");
572 // Skip empty itinerary.
573 if (ItinRecords.empty())
Andrew Trick2661b412012-07-07 04:00:00 +0000574 continue;
Andrew Trick48605c32012-09-15 00:19:57 +0000575
576 ProcModel.ItinDefList.resize(NumItineraryClasses+1);
577
578 // Insert each itinerary data record in the correct position within
579 // the processor model's ItinDefList.
580 for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) {
581 Record *ItinData = ItinRecords[i];
582 Record *ItinDef = ItinData->getValueAsDef("TheClass");
583 if (!SchedClassIdxMap.count(ItinDef->getName())) {
584 DEBUG(dbgs() << ProcModel.ItinsDef->getName()
585 << " has unused itinerary class " << ItinDef->getName() << '\n');
586 continue;
587 }
588 assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass");
589 unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName());
590 assert(Idx <= NumItineraryClasses && "bad ItinClass index");
591 ProcModel.ItinDefList[Idx] = ItinData;
Andrew Trick2661b412012-07-07 04:00:00 +0000592 }
Andrew Trick48605c32012-09-15 00:19:57 +0000593 // Check for missing itinerary entries.
594 assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec");
595 DEBUG(
596 for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) {
597 if (!ProcModel.ItinDefList[i])
598 dbgs() << ProcModel.ItinsDef->getName()
599 << " missing itinerary for class "
600 << SchedClasses[i].Name << '\n';
601 });
Andrew Trick2661b412012-07-07 04:00:00 +0000602 }
Andrew Trick2661b412012-07-07 04:00:00 +0000603}
Andrew Trick48605c32012-09-15 00:19:57 +0000604
605// Gather the read/write types for each itinerary class.
606void CodeGenSchedModels::collectProcItinRW() {
607 RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
608 std::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord());
609 for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) {
610 if (!(*II)->getValueInit("SchedModel")->isComplete())
611 throw TGError((*II)->getLoc(), "SchedModel is undefined");
612 Record *ModelDef = (*II)->getValueAsDef("SchedModel");
613 ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
614 if (I == ProcModelMap.end()) {
615 throw TGError((*II)->getLoc(), "Undefined SchedMachineModel "
616 + ModelDef->getName());
617 }
618 ProcModels[I->second].ItinRWDefs.push_back(*II);
619 }
620}
621
622#ifndef NDEBUG
623void CodeGenProcModel::dump() const {
624 dbgs() << Index << ": " << ModelName << " "
625 << (ModelDef ? ModelDef->getName() : "inferred") << " "
626 << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n';
627}
628
629void CodeGenSchedRW::dump() const {
630 dbgs() << Name << (IsVariadic ? " (V) " : " ");
631 if (IsSequence) {
632 dbgs() << "(";
633 dumpIdxVec(Sequence);
634 dbgs() << ")";
635 }
636}
637
638void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
639 dbgs() << "SCHEDCLASS " << Name << '\n'
640 << " Writes: ";
641 for (unsigned i = 0, N = Writes.size(); i < N; ++i) {
642 SchedModels->getSchedWrite(Writes[i]).dump();
643 if (i < N-1) {
644 dbgs() << '\n';
645 dbgs().indent(10);
646 }
647 }
648 dbgs() << "\n Reads: ";
649 for (unsigned i = 0, N = Reads.size(); i < N; ++i) {
650 SchedModels->getSchedRead(Reads[i]).dump();
651 if (i < N-1) {
652 dbgs() << '\n';
653 dbgs().indent(10);
654 }
655 }
656 dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n';
657}
658#endif // NDEBUG