106f32e7eSjoerg //===- CodeGenSchedule.h - Scheduling Machine Models ------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file defines structures to encapsulate the machine model as described in
1006f32e7eSjoerg // the target description.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg 
1406f32e7eSjoerg #ifndef LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H
1506f32e7eSjoerg #define LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H
1606f32e7eSjoerg 
1706f32e7eSjoerg #include "llvm/ADT/APInt.h"
1806f32e7eSjoerg #include "llvm/ADT/DenseMap.h"
19*da58b97aSjoerg #include "llvm/ADT/STLExtras.h"
2006f32e7eSjoerg #include "llvm/ADT/StringMap.h"
2106f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
2206f32e7eSjoerg #include "llvm/TableGen/Record.h"
2306f32e7eSjoerg #include "llvm/TableGen/SetTheory.h"
24*da58b97aSjoerg #include <map>
2506f32e7eSjoerg 
2606f32e7eSjoerg namespace llvm {
2706f32e7eSjoerg 
2806f32e7eSjoerg class CodeGenTarget;
2906f32e7eSjoerg class CodeGenSchedModels;
3006f32e7eSjoerg class CodeGenInstruction;
3106f32e7eSjoerg class CodeGenRegisterClass;
3206f32e7eSjoerg 
3306f32e7eSjoerg using RecVec = std::vector<Record*>;
3406f32e7eSjoerg using RecIter = std::vector<Record*>::const_iterator;
3506f32e7eSjoerg 
3606f32e7eSjoerg using IdxVec = std::vector<unsigned>;
3706f32e7eSjoerg using IdxIter = std::vector<unsigned>::const_iterator;
3806f32e7eSjoerg 
3906f32e7eSjoerg /// We have two kinds of SchedReadWrites. Explicitly defined and inferred
4006f32e7eSjoerg /// sequences.  TheDef is nonnull for explicit SchedWrites, but Sequence may or
4106f32e7eSjoerg /// may not be empty. TheDef is null for inferred sequences, and Sequence must
4206f32e7eSjoerg /// be nonempty.
4306f32e7eSjoerg ///
4406f32e7eSjoerg /// IsVariadic controls whether the variants are expanded into multiple operands
4506f32e7eSjoerg /// or a sequence of writes on one operand.
4606f32e7eSjoerg struct CodeGenSchedRW {
4706f32e7eSjoerg   unsigned Index;
4806f32e7eSjoerg   std::string Name;
4906f32e7eSjoerg   Record *TheDef;
5006f32e7eSjoerg   bool IsRead;
5106f32e7eSjoerg   bool IsAlias;
5206f32e7eSjoerg   bool HasVariants;
5306f32e7eSjoerg   bool IsVariadic;
5406f32e7eSjoerg   bool IsSequence;
5506f32e7eSjoerg   IdxVec Sequence;
5606f32e7eSjoerg   RecVec Aliases;
5706f32e7eSjoerg 
CodeGenSchedRWCodeGenSchedRW5806f32e7eSjoerg   CodeGenSchedRW()
5906f32e7eSjoerg     : Index(0), TheDef(nullptr), IsRead(false), IsAlias(false),
6006f32e7eSjoerg       HasVariants(false), IsVariadic(false), IsSequence(false) {}
CodeGenSchedRWCodeGenSchedRW6106f32e7eSjoerg   CodeGenSchedRW(unsigned Idx, Record *Def)
6206f32e7eSjoerg     : Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) {
63*da58b97aSjoerg     Name = std::string(Def->getName());
6406f32e7eSjoerg     IsRead = Def->isSubClassOf("SchedRead");
6506f32e7eSjoerg     HasVariants = Def->isSubClassOf("SchedVariant");
6606f32e7eSjoerg     if (HasVariants)
6706f32e7eSjoerg       IsVariadic = Def->getValueAsBit("Variadic");
6806f32e7eSjoerg 
6906f32e7eSjoerg     // Read records don't currently have sequences, but it can be easily
7006f32e7eSjoerg     // added. Note that implicit Reads (from ReadVariant) may have a Sequence
7106f32e7eSjoerg     // (but no record).
7206f32e7eSjoerg     IsSequence = Def->isSubClassOf("WriteSequence");
7306f32e7eSjoerg   }
7406f32e7eSjoerg 
CodeGenSchedRWCodeGenSchedRW7506f32e7eSjoerg   CodeGenSchedRW(unsigned Idx, bool Read, ArrayRef<unsigned> Seq,
7606f32e7eSjoerg                  const std::string &Name)
7706f32e7eSjoerg       : Index(Idx), Name(Name), TheDef(nullptr), IsRead(Read), IsAlias(false),
7806f32e7eSjoerg         HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) {
7906f32e7eSjoerg     assert(Sequence.size() > 1 && "implied sequence needs >1 RWs");
8006f32e7eSjoerg   }
8106f32e7eSjoerg 
isValidCodeGenSchedRW8206f32e7eSjoerg   bool isValid() const {
8306f32e7eSjoerg     assert((!HasVariants || TheDef) && "Variant write needs record def");
8406f32e7eSjoerg     assert((!IsVariadic || HasVariants) && "Variadic write needs variants");
8506f32e7eSjoerg     assert((!IsSequence || !HasVariants) && "Sequence can't have variant");
8606f32e7eSjoerg     assert((!IsSequence || !Sequence.empty()) && "Sequence should be nonempty");
8706f32e7eSjoerg     assert((!IsAlias || Aliases.empty()) && "Alias cannot have aliases");
8806f32e7eSjoerg     return TheDef || !Sequence.empty();
8906f32e7eSjoerg   }
9006f32e7eSjoerg 
9106f32e7eSjoerg #ifndef NDEBUG
9206f32e7eSjoerg   void dump() const;
9306f32e7eSjoerg #endif
9406f32e7eSjoerg };
9506f32e7eSjoerg 
9606f32e7eSjoerg /// Represent a transition between SchedClasses induced by SchedVariant.
9706f32e7eSjoerg struct CodeGenSchedTransition {
9806f32e7eSjoerg   unsigned ToClassIdx;
99*da58b97aSjoerg   unsigned ProcIndex;
10006f32e7eSjoerg   RecVec PredTerm;
10106f32e7eSjoerg };
10206f32e7eSjoerg 
10306f32e7eSjoerg /// Scheduling class.
10406f32e7eSjoerg ///
10506f32e7eSjoerg /// Each instruction description will be mapped to a scheduling class. There are
10606f32e7eSjoerg /// four types of classes:
10706f32e7eSjoerg ///
10806f32e7eSjoerg /// 1) An explicitly defined itinerary class with ItinClassDef set.
10906f32e7eSjoerg /// Writes and ReadDefs are empty. ProcIndices contains 0 for any processor.
11006f32e7eSjoerg ///
11106f32e7eSjoerg /// 2) An implied class with a list of SchedWrites and SchedReads that are
11206f32e7eSjoerg /// defined in an instruction definition and which are common across all
11306f32e7eSjoerg /// subtargets. ProcIndices contains 0 for any processor.
11406f32e7eSjoerg ///
11506f32e7eSjoerg /// 3) An implied class with a list of InstRW records that map instructions to
11606f32e7eSjoerg /// SchedWrites and SchedReads per-processor. InstrClassMap should map the same
11706f32e7eSjoerg /// instructions to this class. ProcIndices contains all the processors that
11806f32e7eSjoerg /// provided InstrRW records for this class. ItinClassDef or Writes/Reads may
11906f32e7eSjoerg /// still be defined for processors with no InstRW entry.
12006f32e7eSjoerg ///
12106f32e7eSjoerg /// 4) An inferred class represents a variant of another class that may be
12206f32e7eSjoerg /// resolved at runtime. ProcIndices contains the set of processors that may
12306f32e7eSjoerg /// require the class. ProcIndices are propagated through SchedClasses as
12406f32e7eSjoerg /// variants are expanded. Multiple SchedClasses may be inferred from an
12506f32e7eSjoerg /// itinerary class. Each inherits the processor index from the ItinRW record
12606f32e7eSjoerg /// that mapped the itinerary class to the variant Writes or Reads.
12706f32e7eSjoerg struct CodeGenSchedClass {
12806f32e7eSjoerg   unsigned Index;
12906f32e7eSjoerg   std::string Name;
13006f32e7eSjoerg   Record *ItinClassDef;
13106f32e7eSjoerg 
13206f32e7eSjoerg   IdxVec Writes;
13306f32e7eSjoerg   IdxVec Reads;
13406f32e7eSjoerg   // Sorted list of ProcIdx, where ProcIdx==0 implies any processor.
13506f32e7eSjoerg   IdxVec ProcIndices;
13606f32e7eSjoerg 
13706f32e7eSjoerg   std::vector<CodeGenSchedTransition> Transitions;
13806f32e7eSjoerg 
13906f32e7eSjoerg   // InstRW records associated with this class. These records may refer to an
14006f32e7eSjoerg   // Instruction no longer mapped to this class by InstrClassMap. These
14106f32e7eSjoerg   // Instructions should be ignored by this class because they have been split
14206f32e7eSjoerg   // off to join another inferred class.
14306f32e7eSjoerg   RecVec InstRWs;
144*da58b97aSjoerg   // InstRWs processor indices. Filled in inferFromInstRWs
145*da58b97aSjoerg   DenseSet<unsigned> InstRWProcIndices;
14606f32e7eSjoerg 
CodeGenSchedClassCodeGenSchedClass14706f32e7eSjoerg   CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef)
14806f32e7eSjoerg     : Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {}
14906f32e7eSjoerg 
isKeyEqualCodeGenSchedClass15006f32e7eSjoerg   bool isKeyEqual(Record *IC, ArrayRef<unsigned> W,
15106f32e7eSjoerg                   ArrayRef<unsigned> R) const {
15206f32e7eSjoerg     return ItinClassDef == IC && makeArrayRef(Writes) == W &&
15306f32e7eSjoerg            makeArrayRef(Reads) == R;
15406f32e7eSjoerg   }
15506f32e7eSjoerg 
15606f32e7eSjoerg   // Is this class generated from a variants if existing classes? Instructions
15706f32e7eSjoerg   // are never mapped directly to inferred scheduling classes.
isInferredCodeGenSchedClass15806f32e7eSjoerg   bool isInferred() const { return !ItinClassDef; }
15906f32e7eSjoerg 
16006f32e7eSjoerg #ifndef NDEBUG
16106f32e7eSjoerg   void dump(const CodeGenSchedModels *SchedModels) const;
16206f32e7eSjoerg #endif
16306f32e7eSjoerg };
16406f32e7eSjoerg 
16506f32e7eSjoerg /// Represent the cost of allocating a register of register class RCDef.
16606f32e7eSjoerg ///
16706f32e7eSjoerg /// The cost of allocating a register is equivalent to the number of physical
16806f32e7eSjoerg /// registers used by the register renamer. Register costs are defined at
16906f32e7eSjoerg /// register class granularity.
17006f32e7eSjoerg struct CodeGenRegisterCost {
17106f32e7eSjoerg   Record *RCDef;
17206f32e7eSjoerg   unsigned Cost;
17306f32e7eSjoerg   bool AllowMoveElimination;
17406f32e7eSjoerg   CodeGenRegisterCost(Record *RC, unsigned RegisterCost, bool AllowMoveElim = false)
RCDefCodeGenRegisterCost17506f32e7eSjoerg       : RCDef(RC), Cost(RegisterCost), AllowMoveElimination(AllowMoveElim) {}
17606f32e7eSjoerg   CodeGenRegisterCost(const CodeGenRegisterCost &) = default;
17706f32e7eSjoerg   CodeGenRegisterCost &operator=(const CodeGenRegisterCost &) = delete;
17806f32e7eSjoerg };
17906f32e7eSjoerg 
18006f32e7eSjoerg /// A processor register file.
18106f32e7eSjoerg ///
18206f32e7eSjoerg /// This class describes a processor register file. Register file information is
18306f32e7eSjoerg /// currently consumed by external tools like llvm-mca to predict dispatch
18406f32e7eSjoerg /// stalls due to register pressure.
18506f32e7eSjoerg struct CodeGenRegisterFile {
18606f32e7eSjoerg   std::string Name;
18706f32e7eSjoerg   Record *RegisterFileDef;
18806f32e7eSjoerg   unsigned MaxMovesEliminatedPerCycle;
18906f32e7eSjoerg   bool AllowZeroMoveEliminationOnly;
19006f32e7eSjoerg 
19106f32e7eSjoerg   unsigned NumPhysRegs;
19206f32e7eSjoerg   std::vector<CodeGenRegisterCost> Costs;
19306f32e7eSjoerg 
19406f32e7eSjoerg   CodeGenRegisterFile(StringRef name, Record *def, unsigned MaxMoveElimPerCy = 0,
19506f32e7eSjoerg                       bool AllowZeroMoveElimOnly = false)
NameCodeGenRegisterFile19606f32e7eSjoerg       : Name(name), RegisterFileDef(def),
19706f32e7eSjoerg         MaxMovesEliminatedPerCycle(MaxMoveElimPerCy),
19806f32e7eSjoerg         AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly),
19906f32e7eSjoerg         NumPhysRegs(0) {}
20006f32e7eSjoerg 
hasDefaultCostsCodeGenRegisterFile20106f32e7eSjoerg   bool hasDefaultCosts() const { return Costs.empty(); }
20206f32e7eSjoerg };
20306f32e7eSjoerg 
20406f32e7eSjoerg // Processor model.
20506f32e7eSjoerg //
20606f32e7eSjoerg // ModelName is a unique name used to name an instantiation of MCSchedModel.
20706f32e7eSjoerg //
20806f32e7eSjoerg // ModelDef is NULL for inferred Models. This happens when a processor defines
20906f32e7eSjoerg // an itinerary but no machine model. If the processor defines neither a machine
21006f32e7eSjoerg // model nor itinerary, then ModelDef remains pointing to NoModel. NoModel has
21106f32e7eSjoerg // the special "NoModel" field set to true.
21206f32e7eSjoerg //
21306f32e7eSjoerg // ItinsDef always points to a valid record definition, but may point to the
21406f32e7eSjoerg // default NoItineraries. NoItineraries has an empty list of InstrItinData
21506f32e7eSjoerg // records.
21606f32e7eSjoerg //
21706f32e7eSjoerg // ItinDefList orders this processor's InstrItinData records by SchedClass idx.
21806f32e7eSjoerg struct CodeGenProcModel {
21906f32e7eSjoerg   unsigned Index;
22006f32e7eSjoerg   std::string ModelName;
22106f32e7eSjoerg   Record *ModelDef;
22206f32e7eSjoerg   Record *ItinsDef;
22306f32e7eSjoerg 
22406f32e7eSjoerg   // Derived members...
22506f32e7eSjoerg 
22606f32e7eSjoerg   // Array of InstrItinData records indexed by a CodeGenSchedClass index.
22706f32e7eSjoerg   // This list is empty if the Processor has no value for Itineraries.
22806f32e7eSjoerg   // Initialized by collectProcItins().
22906f32e7eSjoerg   RecVec ItinDefList;
23006f32e7eSjoerg 
23106f32e7eSjoerg   // Map itinerary classes to per-operand resources.
23206f32e7eSjoerg   // This list is empty if no ItinRW refers to this Processor.
23306f32e7eSjoerg   RecVec ItinRWDefs;
23406f32e7eSjoerg 
23506f32e7eSjoerg   // List of unsupported feature.
23606f32e7eSjoerg   // This list is empty if the Processor has no UnsupportedFeatures.
23706f32e7eSjoerg   RecVec UnsupportedFeaturesDefs;
23806f32e7eSjoerg 
23906f32e7eSjoerg   // All read/write resources associated with this processor.
24006f32e7eSjoerg   RecVec WriteResDefs;
24106f32e7eSjoerg   RecVec ReadAdvanceDefs;
24206f32e7eSjoerg 
24306f32e7eSjoerg   // Per-operand machine model resources associated with this processor.
24406f32e7eSjoerg   RecVec ProcResourceDefs;
24506f32e7eSjoerg 
24606f32e7eSjoerg   // List of Register Files.
24706f32e7eSjoerg   std::vector<CodeGenRegisterFile> RegisterFiles;
24806f32e7eSjoerg 
24906f32e7eSjoerg   // Optional Retire Control Unit definition.
25006f32e7eSjoerg   Record *RetireControlUnit;
25106f32e7eSjoerg 
25206f32e7eSjoerg   // Load/Store queue descriptors.
25306f32e7eSjoerg   Record *LoadQueue;
25406f32e7eSjoerg   Record *StoreQueue;
25506f32e7eSjoerg 
CodeGenProcModelCodeGenProcModel25606f32e7eSjoerg   CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef,
25706f32e7eSjoerg                    Record *IDef) :
25806f32e7eSjoerg     Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef),
25906f32e7eSjoerg     RetireControlUnit(nullptr), LoadQueue(nullptr), StoreQueue(nullptr) {}
26006f32e7eSjoerg 
hasItinerariesCodeGenProcModel26106f32e7eSjoerg   bool hasItineraries() const {
26206f32e7eSjoerg     return !ItinsDef->getValueAsListOfDefs("IID").empty();
26306f32e7eSjoerg   }
26406f32e7eSjoerg 
hasInstrSchedModelCodeGenProcModel26506f32e7eSjoerg   bool hasInstrSchedModel() const {
26606f32e7eSjoerg     return !WriteResDefs.empty() || !ItinRWDefs.empty();
26706f32e7eSjoerg   }
26806f32e7eSjoerg 
hasExtraProcessorInfoCodeGenProcModel26906f32e7eSjoerg   bool hasExtraProcessorInfo() const {
27006f32e7eSjoerg     return RetireControlUnit || LoadQueue || StoreQueue ||
27106f32e7eSjoerg            !RegisterFiles.empty();
27206f32e7eSjoerg   }
27306f32e7eSjoerg 
27406f32e7eSjoerg   unsigned getProcResourceIdx(Record *PRDef) const;
27506f32e7eSjoerg 
27606f32e7eSjoerg   bool isUnsupported(const CodeGenInstruction &Inst) const;
27706f32e7eSjoerg 
27806f32e7eSjoerg #ifndef NDEBUG
27906f32e7eSjoerg   void dump() const;
28006f32e7eSjoerg #endif
28106f32e7eSjoerg };
28206f32e7eSjoerg 
28306f32e7eSjoerg /// Used to correlate instructions to MCInstPredicates specified by
28406f32e7eSjoerg /// InstructionEquivalentClass tablegen definitions.
28506f32e7eSjoerg ///
28606f32e7eSjoerg /// Example: a XOR of a register with self, is a known zero-idiom for most
28706f32e7eSjoerg /// X86 processors.
28806f32e7eSjoerg ///
28906f32e7eSjoerg /// Each processor can use a (potentially different) InstructionEquivalenceClass
29006f32e7eSjoerg ///  definition to classify zero-idioms. That means, XORrr is likely to appear
29106f32e7eSjoerg /// in more than one equivalence class (where each class definition is
29206f32e7eSjoerg /// contributed by a different processor).
29306f32e7eSjoerg ///
29406f32e7eSjoerg /// There is no guarantee that the same MCInstPredicate will be used to describe
29506f32e7eSjoerg /// equivalence classes that identify XORrr as a zero-idiom.
29606f32e7eSjoerg ///
29706f32e7eSjoerg /// To be more specific, the requirements for being a zero-idiom XORrr may be
29806f32e7eSjoerg /// different for different processors.
29906f32e7eSjoerg ///
30006f32e7eSjoerg /// Class PredicateInfo identifies a subset of processors that specify the same
30106f32e7eSjoerg /// requirements (i.e. same MCInstPredicate and OperandMask) for an instruction
30206f32e7eSjoerg /// opcode.
30306f32e7eSjoerg ///
30406f32e7eSjoerg /// Back to the example. Field `ProcModelMask` will have one bit set for every
30506f32e7eSjoerg /// processor model that sees XORrr as a zero-idiom, and that specifies the same
30606f32e7eSjoerg /// set of constraints.
30706f32e7eSjoerg ///
30806f32e7eSjoerg /// By construction, there can be multiple instances of PredicateInfo associated
30906f32e7eSjoerg /// with a same instruction opcode. For example, different processors may define
31006f32e7eSjoerg /// different constraints on the same opcode.
31106f32e7eSjoerg ///
31206f32e7eSjoerg /// Field OperandMask can be used as an extra constraint.
31306f32e7eSjoerg /// It may be used to describe conditions that appy only to a subset of the
31406f32e7eSjoerg /// operands of a machine instruction, and the operands subset may not be the
31506f32e7eSjoerg /// same for all processor models.
31606f32e7eSjoerg struct PredicateInfo {
31706f32e7eSjoerg   llvm::APInt ProcModelMask; // A set of processor model indices.
31806f32e7eSjoerg   llvm::APInt OperandMask;   // An operand mask.
31906f32e7eSjoerg   const Record *Predicate;   // MCInstrPredicate definition.
PredicateInfoPredicateInfo32006f32e7eSjoerg   PredicateInfo(llvm::APInt CpuMask, llvm::APInt Operands, const Record *Pred)
32106f32e7eSjoerg       : ProcModelMask(CpuMask), OperandMask(Operands), Predicate(Pred) {}
32206f32e7eSjoerg 
32306f32e7eSjoerg   bool operator==(const PredicateInfo &Other) const {
32406f32e7eSjoerg     return ProcModelMask == Other.ProcModelMask &&
32506f32e7eSjoerg            OperandMask == Other.OperandMask && Predicate == Other.Predicate;
32606f32e7eSjoerg   }
32706f32e7eSjoerg };
32806f32e7eSjoerg 
32906f32e7eSjoerg /// A collection of PredicateInfo objects.
33006f32e7eSjoerg ///
33106f32e7eSjoerg /// There is at least one OpcodeInfo object for every opcode specified by a
33206f32e7eSjoerg /// TIPredicate definition.
33306f32e7eSjoerg class OpcodeInfo {
33406f32e7eSjoerg   std::vector<PredicateInfo> Predicates;
33506f32e7eSjoerg 
33606f32e7eSjoerg   OpcodeInfo(const OpcodeInfo &Other) = delete;
33706f32e7eSjoerg   OpcodeInfo &operator=(const OpcodeInfo &Other) = delete;
33806f32e7eSjoerg 
33906f32e7eSjoerg public:
34006f32e7eSjoerg   OpcodeInfo() = default;
34106f32e7eSjoerg   OpcodeInfo &operator=(OpcodeInfo &&Other) = default;
34206f32e7eSjoerg   OpcodeInfo(OpcodeInfo &&Other) = default;
34306f32e7eSjoerg 
getPredicates()34406f32e7eSjoerg   ArrayRef<PredicateInfo> getPredicates() const { return Predicates; }
34506f32e7eSjoerg 
34606f32e7eSjoerg   void addPredicateForProcModel(const llvm::APInt &CpuMask,
34706f32e7eSjoerg                                 const llvm::APInt &OperandMask,
34806f32e7eSjoerg                                 const Record *Predicate);
34906f32e7eSjoerg };
35006f32e7eSjoerg 
35106f32e7eSjoerg /// Used to group together tablegen instruction definitions that are subject
35206f32e7eSjoerg /// to a same set of constraints (identified by an instance of OpcodeInfo).
35306f32e7eSjoerg class OpcodeGroup {
35406f32e7eSjoerg   OpcodeInfo Info;
35506f32e7eSjoerg   std::vector<const Record *> Opcodes;
35606f32e7eSjoerg 
35706f32e7eSjoerg   OpcodeGroup(const OpcodeGroup &Other) = delete;
35806f32e7eSjoerg   OpcodeGroup &operator=(const OpcodeGroup &Other) = delete;
35906f32e7eSjoerg 
36006f32e7eSjoerg public:
OpcodeGroup(OpcodeInfo && OpInfo)36106f32e7eSjoerg   OpcodeGroup(OpcodeInfo &&OpInfo) : Info(std::move(OpInfo)) {}
36206f32e7eSjoerg   OpcodeGroup(OpcodeGroup &&Other) = default;
36306f32e7eSjoerg 
addOpcode(const Record * Opcode)36406f32e7eSjoerg   void addOpcode(const Record *Opcode) {
365*da58b97aSjoerg     assert(!llvm::is_contained(Opcodes, Opcode) && "Opcode already in set!");
36606f32e7eSjoerg     Opcodes.push_back(Opcode);
36706f32e7eSjoerg   }
36806f32e7eSjoerg 
getOpcodes()36906f32e7eSjoerg   ArrayRef<const Record *> getOpcodes() const { return Opcodes; }
getOpcodeInfo()37006f32e7eSjoerg   const OpcodeInfo &getOpcodeInfo() const { return Info; }
37106f32e7eSjoerg };
37206f32e7eSjoerg 
37306f32e7eSjoerg /// An STIPredicateFunction descriptor used by tablegen backends to
37406f32e7eSjoerg /// auto-generate the body of a predicate function as a member of tablegen'd
37506f32e7eSjoerg /// class XXXGenSubtargetInfo.
37606f32e7eSjoerg class STIPredicateFunction {
37706f32e7eSjoerg   const Record *FunctionDeclaration;
37806f32e7eSjoerg 
37906f32e7eSjoerg   std::vector<const Record *> Definitions;
38006f32e7eSjoerg   std::vector<OpcodeGroup> Groups;
38106f32e7eSjoerg 
38206f32e7eSjoerg   STIPredicateFunction(const STIPredicateFunction &Other) = delete;
38306f32e7eSjoerg   STIPredicateFunction &operator=(const STIPredicateFunction &Other) = delete;
38406f32e7eSjoerg 
38506f32e7eSjoerg public:
STIPredicateFunction(const Record * Rec)38606f32e7eSjoerg   STIPredicateFunction(const Record *Rec) : FunctionDeclaration(Rec) {}
38706f32e7eSjoerg   STIPredicateFunction(STIPredicateFunction &&Other) = default;
38806f32e7eSjoerg 
isCompatibleWith(const STIPredicateFunction & Other)38906f32e7eSjoerg   bool isCompatibleWith(const STIPredicateFunction &Other) const {
39006f32e7eSjoerg     return FunctionDeclaration == Other.FunctionDeclaration;
39106f32e7eSjoerg   }
39206f32e7eSjoerg 
addDefinition(const Record * Def)39306f32e7eSjoerg   void addDefinition(const Record *Def) { Definitions.push_back(Def); }
addOpcode(const Record * OpcodeRec,OpcodeInfo && Info)39406f32e7eSjoerg   void addOpcode(const Record *OpcodeRec, OpcodeInfo &&Info) {
39506f32e7eSjoerg     if (Groups.empty() ||
39606f32e7eSjoerg         Groups.back().getOpcodeInfo().getPredicates() != Info.getPredicates())
39706f32e7eSjoerg       Groups.emplace_back(std::move(Info));
39806f32e7eSjoerg     Groups.back().addOpcode(OpcodeRec);
39906f32e7eSjoerg   }
40006f32e7eSjoerg 
getName()40106f32e7eSjoerg   StringRef getName() const {
40206f32e7eSjoerg     return FunctionDeclaration->getValueAsString("Name");
40306f32e7eSjoerg   }
getDefaultReturnPredicate()40406f32e7eSjoerg   const Record *getDefaultReturnPredicate() const {
40506f32e7eSjoerg     return FunctionDeclaration->getValueAsDef("DefaultReturnValue");
40606f32e7eSjoerg   }
40706f32e7eSjoerg 
getDeclaration()40806f32e7eSjoerg   const Record *getDeclaration() const { return FunctionDeclaration; }
getDefinitions()40906f32e7eSjoerg   ArrayRef<const Record *> getDefinitions() const { return Definitions; }
getGroups()41006f32e7eSjoerg   ArrayRef<OpcodeGroup> getGroups() const { return Groups; }
41106f32e7eSjoerg };
41206f32e7eSjoerg 
413*da58b97aSjoerg using ProcModelMapTy = DenseMap<const Record *, unsigned>;
414*da58b97aSjoerg 
41506f32e7eSjoerg /// Top level container for machine model data.
41606f32e7eSjoerg class CodeGenSchedModels {
41706f32e7eSjoerg   RecordKeeper &Records;
41806f32e7eSjoerg   const CodeGenTarget &Target;
41906f32e7eSjoerg 
42006f32e7eSjoerg   // Map dag expressions to Instruction lists.
42106f32e7eSjoerg   SetTheory Sets;
42206f32e7eSjoerg 
42306f32e7eSjoerg   // List of unique processor models.
42406f32e7eSjoerg   std::vector<CodeGenProcModel> ProcModels;
42506f32e7eSjoerg 
42606f32e7eSjoerg   // Map Processor's MachineModel or ProcItin to a CodeGenProcModel index.
42706f32e7eSjoerg   ProcModelMapTy ProcModelMap;
42806f32e7eSjoerg 
42906f32e7eSjoerg   // Per-operand SchedReadWrite types.
43006f32e7eSjoerg   std::vector<CodeGenSchedRW> SchedWrites;
43106f32e7eSjoerg   std::vector<CodeGenSchedRW> SchedReads;
43206f32e7eSjoerg 
43306f32e7eSjoerg   // List of unique SchedClasses.
43406f32e7eSjoerg   std::vector<CodeGenSchedClass> SchedClasses;
43506f32e7eSjoerg 
43606f32e7eSjoerg   // Any inferred SchedClass has an index greater than NumInstrSchedClassses.
43706f32e7eSjoerg   unsigned NumInstrSchedClasses;
43806f32e7eSjoerg 
43906f32e7eSjoerg   RecVec ProcResourceDefs;
44006f32e7eSjoerg   RecVec ProcResGroups;
44106f32e7eSjoerg 
44206f32e7eSjoerg   // Map each instruction to its unique SchedClass index considering the
44306f32e7eSjoerg   // combination of it's itinerary class, SchedRW list, and InstRW records.
44406f32e7eSjoerg   using InstClassMapTy = DenseMap<Record*, unsigned>;
44506f32e7eSjoerg   InstClassMapTy InstrClassMap;
44606f32e7eSjoerg 
44706f32e7eSjoerg   std::vector<STIPredicateFunction> STIPredicates;
448*da58b97aSjoerg   std::vector<unsigned> getAllProcIndices() const;
44906f32e7eSjoerg 
45006f32e7eSjoerg public:
45106f32e7eSjoerg   CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT);
45206f32e7eSjoerg 
45306f32e7eSjoerg   // iterator access to the scheduling classes.
45406f32e7eSjoerg   using class_iterator = std::vector<CodeGenSchedClass>::iterator;
45506f32e7eSjoerg   using const_class_iterator = std::vector<CodeGenSchedClass>::const_iterator;
classes_begin()45606f32e7eSjoerg   class_iterator classes_begin() { return SchedClasses.begin(); }
classes_begin()45706f32e7eSjoerg   const_class_iterator classes_begin() const { return SchedClasses.begin(); }
classes_end()45806f32e7eSjoerg   class_iterator classes_end() { return SchedClasses.end(); }
classes_end()45906f32e7eSjoerg   const_class_iterator classes_end() const { return SchedClasses.end(); }
classes()46006f32e7eSjoerg   iterator_range<class_iterator> classes() {
46106f32e7eSjoerg    return make_range(classes_begin(), classes_end());
46206f32e7eSjoerg   }
classes()46306f32e7eSjoerg   iterator_range<const_class_iterator> classes() const {
46406f32e7eSjoerg    return make_range(classes_begin(), classes_end());
46506f32e7eSjoerg   }
explicit_classes()46606f32e7eSjoerg   iterator_range<class_iterator> explicit_classes() {
46706f32e7eSjoerg     return make_range(classes_begin(), classes_begin() + NumInstrSchedClasses);
46806f32e7eSjoerg   }
explicit_classes()46906f32e7eSjoerg   iterator_range<const_class_iterator> explicit_classes() const {
47006f32e7eSjoerg     return make_range(classes_begin(), classes_begin() + NumInstrSchedClasses);
47106f32e7eSjoerg   }
47206f32e7eSjoerg 
getModelOrItinDef(Record * ProcDef)47306f32e7eSjoerg   Record *getModelOrItinDef(Record *ProcDef) const {
47406f32e7eSjoerg     Record *ModelDef = ProcDef->getValueAsDef("SchedModel");
47506f32e7eSjoerg     Record *ItinsDef = ProcDef->getValueAsDef("ProcItin");
47606f32e7eSjoerg     if (!ItinsDef->getValueAsListOfDefs("IID").empty()) {
47706f32e7eSjoerg       assert(ModelDef->getValueAsBit("NoModel")
47806f32e7eSjoerg              && "Itineraries must be defined within SchedMachineModel");
47906f32e7eSjoerg       return ItinsDef;
48006f32e7eSjoerg     }
48106f32e7eSjoerg     return ModelDef;
48206f32e7eSjoerg   }
48306f32e7eSjoerg 
getModelForProc(Record * ProcDef)48406f32e7eSjoerg   const CodeGenProcModel &getModelForProc(Record *ProcDef) const {
48506f32e7eSjoerg     Record *ModelDef = getModelOrItinDef(ProcDef);
48606f32e7eSjoerg     ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
48706f32e7eSjoerg     assert(I != ProcModelMap.end() && "missing machine model");
48806f32e7eSjoerg     return ProcModels[I->second];
48906f32e7eSjoerg   }
49006f32e7eSjoerg 
getProcModel(Record * ModelDef)49106f32e7eSjoerg   CodeGenProcModel &getProcModel(Record *ModelDef) {
49206f32e7eSjoerg     ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
49306f32e7eSjoerg     assert(I != ProcModelMap.end() && "missing machine model");
49406f32e7eSjoerg     return ProcModels[I->second];
49506f32e7eSjoerg   }
getProcModel(Record * ModelDef)49606f32e7eSjoerg   const CodeGenProcModel &getProcModel(Record *ModelDef) const {
49706f32e7eSjoerg     return const_cast<CodeGenSchedModels*>(this)->getProcModel(ModelDef);
49806f32e7eSjoerg   }
49906f32e7eSjoerg 
50006f32e7eSjoerg   // Iterate over the unique processor models.
50106f32e7eSjoerg   using ProcIter = std::vector<CodeGenProcModel>::const_iterator;
procModelBegin()50206f32e7eSjoerg   ProcIter procModelBegin() const { return ProcModels.begin(); }
procModelEnd()50306f32e7eSjoerg   ProcIter procModelEnd() const { return ProcModels.end(); }
procModels()50406f32e7eSjoerg   ArrayRef<CodeGenProcModel> procModels() const { return ProcModels; }
50506f32e7eSjoerg 
50606f32e7eSjoerg   // Return true if any processors have itineraries.
50706f32e7eSjoerg   bool hasItineraries() const;
50806f32e7eSjoerg 
50906f32e7eSjoerg   // Get a SchedWrite from its index.
getSchedWrite(unsigned Idx)51006f32e7eSjoerg   const CodeGenSchedRW &getSchedWrite(unsigned Idx) const {
51106f32e7eSjoerg     assert(Idx < SchedWrites.size() && "bad SchedWrite index");
51206f32e7eSjoerg     assert(SchedWrites[Idx].isValid() && "invalid SchedWrite");
51306f32e7eSjoerg     return SchedWrites[Idx];
51406f32e7eSjoerg   }
51506f32e7eSjoerg   // Get a SchedWrite from its index.
getSchedRead(unsigned Idx)51606f32e7eSjoerg   const CodeGenSchedRW &getSchedRead(unsigned Idx) const {
51706f32e7eSjoerg     assert(Idx < SchedReads.size() && "bad SchedRead index");
51806f32e7eSjoerg     assert(SchedReads[Idx].isValid() && "invalid SchedRead");
51906f32e7eSjoerg     return SchedReads[Idx];
52006f32e7eSjoerg   }
52106f32e7eSjoerg 
getSchedRW(unsigned Idx,bool IsRead)52206f32e7eSjoerg   const CodeGenSchedRW &getSchedRW(unsigned Idx, bool IsRead) const {
52306f32e7eSjoerg     return IsRead ? getSchedRead(Idx) : getSchedWrite(Idx);
52406f32e7eSjoerg   }
getSchedRW(Record * Def)52506f32e7eSjoerg   CodeGenSchedRW &getSchedRW(Record *Def) {
52606f32e7eSjoerg     bool IsRead = Def->isSubClassOf("SchedRead");
52706f32e7eSjoerg     unsigned Idx = getSchedRWIdx(Def, IsRead);
52806f32e7eSjoerg     return const_cast<CodeGenSchedRW&>(
52906f32e7eSjoerg       IsRead ? getSchedRead(Idx) : getSchedWrite(Idx));
53006f32e7eSjoerg   }
getSchedRW(Record * Def)53106f32e7eSjoerg   const CodeGenSchedRW &getSchedRW(Record *Def) const {
53206f32e7eSjoerg     return const_cast<CodeGenSchedModels&>(*this).getSchedRW(Def);
53306f32e7eSjoerg   }
53406f32e7eSjoerg 
53506f32e7eSjoerg   unsigned getSchedRWIdx(const Record *Def, bool IsRead) const;
53606f32e7eSjoerg 
53706f32e7eSjoerg   // Return true if the given write record is referenced by a ReadAdvance.
53806f32e7eSjoerg   bool hasReadOfWrite(Record *WriteDef) const;
53906f32e7eSjoerg 
54006f32e7eSjoerg   // Get a SchedClass from its index.
getSchedClass(unsigned Idx)54106f32e7eSjoerg   CodeGenSchedClass &getSchedClass(unsigned Idx) {
54206f32e7eSjoerg     assert(Idx < SchedClasses.size() && "bad SchedClass index");
54306f32e7eSjoerg     return SchedClasses[Idx];
54406f32e7eSjoerg   }
getSchedClass(unsigned Idx)54506f32e7eSjoerg   const CodeGenSchedClass &getSchedClass(unsigned Idx) const {
54606f32e7eSjoerg     assert(Idx < SchedClasses.size() && "bad SchedClass index");
54706f32e7eSjoerg     return SchedClasses[Idx];
54806f32e7eSjoerg   }
54906f32e7eSjoerg 
55006f32e7eSjoerg   // Get the SchedClass index for an instruction. Instructions with no
55106f32e7eSjoerg   // itinerary, no SchedReadWrites, and no InstrReadWrites references return 0
55206f32e7eSjoerg   // for NoItinerary.
55306f32e7eSjoerg   unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const;
55406f32e7eSjoerg 
55506f32e7eSjoerg   using SchedClassIter = std::vector<CodeGenSchedClass>::const_iterator;
schedClassBegin()55606f32e7eSjoerg   SchedClassIter schedClassBegin() const { return SchedClasses.begin(); }
schedClassEnd()55706f32e7eSjoerg   SchedClassIter schedClassEnd() const { return SchedClasses.end(); }
schedClasses()55806f32e7eSjoerg   ArrayRef<CodeGenSchedClass> schedClasses() const { return SchedClasses; }
55906f32e7eSjoerg 
numInstrSchedClasses()56006f32e7eSjoerg   unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; }
56106f32e7eSjoerg 
56206f32e7eSjoerg   void findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const;
56306f32e7eSjoerg   void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const;
56406f32e7eSjoerg   void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const;
56506f32e7eSjoerg   void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
56606f32e7eSjoerg                           const CodeGenProcModel &ProcModel) const;
56706f32e7eSjoerg 
56806f32e7eSjoerg   unsigned addSchedClass(Record *ItinDef, ArrayRef<unsigned> OperWrites,
56906f32e7eSjoerg                          ArrayRef<unsigned> OperReads,
57006f32e7eSjoerg                          ArrayRef<unsigned> ProcIndices);
57106f32e7eSjoerg 
57206f32e7eSjoerg   unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead);
57306f32e7eSjoerg 
57406f32e7eSjoerg   Record *findProcResUnits(Record *ProcResKind, const CodeGenProcModel &PM,
57506f32e7eSjoerg                            ArrayRef<SMLoc> Loc) const;
57606f32e7eSjoerg 
getSTIPredicates()57706f32e7eSjoerg   ArrayRef<STIPredicateFunction> getSTIPredicates() const {
57806f32e7eSjoerg     return STIPredicates;
57906f32e7eSjoerg   }
58006f32e7eSjoerg private:
58106f32e7eSjoerg   void collectProcModels();
58206f32e7eSjoerg 
58306f32e7eSjoerg   // Initialize a new processor model if it is unique.
58406f32e7eSjoerg   void addProcModel(Record *ProcDef);
58506f32e7eSjoerg 
58606f32e7eSjoerg   void collectSchedRW();
58706f32e7eSjoerg 
58806f32e7eSjoerg   std::string genRWName(ArrayRef<unsigned> Seq, bool IsRead);
58906f32e7eSjoerg   unsigned findRWForSequence(ArrayRef<unsigned> Seq, bool IsRead);
59006f32e7eSjoerg 
59106f32e7eSjoerg   void collectSchedClasses();
59206f32e7eSjoerg 
59306f32e7eSjoerg   void collectRetireControlUnits();
59406f32e7eSjoerg 
59506f32e7eSjoerg   void collectRegisterFiles();
59606f32e7eSjoerg 
59706f32e7eSjoerg   void collectOptionalProcessorInfo();
59806f32e7eSjoerg 
59906f32e7eSjoerg   std::string createSchedClassName(Record *ItinClassDef,
60006f32e7eSjoerg                                    ArrayRef<unsigned> OperWrites,
60106f32e7eSjoerg                                    ArrayRef<unsigned> OperReads);
60206f32e7eSjoerg   std::string createSchedClassName(const RecVec &InstDefs);
60306f32e7eSjoerg   void createInstRWClass(Record *InstRWDef);
60406f32e7eSjoerg 
60506f32e7eSjoerg   void collectProcItins();
60606f32e7eSjoerg 
60706f32e7eSjoerg   void collectProcItinRW();
60806f32e7eSjoerg 
60906f32e7eSjoerg   void collectProcUnsupportedFeatures();
61006f32e7eSjoerg 
61106f32e7eSjoerg   void inferSchedClasses();
61206f32e7eSjoerg 
61306f32e7eSjoerg   void checkMCInstPredicates() const;
61406f32e7eSjoerg 
61506f32e7eSjoerg   void checkSTIPredicates() const;
61606f32e7eSjoerg 
61706f32e7eSjoerg   void collectSTIPredicates();
61806f32e7eSjoerg 
61906f32e7eSjoerg   void collectLoadStoreQueueInfo();
62006f32e7eSjoerg 
62106f32e7eSjoerg   void checkCompleteness();
62206f32e7eSjoerg 
62306f32e7eSjoerg   void inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads,
62406f32e7eSjoerg                    unsigned FromClassIdx, ArrayRef<unsigned> ProcIndices);
62506f32e7eSjoerg   void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx);
62606f32e7eSjoerg   void inferFromInstRWs(unsigned SCIdx);
62706f32e7eSjoerg 
62806f32e7eSjoerg   bool hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM);
62906f32e7eSjoerg   void verifyProcResourceGroups(CodeGenProcModel &PM);
63006f32e7eSjoerg 
63106f32e7eSjoerg   void collectProcResources();
63206f32e7eSjoerg 
63306f32e7eSjoerg   void collectItinProcResources(Record *ItinClassDef);
63406f32e7eSjoerg 
63506f32e7eSjoerg   void collectRWResources(unsigned RWIdx, bool IsRead,
63606f32e7eSjoerg                           ArrayRef<unsigned> ProcIndices);
63706f32e7eSjoerg 
63806f32e7eSjoerg   void collectRWResources(ArrayRef<unsigned> Writes, ArrayRef<unsigned> Reads,
63906f32e7eSjoerg                           ArrayRef<unsigned> ProcIndices);
64006f32e7eSjoerg 
64106f32e7eSjoerg   void addProcResource(Record *ProcResourceKind, CodeGenProcModel &PM,
64206f32e7eSjoerg                        ArrayRef<SMLoc> Loc);
64306f32e7eSjoerg 
64406f32e7eSjoerg   void addWriteRes(Record *ProcWriteResDef, unsigned PIdx);
64506f32e7eSjoerg 
64606f32e7eSjoerg   void addReadAdvance(Record *ProcReadAdvanceDef, unsigned PIdx);
64706f32e7eSjoerg };
64806f32e7eSjoerg 
64906f32e7eSjoerg } // namespace llvm
65006f32e7eSjoerg 
65106f32e7eSjoerg #endif
652