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