1 | //===- CodeGenSchedule.h - Scheduling Machine Models ------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines structures to encapsulate the machine model as described in |
10 | // the target description. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H |
15 | #define LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H |
16 | |
17 | #include "llvm/ADT/APInt.h" |
18 | #include "llvm/ADT/ArrayRef.h" |
19 | #include "llvm/ADT/DenseMap.h" |
20 | #include "llvm/ADT/DenseSet.h" |
21 | #include "llvm/ADT/STLExtras.h" |
22 | #include "llvm/ADT/StringRef.h" |
23 | #include "llvm/TableGen/Record.h" |
24 | #include "llvm/TableGen/SetTheory.h" |
25 | #include <cassert> |
26 | #include <string> |
27 | #include <utility> |
28 | #include <vector> |
29 | |
30 | namespace llvm { |
31 | |
32 | class CodeGenTarget; |
33 | class CodeGenSchedModels; |
34 | class CodeGenInstruction; |
35 | |
36 | using RecVec = std::vector<Record *>; |
37 | using RecIter = std::vector<Record *>::const_iterator; |
38 | |
39 | using IdxVec = std::vector<unsigned>; |
40 | using IdxIter = std::vector<unsigned>::const_iterator; |
41 | |
42 | /// We have two kinds of SchedReadWrites. Explicitly defined and inferred |
43 | /// sequences. TheDef is nonnull for explicit SchedWrites, but Sequence may or |
44 | /// may not be empty. TheDef is null for inferred sequences, and Sequence must |
45 | /// be nonempty. |
46 | /// |
47 | /// IsVariadic controls whether the variants are expanded into multiple operands |
48 | /// or a sequence of writes on one operand. |
49 | struct CodeGenSchedRW { |
50 | unsigned Index; |
51 | std::string Name; |
52 | Record *TheDef; |
53 | bool IsRead; |
54 | bool IsAlias; |
55 | bool HasVariants; |
56 | bool IsVariadic; |
57 | bool IsSequence; |
58 | IdxVec Sequence; |
59 | RecVec Aliases; |
60 | |
61 | CodeGenSchedRW() |
62 | : Index(0), TheDef(nullptr), IsRead(false), IsAlias(false), |
63 | HasVariants(false), IsVariadic(false), IsSequence(false) {} |
64 | CodeGenSchedRW(unsigned Idx, Record *Def) |
65 | : Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) { |
66 | Name = std::string(Def->getName()); |
67 | IsRead = Def->isSubClassOf(Name: "SchedRead" ); |
68 | HasVariants = Def->isSubClassOf(Name: "SchedVariant" ); |
69 | if (HasVariants) |
70 | IsVariadic = Def->getValueAsBit(FieldName: "Variadic" ); |
71 | |
72 | // Read records don't currently have sequences, but it can be easily |
73 | // added. Note that implicit Reads (from ReadVariant) may have a Sequence |
74 | // (but no record). |
75 | IsSequence = Def->isSubClassOf(Name: "WriteSequence" ); |
76 | } |
77 | |
78 | CodeGenSchedRW(unsigned Idx, bool Read, ArrayRef<unsigned> Seq, |
79 | const std::string &Name) |
80 | : Index(Idx), Name(Name), TheDef(nullptr), IsRead(Read), IsAlias(false), |
81 | HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) { |
82 | assert(Sequence.size() > 1 && "implied sequence needs >1 RWs" ); |
83 | } |
84 | |
85 | bool isValid() const { |
86 | assert((!HasVariants || TheDef) && "Variant write needs record def" ); |
87 | assert((!IsVariadic || HasVariants) && "Variadic write needs variants" ); |
88 | assert((!IsSequence || !HasVariants) && "Sequence can't have variant" ); |
89 | assert((!IsSequence || !Sequence.empty()) && "Sequence should be nonempty" ); |
90 | assert((!IsAlias || Aliases.empty()) && "Alias cannot have aliases" ); |
91 | return TheDef || !Sequence.empty(); |
92 | } |
93 | |
94 | #ifndef NDEBUG |
95 | void dump() const; |
96 | #endif |
97 | }; |
98 | |
99 | /// Represent a transition between SchedClasses induced by SchedVariant. |
100 | struct CodeGenSchedTransition { |
101 | unsigned ToClassIdx; |
102 | unsigned ProcIndex; |
103 | RecVec PredTerm; |
104 | }; |
105 | |
106 | /// Scheduling class. |
107 | /// |
108 | /// Each instruction description will be mapped to a scheduling class. There are |
109 | /// four types of classes: |
110 | /// |
111 | /// 1) An explicitly defined itinerary class with ItinClassDef set. |
112 | /// Writes and ReadDefs are empty. ProcIndices contains 0 for any processor. |
113 | /// |
114 | /// 2) An implied class with a list of SchedWrites and SchedReads that are |
115 | /// defined in an instruction definition and which are common across all |
116 | /// subtargets. ProcIndices contains 0 for any processor. |
117 | /// |
118 | /// 3) An implied class with a list of InstRW records that map instructions to |
119 | /// SchedWrites and SchedReads per-processor. InstrClassMap should map the same |
120 | /// instructions to this class. ProcIndices contains all the processors that |
121 | /// provided InstrRW records for this class. ItinClassDef or Writes/Reads may |
122 | /// still be defined for processors with no InstRW entry. |
123 | /// |
124 | /// 4) An inferred class represents a variant of another class that may be |
125 | /// resolved at runtime. ProcIndices contains the set of processors that may |
126 | /// require the class. ProcIndices are propagated through SchedClasses as |
127 | /// variants are expanded. Multiple SchedClasses may be inferred from an |
128 | /// itinerary class. Each inherits the processor index from the ItinRW record |
129 | /// that mapped the itinerary class to the variant Writes or Reads. |
130 | struct CodeGenSchedClass { |
131 | unsigned Index; |
132 | std::string Name; |
133 | Record *ItinClassDef; |
134 | |
135 | IdxVec Writes; |
136 | IdxVec Reads; |
137 | // Sorted list of ProcIdx, where ProcIdx==0 implies any processor. |
138 | IdxVec ProcIndices; |
139 | |
140 | std::vector<CodeGenSchedTransition> Transitions; |
141 | |
142 | // InstRW records associated with this class. These records may refer to an |
143 | // Instruction no longer mapped to this class by InstrClassMap. These |
144 | // Instructions should be ignored by this class because they have been split |
145 | // off to join another inferred class. |
146 | RecVec InstRWs; |
147 | // InstRWs processor indices. Filled in inferFromInstRWs |
148 | DenseSet<unsigned> InstRWProcIndices; |
149 | |
150 | CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef) |
151 | : Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {} |
152 | |
153 | bool isKeyEqual(Record *IC, ArrayRef<unsigned> W, |
154 | ArrayRef<unsigned> R) const { |
155 | return ItinClassDef == IC && ArrayRef(Writes) == W && ArrayRef(Reads) == R; |
156 | } |
157 | |
158 | // Is this class generated from a variants if existing classes? Instructions |
159 | // are never mapped directly to inferred scheduling classes. |
160 | bool isInferred() const { return !ItinClassDef; } |
161 | |
162 | #ifndef NDEBUG |
163 | void dump(const CodeGenSchedModels *SchedModels) const; |
164 | #endif |
165 | }; |
166 | |
167 | /// Represent the cost of allocating a register of register class RCDef. |
168 | /// |
169 | /// The cost of allocating a register is equivalent to the number of physical |
170 | /// registers used by the register renamer. Register costs are defined at |
171 | /// register class granularity. |
172 | struct CodeGenRegisterCost { |
173 | Record *RCDef; |
174 | unsigned Cost; |
175 | bool AllowMoveElimination; |
176 | CodeGenRegisterCost(Record *RC, unsigned RegisterCost, |
177 | bool AllowMoveElim = false) |
178 | : RCDef(RC), Cost(RegisterCost), AllowMoveElimination(AllowMoveElim) {} |
179 | CodeGenRegisterCost(const CodeGenRegisterCost &) = default; |
180 | CodeGenRegisterCost &operator=(const CodeGenRegisterCost &) = delete; |
181 | }; |
182 | |
183 | /// A processor register file. |
184 | /// |
185 | /// This class describes a processor register file. Register file information is |
186 | /// currently consumed by external tools like llvm-mca to predict dispatch |
187 | /// stalls due to register pressure. |
188 | struct CodeGenRegisterFile { |
189 | std::string Name; |
190 | Record *RegisterFileDef; |
191 | unsigned MaxMovesEliminatedPerCycle; |
192 | bool AllowZeroMoveEliminationOnly; |
193 | |
194 | unsigned NumPhysRegs; |
195 | std::vector<CodeGenRegisterCost> Costs; |
196 | |
197 | CodeGenRegisterFile(StringRef name, Record *def, |
198 | unsigned MaxMoveElimPerCy = 0, |
199 | bool AllowZeroMoveElimOnly = false) |
200 | : Name(name), RegisterFileDef(def), |
201 | MaxMovesEliminatedPerCycle(MaxMoveElimPerCy), |
202 | AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly), NumPhysRegs(0) {} |
203 | |
204 | bool hasDefaultCosts() const { return Costs.empty(); } |
205 | }; |
206 | |
207 | // Processor model. |
208 | // |
209 | // ModelName is a unique name used to name an instantiation of MCSchedModel. |
210 | // |
211 | // ModelDef is NULL for inferred Models. This happens when a processor defines |
212 | // an itinerary but no machine model. If the processor defines neither a machine |
213 | // model nor itinerary, then ModelDef remains pointing to NoModel. NoModel has |
214 | // the special "NoModel" field set to true. |
215 | // |
216 | // ItinsDef always points to a valid record definition, but may point to the |
217 | // default NoItineraries. NoItineraries has an empty list of InstrItinData |
218 | // records. |
219 | // |
220 | // ItinDefList orders this processor's InstrItinData records by SchedClass idx. |
221 | struct CodeGenProcModel { |
222 | unsigned Index; |
223 | std::string ModelName; |
224 | Record *ModelDef; |
225 | Record *ItinsDef; |
226 | |
227 | // Derived members... |
228 | |
229 | // Array of InstrItinData records indexed by a CodeGenSchedClass index. |
230 | // This list is empty if the Processor has no value for Itineraries. |
231 | // Initialized by collectProcItins(). |
232 | RecVec ItinDefList; |
233 | |
234 | // Map itinerary classes to per-operand resources. |
235 | // This list is empty if no ItinRW refers to this Processor. |
236 | RecVec ItinRWDefs; |
237 | |
238 | // List of unsupported feature. |
239 | // This list is empty if the Processor has no UnsupportedFeatures. |
240 | RecVec UnsupportedFeaturesDefs; |
241 | |
242 | // All read/write resources associated with this processor. |
243 | RecVec WriteResDefs; |
244 | RecVec ReadAdvanceDefs; |
245 | |
246 | // Per-operand machine model resources associated with this processor. |
247 | RecVec ProcResourceDefs; |
248 | |
249 | // List of Register Files. |
250 | std::vector<CodeGenRegisterFile> RegisterFiles; |
251 | |
252 | // Optional Retire Control Unit definition. |
253 | Record *RetireControlUnit; |
254 | |
255 | // Load/Store queue descriptors. |
256 | Record *LoadQueue; |
257 | Record *StoreQueue; |
258 | |
259 | CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef, Record *IDef) |
260 | : Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef), |
261 | RetireControlUnit(nullptr), LoadQueue(nullptr), StoreQueue(nullptr) {} |
262 | |
263 | bool hasItineraries() const { |
264 | return !ItinsDef->getValueAsListOfDefs(FieldName: "IID" ).empty(); |
265 | } |
266 | |
267 | bool hasInstrSchedModel() const { |
268 | return !WriteResDefs.empty() || !ItinRWDefs.empty(); |
269 | } |
270 | |
271 | bool () const { |
272 | return RetireControlUnit || LoadQueue || StoreQueue || |
273 | !RegisterFiles.empty(); |
274 | } |
275 | |
276 | unsigned getProcResourceIdx(Record *PRDef) const; |
277 | |
278 | bool isUnsupported(const CodeGenInstruction &Inst) const; |
279 | |
280 | // Return true if the given write record is referenced by a ReadAdvance. |
281 | bool hasReadOfWrite(Record *WriteDef) const; |
282 | |
283 | #ifndef NDEBUG |
284 | void dump() const; |
285 | #endif |
286 | }; |
287 | |
288 | /// Used to correlate instructions to MCInstPredicates specified by |
289 | /// InstructionEquivalentClass tablegen definitions. |
290 | /// |
291 | /// Example: a XOR of a register with self, is a known zero-idiom for most |
292 | /// X86 processors. |
293 | /// |
294 | /// Each processor can use a (potentially different) InstructionEquivalenceClass |
295 | /// definition to classify zero-idioms. That means, XORrr is likely to appear |
296 | /// in more than one equivalence class (where each class definition is |
297 | /// contributed by a different processor). |
298 | /// |
299 | /// There is no guarantee that the same MCInstPredicate will be used to describe |
300 | /// equivalence classes that identify XORrr as a zero-idiom. |
301 | /// |
302 | /// To be more specific, the requirements for being a zero-idiom XORrr may be |
303 | /// different for different processors. |
304 | /// |
305 | /// Class PredicateInfo identifies a subset of processors that specify the same |
306 | /// requirements (i.e. same MCInstPredicate and OperandMask) for an instruction |
307 | /// opcode. |
308 | /// |
309 | /// Back to the example. Field `ProcModelMask` will have one bit set for every |
310 | /// processor model that sees XORrr as a zero-idiom, and that specifies the same |
311 | /// set of constraints. |
312 | /// |
313 | /// By construction, there can be multiple instances of PredicateInfo associated |
314 | /// with a same instruction opcode. For example, different processors may define |
315 | /// different constraints on the same opcode. |
316 | /// |
317 | /// Field OperandMask can be used as an extra constraint. |
318 | /// It may be used to describe conditions that appy only to a subset of the |
319 | /// operands of a machine instruction, and the operands subset may not be the |
320 | /// same for all processor models. |
321 | struct PredicateInfo { |
322 | llvm::APInt ProcModelMask; // A set of processor model indices. |
323 | llvm::APInt OperandMask; // An operand mask. |
324 | const Record *Predicate; // MCInstrPredicate definition. |
325 | PredicateInfo(llvm::APInt CpuMask, llvm::APInt Operands, const Record *Pred) |
326 | : ProcModelMask(CpuMask), OperandMask(Operands), Predicate(Pred) {} |
327 | |
328 | bool operator==(const PredicateInfo &Other) const { |
329 | return ProcModelMask == Other.ProcModelMask && |
330 | OperandMask == Other.OperandMask && Predicate == Other.Predicate; |
331 | } |
332 | }; |
333 | |
334 | /// A collection of PredicateInfo objects. |
335 | /// |
336 | /// There is at least one OpcodeInfo object for every opcode specified by a |
337 | /// TIPredicate definition. |
338 | class OpcodeInfo { |
339 | std::vector<PredicateInfo> Predicates; |
340 | |
341 | OpcodeInfo(const OpcodeInfo &Other) = delete; |
342 | OpcodeInfo &operator=(const OpcodeInfo &Other) = delete; |
343 | |
344 | public: |
345 | OpcodeInfo() = default; |
346 | OpcodeInfo &operator=(OpcodeInfo &&Other) = default; |
347 | OpcodeInfo(OpcodeInfo &&Other) = default; |
348 | |
349 | ArrayRef<PredicateInfo> getPredicates() const { return Predicates; } |
350 | |
351 | void addPredicateForProcModel(const llvm::APInt &CpuMask, |
352 | const llvm::APInt &OperandMask, |
353 | const Record *Predicate); |
354 | }; |
355 | |
356 | /// Used to group together tablegen instruction definitions that are subject |
357 | /// to a same set of constraints (identified by an instance of OpcodeInfo). |
358 | class OpcodeGroup { |
359 | OpcodeInfo Info; |
360 | std::vector<const Record *> Opcodes; |
361 | |
362 | OpcodeGroup(const OpcodeGroup &Other) = delete; |
363 | OpcodeGroup &operator=(const OpcodeGroup &Other) = delete; |
364 | |
365 | public: |
366 | OpcodeGroup(OpcodeInfo &&OpInfo) : Info(std::move(OpInfo)) {} |
367 | OpcodeGroup(OpcodeGroup &&Other) = default; |
368 | |
369 | void addOpcode(const Record *Opcode) { |
370 | assert(!llvm::is_contained(Opcodes, Opcode) && "Opcode already in set!" ); |
371 | Opcodes.push_back(x: Opcode); |
372 | } |
373 | |
374 | ArrayRef<const Record *> getOpcodes() const { return Opcodes; } |
375 | const OpcodeInfo &getOpcodeInfo() const { return Info; } |
376 | }; |
377 | |
378 | /// An STIPredicateFunction descriptor used by tablegen backends to |
379 | /// auto-generate the body of a predicate function as a member of tablegen'd |
380 | /// class XXXGenSubtargetInfo. |
381 | class STIPredicateFunction { |
382 | const Record *FunctionDeclaration; |
383 | |
384 | std::vector<const Record *> Definitions; |
385 | std::vector<OpcodeGroup> Groups; |
386 | |
387 | STIPredicateFunction(const STIPredicateFunction &Other) = delete; |
388 | STIPredicateFunction &operator=(const STIPredicateFunction &Other) = delete; |
389 | |
390 | public: |
391 | STIPredicateFunction(const Record *Rec) : FunctionDeclaration(Rec) {} |
392 | STIPredicateFunction(STIPredicateFunction &&Other) = default; |
393 | |
394 | bool isCompatibleWith(const STIPredicateFunction &Other) const { |
395 | return FunctionDeclaration == Other.FunctionDeclaration; |
396 | } |
397 | |
398 | void addDefinition(const Record *Def) { Definitions.push_back(x: Def); } |
399 | void addOpcode(const Record *OpcodeRec, OpcodeInfo &&Info) { |
400 | if (Groups.empty() || |
401 | Groups.back().getOpcodeInfo().getPredicates() != Info.getPredicates()) |
402 | Groups.emplace_back(args: std::move(Info)); |
403 | Groups.back().addOpcode(Opcode: OpcodeRec); |
404 | } |
405 | |
406 | StringRef getName() const { |
407 | return FunctionDeclaration->getValueAsString(FieldName: "Name" ); |
408 | } |
409 | const Record *getDefaultReturnPredicate() const { |
410 | return FunctionDeclaration->getValueAsDef(FieldName: "DefaultReturnValue" ); |
411 | } |
412 | |
413 | const Record *getDeclaration() const { return FunctionDeclaration; } |
414 | ArrayRef<const Record *> getDefinitions() const { return Definitions; } |
415 | ArrayRef<OpcodeGroup> getGroups() const { return Groups; } |
416 | }; |
417 | |
418 | using ProcModelMapTy = DenseMap<const Record *, unsigned>; |
419 | |
420 | /// Top level container for machine model data. |
421 | class CodeGenSchedModels { |
422 | RecordKeeper &Records; |
423 | const CodeGenTarget &Target; |
424 | |
425 | // Map dag expressions to Instruction lists. |
426 | SetTheory Sets; |
427 | |
428 | // List of unique processor models. |
429 | std::vector<CodeGenProcModel> ProcModels; |
430 | |
431 | // Map Processor's MachineModel or ProcItin to a CodeGenProcModel index. |
432 | ProcModelMapTy ProcModelMap; |
433 | |
434 | // Per-operand SchedReadWrite types. |
435 | std::vector<CodeGenSchedRW> SchedWrites; |
436 | std::vector<CodeGenSchedRW> SchedReads; |
437 | |
438 | // List of unique SchedClasses. |
439 | std::vector<CodeGenSchedClass> SchedClasses; |
440 | |
441 | // Any inferred SchedClass has an index greater than NumInstrSchedClassses. |
442 | unsigned NumInstrSchedClasses; |
443 | |
444 | RecVec ProcResourceDefs; |
445 | RecVec ProcResGroups; |
446 | |
447 | // Map each instruction to its unique SchedClass index considering the |
448 | // combination of it's itinerary class, SchedRW list, and InstRW records. |
449 | using InstClassMapTy = DenseMap<Record *, unsigned>; |
450 | InstClassMapTy InstrClassMap; |
451 | |
452 | std::vector<STIPredicateFunction> STIPredicates; |
453 | std::vector<unsigned> getAllProcIndices() const; |
454 | |
455 | public: |
456 | CodeGenSchedModels(RecordKeeper &RK, const CodeGenTarget &TGT); |
457 | |
458 | // iterator access to the scheduling classes. |
459 | using class_iterator = std::vector<CodeGenSchedClass>::iterator; |
460 | using const_class_iterator = std::vector<CodeGenSchedClass>::const_iterator; |
461 | class_iterator classes_begin() { return SchedClasses.begin(); } |
462 | const_class_iterator classes_begin() const { return SchedClasses.begin(); } |
463 | class_iterator classes_end() { return SchedClasses.end(); } |
464 | const_class_iterator classes_end() const { return SchedClasses.end(); } |
465 | iterator_range<class_iterator> classes() { |
466 | return make_range(x: classes_begin(), y: classes_end()); |
467 | } |
468 | iterator_range<const_class_iterator> classes() const { |
469 | return make_range(x: classes_begin(), y: classes_end()); |
470 | } |
471 | iterator_range<class_iterator> explicit_classes() { |
472 | return make_range(x: classes_begin(), y: classes_begin() + NumInstrSchedClasses); |
473 | } |
474 | iterator_range<const_class_iterator> explicit_classes() const { |
475 | return make_range(x: classes_begin(), y: classes_begin() + NumInstrSchedClasses); |
476 | } |
477 | |
478 | Record *getModelOrItinDef(Record *ProcDef) const { |
479 | Record *ModelDef = ProcDef->getValueAsDef(FieldName: "SchedModel" ); |
480 | Record *ItinsDef = ProcDef->getValueAsDef(FieldName: "ProcItin" ); |
481 | if (!ItinsDef->getValueAsListOfDefs(FieldName: "IID" ).empty()) { |
482 | assert(ModelDef->getValueAsBit("NoModel" ) && |
483 | "Itineraries must be defined within SchedMachineModel" ); |
484 | return ItinsDef; |
485 | } |
486 | return ModelDef; |
487 | } |
488 | |
489 | const CodeGenProcModel &getModelForProc(Record *ProcDef) const { |
490 | Record *ModelDef = getModelOrItinDef(ProcDef); |
491 | ProcModelMapTy::const_iterator I = ProcModelMap.find(Val: ModelDef); |
492 | assert(I != ProcModelMap.end() && "missing machine model" ); |
493 | return ProcModels[I->second]; |
494 | } |
495 | |
496 | CodeGenProcModel &getProcModel(Record *ModelDef) { |
497 | ProcModelMapTy::const_iterator I = ProcModelMap.find(Val: ModelDef); |
498 | assert(I != ProcModelMap.end() && "missing machine model" ); |
499 | return ProcModels[I->second]; |
500 | } |
501 | const CodeGenProcModel &getProcModel(Record *ModelDef) const { |
502 | return const_cast<CodeGenSchedModels *>(this)->getProcModel(ModelDef); |
503 | } |
504 | |
505 | // Iterate over the unique processor models. |
506 | using ProcIter = std::vector<CodeGenProcModel>::const_iterator; |
507 | ProcIter procModelBegin() const { return ProcModels.begin(); } |
508 | ProcIter procModelEnd() const { return ProcModels.end(); } |
509 | ArrayRef<CodeGenProcModel> procModels() const { return ProcModels; } |
510 | |
511 | // Return true if any processors have itineraries. |
512 | bool hasItineraries() const; |
513 | |
514 | // Get a SchedWrite from its index. |
515 | const CodeGenSchedRW &getSchedWrite(unsigned Idx) const { |
516 | assert(Idx < SchedWrites.size() && "bad SchedWrite index" ); |
517 | assert(SchedWrites[Idx].isValid() && "invalid SchedWrite" ); |
518 | return SchedWrites[Idx]; |
519 | } |
520 | // Get a SchedWrite from its index. |
521 | const CodeGenSchedRW &getSchedRead(unsigned Idx) const { |
522 | assert(Idx < SchedReads.size() && "bad SchedRead index" ); |
523 | assert(SchedReads[Idx].isValid() && "invalid SchedRead" ); |
524 | return SchedReads[Idx]; |
525 | } |
526 | |
527 | const CodeGenSchedRW &getSchedRW(unsigned Idx, bool IsRead) const { |
528 | return IsRead ? getSchedRead(Idx) : getSchedWrite(Idx); |
529 | } |
530 | CodeGenSchedRW &getSchedRW(Record *Def) { |
531 | bool IsRead = Def->isSubClassOf(Name: "SchedRead" ); |
532 | unsigned Idx = getSchedRWIdx(Def, IsRead); |
533 | return const_cast<CodeGenSchedRW &>(IsRead ? getSchedRead(Idx) |
534 | : getSchedWrite(Idx)); |
535 | } |
536 | const CodeGenSchedRW &getSchedRW(Record *Def) const { |
537 | return const_cast<CodeGenSchedModels &>(*this).getSchedRW(Def); |
538 | } |
539 | |
540 | unsigned getSchedRWIdx(const Record *Def, bool IsRead) const; |
541 | |
542 | // Get a SchedClass from its index. |
543 | CodeGenSchedClass &getSchedClass(unsigned Idx) { |
544 | assert(Idx < SchedClasses.size() && "bad SchedClass index" ); |
545 | return SchedClasses[Idx]; |
546 | } |
547 | const CodeGenSchedClass &getSchedClass(unsigned Idx) const { |
548 | assert(Idx < SchedClasses.size() && "bad SchedClass index" ); |
549 | return SchedClasses[Idx]; |
550 | } |
551 | |
552 | // Get the SchedClass index for an instruction. Instructions with no |
553 | // itinerary, no SchedReadWrites, and no InstrReadWrites references return 0 |
554 | // for NoItinerary. |
555 | unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const; |
556 | |
557 | using SchedClassIter = std::vector<CodeGenSchedClass>::const_iterator; |
558 | SchedClassIter schedClassBegin() const { return SchedClasses.begin(); } |
559 | SchedClassIter schedClassEnd() const { return SchedClasses.end(); } |
560 | ArrayRef<CodeGenSchedClass> schedClasses() const { return SchedClasses; } |
561 | |
562 | unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; } |
563 | |
564 | void findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const; |
565 | void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const; |
566 | void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const; |
567 | void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead, |
568 | const CodeGenProcModel &ProcModel) const; |
569 | |
570 | unsigned addSchedClass(Record *ItinDef, ArrayRef<unsigned> OperWrites, |
571 | ArrayRef<unsigned> OperReads, |
572 | ArrayRef<unsigned> ProcIndices); |
573 | |
574 | unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead); |
575 | |
576 | Record *findProcResUnits(Record *ProcResKind, const CodeGenProcModel &PM, |
577 | ArrayRef<SMLoc> Loc) const; |
578 | |
579 | ArrayRef<STIPredicateFunction> getSTIPredicates() const { |
580 | return STIPredicates; |
581 | } |
582 | |
583 | private: |
584 | void collectProcModels(); |
585 | |
586 | // Initialize a new processor model if it is unique. |
587 | void addProcModel(Record *ProcDef); |
588 | |
589 | void collectSchedRW(); |
590 | |
591 | std::string genRWName(ArrayRef<unsigned> Seq, bool IsRead); |
592 | unsigned findRWForSequence(ArrayRef<unsigned> Seq, bool IsRead); |
593 | |
594 | void collectSchedClasses(); |
595 | |
596 | void collectRetireControlUnits(); |
597 | |
598 | void collectRegisterFiles(); |
599 | |
600 | void collectOptionalProcessorInfo(); |
601 | |
602 | std::string createSchedClassName(Record *ItinClassDef, |
603 | ArrayRef<unsigned> OperWrites, |
604 | ArrayRef<unsigned> OperReads); |
605 | std::string createSchedClassName(const RecVec &InstDefs); |
606 | void createInstRWClass(Record *InstRWDef); |
607 | |
608 | void collectProcItins(); |
609 | |
610 | void collectProcItinRW(); |
611 | |
612 | void collectProcUnsupportedFeatures(); |
613 | |
614 | void inferSchedClasses(); |
615 | |
616 | void checkMCInstPredicates() const; |
617 | |
618 | void checkSTIPredicates() const; |
619 | |
620 | void collectSTIPredicates(); |
621 | |
622 | void collectLoadStoreQueueInfo(); |
623 | |
624 | void checkCompleteness(); |
625 | |
626 | void inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads, |
627 | unsigned FromClassIdx, ArrayRef<unsigned> ProcIndices); |
628 | void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx); |
629 | void inferFromInstRWs(unsigned SCIdx); |
630 | |
631 | bool hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM); |
632 | void verifyProcResourceGroups(CodeGenProcModel &PM); |
633 | |
634 | void collectProcResources(); |
635 | |
636 | void collectItinProcResources(Record *ItinClassDef); |
637 | |
638 | void collectRWResources(unsigned RWIdx, bool IsRead, |
639 | ArrayRef<unsigned> ProcIndices); |
640 | |
641 | void collectRWResources(ArrayRef<unsigned> Writes, ArrayRef<unsigned> Reads, |
642 | ArrayRef<unsigned> ProcIndices); |
643 | |
644 | void addProcResource(Record *ProcResourceKind, CodeGenProcModel &PM, |
645 | ArrayRef<SMLoc> Loc); |
646 | |
647 | void addWriteRes(Record *ProcWriteResDef, unsigned PIdx); |
648 | |
649 | void addReadAdvance(Record *ProcReadAdvanceDef, unsigned PIdx); |
650 | }; |
651 | |
652 | } // namespace llvm |
653 | |
654 | #endif |
655 | |