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