| //===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file defines structures to encapsulate the machine model as described in | 
 | // the target description. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "CodeGenSchedule.h" | 
 | #include "CodeGenInstruction.h" | 
 | #include "CodeGenTarget.h" | 
 | #include "llvm/ADT/MapVector.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/ADT/SmallPtrSet.h" | 
 | #include "llvm/ADT/SmallVector.h" | 
 | #include "llvm/Support/Casting.h" | 
 | #include "llvm/Support/Debug.h" | 
 | #include "llvm/Support/Regex.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | #include "llvm/TableGen/Error.h" | 
 | #include <algorithm> | 
 | #include <iterator> | 
 | #include <utility> | 
 |  | 
 | using namespace llvm; | 
 |  | 
 | #define DEBUG_TYPE "subtarget-emitter" | 
 |  | 
 | #ifndef NDEBUG | 
 | static void dumpIdxVec(ArrayRef<unsigned> V) { | 
 |   for (unsigned Idx : V) | 
 |     dbgs() << Idx << ", "; | 
 | } | 
 | #endif | 
 |  | 
 | namespace { | 
 |  | 
 | // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. | 
 | struct InstrsOp : public SetTheory::Operator { | 
 |   void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, | 
 |              ArrayRef<SMLoc> Loc) override { | 
 |     ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); | 
 |   } | 
 | }; | 
 |  | 
 | // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. | 
 | struct InstRegexOp : public SetTheory::Operator { | 
 |   const CodeGenTarget &Target; | 
 |   InstRegexOp(const CodeGenTarget &t): Target(t) {} | 
 |  | 
 |   /// Remove any text inside of parentheses from S. | 
 |   static std::string removeParens(llvm::StringRef S) { | 
 |     std::string Result; | 
 |     unsigned Paren = 0; | 
 |     // NB: We don't care about escaped parens here. | 
 |     for (char C : S) { | 
 |       switch (C) { | 
 |       case '(': | 
 |         ++Paren; | 
 |         break; | 
 |       case ')': | 
 |         --Paren; | 
 |         break; | 
 |       default: | 
 |         if (Paren == 0) | 
 |           Result += C; | 
 |       } | 
 |     } | 
 |     return Result; | 
 |   } | 
 |  | 
 |   void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, | 
 |              ArrayRef<SMLoc> Loc) override { | 
 |     ArrayRef<const CodeGenInstruction *> Instructions = | 
 |         Target.getInstructionsByEnumValue(); | 
 |  | 
 |     unsigned NumGeneric = Target.getNumFixedInstructions(); | 
 |     unsigned NumPseudos = Target.getNumPseudoInstructions(); | 
 |     auto Generics = Instructions.slice(0, NumGeneric); | 
 |     auto Pseudos = Instructions.slice(NumGeneric, NumPseudos); | 
 |     auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos); | 
 |  | 
 |     for (Init *Arg : Expr->getArgs()) { | 
 |       StringInit *SI = dyn_cast<StringInit>(Arg); | 
 |       if (!SI) | 
 |         PrintFatalError(Loc, "instregex requires pattern string: " + | 
 |                                  Expr->getAsString()); | 
 |       StringRef Original = SI->getValue(); | 
 |  | 
 |       // Extract a prefix that we can binary search on. | 
 |       static const char RegexMetachars[] = "()^$|*+?.[]\\{}"; | 
 |       auto FirstMeta = Original.find_first_of(RegexMetachars); | 
 |  | 
 |       // Look for top-level | or ?. We cannot optimize them to binary search. | 
 |       if (removeParens(Original).find_first_of("|?") != std::string::npos) | 
 |         FirstMeta = 0; | 
 |  | 
 |       Optional<Regex> Regexpr = None; | 
 |       StringRef Prefix = Original.substr(0, FirstMeta); | 
 |       StringRef PatStr = Original.substr(FirstMeta); | 
 |       if (!PatStr.empty()) { | 
 |         // For the rest use a python-style prefix match. | 
 |         std::string pat = std::string(PatStr); | 
 |         if (pat[0] != '^') { | 
 |           pat.insert(0, "^("); | 
 |           pat.insert(pat.end(), ')'); | 
 |         } | 
 |         Regexpr = Regex(pat); | 
 |       } | 
 |  | 
 |       int NumMatches = 0; | 
 |  | 
 |       // The generic opcodes are unsorted, handle them manually. | 
 |       for (auto *Inst : Generics) { | 
 |         StringRef InstName = Inst->TheDef->getName(); | 
 |         if (InstName.startswith(Prefix) && | 
 |             (!Regexpr || Regexpr->match(InstName.substr(Prefix.size())))) { | 
 |           Elts.insert(Inst->TheDef); | 
 |           NumMatches++; | 
 |         } | 
 |       } | 
 |  | 
 |       // Target instructions are split into two ranges: pseudo instructions | 
 |       // first, than non-pseudos. Each range is in lexicographical order | 
 |       // sorted by name. Find the sub-ranges that start with our prefix. | 
 |       struct Comp { | 
 |         bool operator()(const CodeGenInstruction *LHS, StringRef RHS) { | 
 |           return LHS->TheDef->getName() < RHS; | 
 |         } | 
 |         bool operator()(StringRef LHS, const CodeGenInstruction *RHS) { | 
 |           return LHS < RHS->TheDef->getName() && | 
 |                  !RHS->TheDef->getName().startswith(LHS); | 
 |         } | 
 |       }; | 
 |       auto Range1 = | 
 |           std::equal_range(Pseudos.begin(), Pseudos.end(), Prefix, Comp()); | 
 |       auto Range2 = std::equal_range(NonPseudos.begin(), NonPseudos.end(), | 
 |                                      Prefix, Comp()); | 
 |  | 
 |       // For these ranges we know that instruction names start with the prefix. | 
 |       // Check if there's a regex that needs to be checked. | 
 |       const auto HandleNonGeneric = [&](const CodeGenInstruction *Inst) { | 
 |         StringRef InstName = Inst->TheDef->getName(); | 
 |         if (!Regexpr || Regexpr->match(InstName.substr(Prefix.size()))) { | 
 |           Elts.insert(Inst->TheDef); | 
 |           NumMatches++; | 
 |         } | 
 |       }; | 
 |       std::for_each(Range1.first, Range1.second, HandleNonGeneric); | 
 |       std::for_each(Range2.first, Range2.second, HandleNonGeneric); | 
 |  | 
 |       if (0 == NumMatches) | 
 |         PrintFatalError(Loc, "instregex has no matches: " + Original); | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | } // end anonymous namespace | 
 |  | 
 | /// CodeGenModels ctor interprets machine model records and populates maps. | 
 | CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, | 
 |                                        const CodeGenTarget &TGT): | 
 |   Records(RK), Target(TGT) { | 
 |  | 
 |   Sets.addFieldExpander("InstRW", "Instrs"); | 
 |  | 
 |   // Allow Set evaluation to recognize the dags used in InstRW records: | 
 |   // (instrs Op1, Op1...) | 
 |   Sets.addOperator("instrs", std::make_unique<InstrsOp>()); | 
 |   Sets.addOperator("instregex", std::make_unique<InstRegexOp>(Target)); | 
 |  | 
 |   // Instantiate a CodeGenProcModel for each SchedMachineModel with the values | 
 |   // that are explicitly referenced in tablegen records. Resources associated | 
 |   // with each processor will be derived later. Populate ProcModelMap with the | 
 |   // CodeGenProcModel instances. | 
 |   collectProcModels(); | 
 |  | 
 |   // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly | 
 |   // defined, and populate SchedReads and SchedWrites vectors. Implicit | 
 |   // SchedReadWrites that represent sequences derived from expanded variant will | 
 |   // be inferred later. | 
 |   collectSchedRW(); | 
 |  | 
 |   // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly | 
 |   // required by an instruction definition, and populate SchedClassIdxMap. Set | 
 |   // NumItineraryClasses to the number of explicit itinerary classes referenced | 
 |   // by instructions. Set NumInstrSchedClasses to the number of itinerary | 
 |   // classes plus any classes implied by instructions that derive from class | 
 |   // Sched and provide SchedRW list. This does not infer any new classes from | 
 |   // SchedVariant. | 
 |   collectSchedClasses(); | 
 |  | 
 |   // Find instruction itineraries for each processor. Sort and populate | 
 |   // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires | 
 |   // all itinerary classes to be discovered. | 
 |   collectProcItins(); | 
 |  | 
 |   // Find ItinRW records for each processor and itinerary class. | 
 |   // (For per-operand resources mapped to itinerary classes). | 
 |   collectProcItinRW(); | 
 |  | 
 |   // Find UnsupportedFeatures records for each processor. | 
 |   // (For per-operand resources mapped to itinerary classes). | 
 |   collectProcUnsupportedFeatures(); | 
 |  | 
 |   // Infer new SchedClasses from SchedVariant. | 
 |   inferSchedClasses(); | 
 |  | 
 |   // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and | 
 |   // ProcResourceDefs. | 
 |   LLVM_DEBUG( | 
 |       dbgs() << "\n+++ RESOURCE DEFINITIONS (collectProcResources) +++\n"); | 
 |   collectProcResources(); | 
 |  | 
 |   // Collect optional processor description. | 
 |   collectOptionalProcessorInfo(); | 
 |  | 
 |   // Check MCInstPredicate definitions. | 
 |   checkMCInstPredicates(); | 
 |  | 
 |   // Check STIPredicate definitions. | 
 |   checkSTIPredicates(); | 
 |  | 
 |   // Find STIPredicate definitions for each processor model, and construct | 
 |   // STIPredicateFunction objects. | 
 |   collectSTIPredicates(); | 
 |  | 
 |   checkCompleteness(); | 
 | } | 
 |  | 
 | void CodeGenSchedModels::checkSTIPredicates() const { | 
 |   DenseMap<StringRef, const Record *> Declarations; | 
 |  | 
 |   // There cannot be multiple declarations with the same name. | 
 |   const RecVec Decls = Records.getAllDerivedDefinitions("STIPredicateDecl"); | 
 |   for (const Record *R : Decls) { | 
 |     StringRef Name = R->getValueAsString("Name"); | 
 |     const auto It = Declarations.find(Name); | 
 |     if (It == Declarations.end()) { | 
 |       Declarations[Name] = R; | 
 |       continue; | 
 |     } | 
 |  | 
 |     PrintError(R->getLoc(), "STIPredicate " + Name + " multiply declared."); | 
 |     PrintFatalNote(It->second->getLoc(), "Previous declaration was here."); | 
 |   } | 
 |  | 
 |   // Disallow InstructionEquivalenceClasses with an empty instruction list. | 
 |   const RecVec Defs = | 
 |       Records.getAllDerivedDefinitions("InstructionEquivalenceClass"); | 
 |   for (const Record *R : Defs) { | 
 |     RecVec Opcodes = R->getValueAsListOfDefs("Opcodes"); | 
 |     if (Opcodes.empty()) { | 
 |       PrintFatalError(R->getLoc(), "Invalid InstructionEquivalenceClass " | 
 |                                    "defined with an empty opcode list."); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Used by function `processSTIPredicate` to construct a mask of machine | 
 | // instruction operands. | 
 | static APInt constructOperandMask(ArrayRef<int64_t> Indices) { | 
 |   APInt OperandMask; | 
 |   if (Indices.empty()) | 
 |     return OperandMask; | 
 |  | 
 |   int64_t MaxIndex = *std::max_element(Indices.begin(), Indices.end()); | 
 |   assert(MaxIndex >= 0 && "Invalid negative indices in input!"); | 
 |   OperandMask = OperandMask.zext(MaxIndex + 1); | 
 |   for (const int64_t Index : Indices) { | 
 |     assert(Index >= 0 && "Invalid negative indices!"); | 
 |     OperandMask.setBit(Index); | 
 |   } | 
 |  | 
 |   return OperandMask; | 
 | } | 
 |  | 
 | static void | 
 | processSTIPredicate(STIPredicateFunction &Fn, | 
 |                     const ProcModelMapTy &ProcModelMap) { | 
 |   DenseMap<const Record *, unsigned> Opcode2Index; | 
 |   using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>; | 
 |   std::vector<OpcodeMapPair> OpcodeMappings; | 
 |   std::vector<std::pair<APInt, APInt>> OpcodeMasks; | 
 |  | 
 |   DenseMap<const Record *, unsigned> Predicate2Index; | 
 |   unsigned NumUniquePredicates = 0; | 
 |  | 
 |   // Number unique predicates and opcodes used by InstructionEquivalenceClass | 
 |   // definitions. Each unique opcode will be associated with an OpcodeInfo | 
 |   // object. | 
 |   for (const Record *Def : Fn.getDefinitions()) { | 
 |     RecVec Classes = Def->getValueAsListOfDefs("Classes"); | 
 |     for (const Record *EC : Classes) { | 
 |       const Record *Pred = EC->getValueAsDef("Predicate"); | 
 |       if (Predicate2Index.find(Pred) == Predicate2Index.end()) | 
 |         Predicate2Index[Pred] = NumUniquePredicates++; | 
 |  | 
 |       RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes"); | 
 |       for (const Record *Opcode : Opcodes) { | 
 |         if (Opcode2Index.find(Opcode) == Opcode2Index.end()) { | 
 |           Opcode2Index[Opcode] = OpcodeMappings.size(); | 
 |           OpcodeMappings.emplace_back(Opcode, OpcodeInfo()); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Initialize vector `OpcodeMasks` with default values.  We want to keep track | 
 |   // of which processors "use" which opcodes.  We also want to be able to | 
 |   // identify predicates that are used by different processors for a same | 
 |   // opcode. | 
 |   // This information is used later on by this algorithm to sort OpcodeMapping | 
 |   // elements based on their processor and predicate sets. | 
 |   OpcodeMasks.resize(OpcodeMappings.size()); | 
 |   APInt DefaultProcMask(ProcModelMap.size(), 0); | 
 |   APInt DefaultPredMask(NumUniquePredicates, 0); | 
 |   for (std::pair<APInt, APInt> &MaskPair : OpcodeMasks) | 
 |     MaskPair = std::make_pair(DefaultProcMask, DefaultPredMask); | 
 |  | 
 |   // Construct a OpcodeInfo object for every unique opcode declared by an | 
 |   // InstructionEquivalenceClass definition. | 
 |   for (const Record *Def : Fn.getDefinitions()) { | 
 |     RecVec Classes = Def->getValueAsListOfDefs("Classes"); | 
 |     const Record *SchedModel = Def->getValueAsDef("SchedModel"); | 
 |     unsigned ProcIndex = ProcModelMap.find(SchedModel)->second; | 
 |     APInt ProcMask(ProcModelMap.size(), 0); | 
 |     ProcMask.setBit(ProcIndex); | 
 |  | 
 |     for (const Record *EC : Classes) { | 
 |       RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes"); | 
 |  | 
 |       std::vector<int64_t> OpIndices = | 
 |           EC->getValueAsListOfInts("OperandIndices"); | 
 |       APInt OperandMask = constructOperandMask(OpIndices); | 
 |  | 
 |       const Record *Pred = EC->getValueAsDef("Predicate"); | 
 |       APInt PredMask(NumUniquePredicates, 0); | 
 |       PredMask.setBit(Predicate2Index[Pred]); | 
 |  | 
 |       for (const Record *Opcode : Opcodes) { | 
 |         unsigned OpcodeIdx = Opcode2Index[Opcode]; | 
 |         if (OpcodeMasks[OpcodeIdx].first[ProcIndex]) { | 
 |           std::string Message = | 
 |               "Opcode " + Opcode->getName().str() + | 
 |               " used by multiple InstructionEquivalenceClass definitions."; | 
 |           PrintFatalError(EC->getLoc(), Message); | 
 |         } | 
 |         OpcodeMasks[OpcodeIdx].first |= ProcMask; | 
 |         OpcodeMasks[OpcodeIdx].second |= PredMask; | 
 |         OpcodeInfo &OI = OpcodeMappings[OpcodeIdx].second; | 
 |  | 
 |         OI.addPredicateForProcModel(ProcMask, OperandMask, Pred); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Sort OpcodeMappings elements based on their CPU and predicate masks. | 
 |   // As a last resort, order elements by opcode identifier. | 
 |   llvm::sort(OpcodeMappings, | 
 |              [&](const OpcodeMapPair &Lhs, const OpcodeMapPair &Rhs) { | 
 |                unsigned LhsIdx = Opcode2Index[Lhs.first]; | 
 |                unsigned RhsIdx = Opcode2Index[Rhs.first]; | 
 |                const std::pair<APInt, APInt> &LhsMasks = OpcodeMasks[LhsIdx]; | 
 |                const std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx]; | 
 |  | 
 |                auto LessThan = [](const APInt &Lhs, const APInt &Rhs) { | 
 |                  unsigned LhsCountPopulation = Lhs.countPopulation(); | 
 |                  unsigned RhsCountPopulation = Rhs.countPopulation(); | 
 |                  return ((LhsCountPopulation < RhsCountPopulation) || | 
 |                          ((LhsCountPopulation == RhsCountPopulation) && | 
 |                           (Lhs.countLeadingZeros() > Rhs.countLeadingZeros()))); | 
 |                }; | 
 |  | 
 |                if (LhsMasks.first != RhsMasks.first) | 
 |                  return LessThan(LhsMasks.first, RhsMasks.first); | 
 |  | 
 |                if (LhsMasks.second != RhsMasks.second) | 
 |                  return LessThan(LhsMasks.second, RhsMasks.second); | 
 |  | 
 |                return LhsIdx < RhsIdx; | 
 |              }); | 
 |  | 
 |   // Now construct opcode groups. Groups are used by the SubtargetEmitter when | 
 |   // expanding the body of a STIPredicate function. In particular, each opcode | 
 |   // group is expanded into a sequence of labels in a switch statement. | 
 |   // It identifies opcodes for which different processors define same predicates | 
 |   // and same opcode masks. | 
 |   for (OpcodeMapPair &Info : OpcodeMappings) | 
 |     Fn.addOpcode(Info.first, std::move(Info.second)); | 
 | } | 
 |  | 
 | void CodeGenSchedModels::collectSTIPredicates() { | 
 |   // Map STIPredicateDecl records to elements of vector | 
 |   // CodeGenSchedModels::STIPredicates. | 
 |   DenseMap<const Record *, unsigned> Decl2Index; | 
 |  | 
 |   RecVec RV = Records.getAllDerivedDefinitions("STIPredicate"); | 
 |   for (const Record *R : RV) { | 
 |     const Record *Decl = R->getValueAsDef("Declaration"); | 
 |  | 
 |     const auto It = Decl2Index.find(Decl); | 
 |     if (It == Decl2Index.end()) { | 
 |       Decl2Index[Decl] = STIPredicates.size(); | 
 |       STIPredicateFunction Predicate(Decl); | 
 |       Predicate.addDefinition(R); | 
 |       STIPredicates.emplace_back(std::move(Predicate)); | 
 |       continue; | 
 |     } | 
 |  | 
 |     STIPredicateFunction &PreviousDef = STIPredicates[It->second]; | 
 |     PreviousDef.addDefinition(R); | 
 |   } | 
 |  | 
 |   for (STIPredicateFunction &Fn : STIPredicates) | 
 |     processSTIPredicate(Fn, ProcModelMap); | 
 | } | 
 |  | 
 | void OpcodeInfo::addPredicateForProcModel(const llvm::APInt &CpuMask, | 
 |                                           const llvm::APInt &OperandMask, | 
 |                                           const Record *Predicate) { | 
 |   auto It = llvm::find_if( | 
 |       Predicates, [&OperandMask, &Predicate](const PredicateInfo &P) { | 
 |         return P.Predicate == Predicate && P.OperandMask == OperandMask; | 
 |       }); | 
 |   if (It == Predicates.end()) { | 
 |     Predicates.emplace_back(CpuMask, OperandMask, Predicate); | 
 |     return; | 
 |   } | 
 |   It->ProcModelMask |= CpuMask; | 
 | } | 
 |  | 
 | void CodeGenSchedModels::checkMCInstPredicates() const { | 
 |   RecVec MCPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); | 
 |   if (MCPredicates.empty()) | 
 |     return; | 
 |  | 
 |   // A target cannot have multiple TIIPredicate definitions with a same name. | 
 |   llvm::StringMap<const Record *> TIIPredicates(MCPredicates.size()); | 
 |   for (const Record *TIIPred : MCPredicates) { | 
 |     StringRef Name = TIIPred->getValueAsString("FunctionName"); | 
 |     StringMap<const Record *>::const_iterator It = TIIPredicates.find(Name); | 
 |     if (It == TIIPredicates.end()) { | 
 |       TIIPredicates[Name] = TIIPred; | 
 |       continue; | 
 |     } | 
 |  | 
 |     PrintError(TIIPred->getLoc(), | 
 |                "TIIPredicate " + Name + " is multiply defined."); | 
 |     PrintFatalNote(It->second->getLoc(), | 
 |                    " Previous definition of " + Name + " was here."); | 
 |   } | 
 | } | 
 |  | 
 | void CodeGenSchedModels::collectRetireControlUnits() { | 
 |   RecVec Units = Records.getAllDerivedDefinitions("RetireControlUnit"); | 
 |  | 
 |   for (Record *RCU : Units) { | 
 |     CodeGenProcModel &PM = getProcModel(RCU->getValueAsDef("SchedModel")); | 
 |     if (PM.RetireControlUnit) { | 
 |       PrintError(RCU->getLoc(), | 
 |                  "Expected a single RetireControlUnit definition"); | 
 |       PrintNote(PM.RetireControlUnit->getLoc(), | 
 |                 "Previous definition of RetireControlUnit was here"); | 
 |     } | 
 |     PM.RetireControlUnit = RCU; | 
 |   } | 
 | } | 
 |  | 
 | void CodeGenSchedModels::collectLoadStoreQueueInfo() { | 
 |   RecVec Queues = Records.getAllDerivedDefinitions("MemoryQueue"); | 
 |  | 
 |   for (Record *Queue : Queues) { | 
 |     CodeGenProcModel &PM = getProcModel(Queue->getValueAsDef("SchedModel")); | 
 |     if (Queue->isSubClassOf("LoadQueue")) { | 
 |       if (PM.LoadQueue) { | 
 |         PrintError(Queue->getLoc(), | 
 |                    "Expected a single LoadQueue definition"); | 
 |         PrintNote(PM.LoadQueue->getLoc(), | 
 |                   "Previous definition of LoadQueue was here"); | 
 |       } | 
 |  | 
 |       PM.LoadQueue = Queue; | 
 |     } | 
 |  | 
 |     if (Queue->isSubClassOf("StoreQueue")) { | 
 |       if (PM.StoreQueue) { | 
 |         PrintError(Queue->getLoc(), | 
 |                    "Expected a single StoreQueue definition"); | 
 |         PrintNote(PM.LoadQueue->getLoc(), | 
 |                   "Previous definition of StoreQueue was here"); | 
 |       } | 
 |  | 
 |       PM.StoreQueue = Queue; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// Collect optional processor information. | 
 | void CodeGenSchedModels::collectOptionalProcessorInfo() { | 
 |   // Find register file definitions for each processor. | 
 |   collectRegisterFiles(); | 
 |  | 
 |   // Collect processor RetireControlUnit descriptors if available. | 
 |   collectRetireControlUnits(); | 
 |  | 
 |   // Collect information about load/store queues. | 
 |   collectLoadStoreQueueInfo(); | 
 |  | 
 |   checkCompleteness(); | 
 | } | 
 |  | 
 | /// Gather all processor models. | 
 | void CodeGenSchedModels::collectProcModels() { | 
 |   RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor"); | 
 |   llvm::sort(ProcRecords, LessRecordFieldName()); | 
 |  | 
 |   // Check for duplicated names. | 
 |   auto I = std::adjacent_find(ProcRecords.begin(), ProcRecords.end(), | 
 |                               [](const Record *Rec1, const Record *Rec2) { | 
 |     return Rec1->getValueAsString("Name") == Rec2->getValueAsString("Name"); | 
 |   }); | 
 |   if (I != ProcRecords.end()) | 
 |     PrintFatalError((*I)->getLoc(), "Duplicate processor name " + | 
 |                     (*I)->getValueAsString("Name")); | 
 |  | 
 |   // Reserve space because we can. Reallocation would be ok. | 
 |   ProcModels.reserve(ProcRecords.size()+1); | 
 |  | 
 |   // Use idx=0 for NoModel/NoItineraries. | 
 |   Record *NoModelDef = Records.getDef("NoSchedModel"); | 
 |   Record *NoItinsDef = Records.getDef("NoItineraries"); | 
 |   ProcModels.emplace_back(0, "NoSchedModel", NoModelDef, NoItinsDef); | 
 |   ProcModelMap[NoModelDef] = 0; | 
 |  | 
 |   // For each processor, find a unique machine model. | 
 |   LLVM_DEBUG(dbgs() << "+++ PROCESSOR MODELs (addProcModel) +++\n"); | 
 |   for (Record *ProcRecord : ProcRecords) | 
 |     addProcModel(ProcRecord); | 
 | } | 
 |  | 
 | /// Get a unique processor model based on the defined MachineModel and | 
 | /// ProcessorItineraries. | 
 | void CodeGenSchedModels::addProcModel(Record *ProcDef) { | 
 |   Record *ModelKey = getModelOrItinDef(ProcDef); | 
 |   if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second) | 
 |     return; | 
 |  | 
 |   std::string Name = std::string(ModelKey->getName()); | 
 |   if (ModelKey->isSubClassOf("SchedMachineModel")) { | 
 |     Record *ItinsDef = ModelKey->getValueAsDef("Itineraries"); | 
 |     ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef); | 
 |   } | 
 |   else { | 
 |     // An itinerary is defined without a machine model. Infer a new model. | 
 |     if (!ModelKey->getValueAsListOfDefs("IID").empty()) | 
 |       Name = Name + "Model"; | 
 |     ProcModels.emplace_back(ProcModels.size(), Name, | 
 |                             ProcDef->getValueAsDef("SchedModel"), ModelKey); | 
 |   } | 
 |   LLVM_DEBUG(ProcModels.back().dump()); | 
 | } | 
 |  | 
 | // Recursively find all reachable SchedReadWrite records. | 
 | static void scanSchedRW(Record *RWDef, RecVec &RWDefs, | 
 |                         SmallPtrSet<Record*, 16> &RWSet) { | 
 |   if (!RWSet.insert(RWDef).second) | 
 |     return; | 
 |   RWDefs.push_back(RWDef); | 
 |   // Reads don't currently have sequence records, but it can be added later. | 
 |   if (RWDef->isSubClassOf("WriteSequence")) { | 
 |     RecVec Seq = RWDef->getValueAsListOfDefs("Writes"); | 
 |     for (Record *WSRec : Seq) | 
 |       scanSchedRW(WSRec, RWDefs, RWSet); | 
 |   } | 
 |   else if (RWDef->isSubClassOf("SchedVariant")) { | 
 |     // Visit each variant (guarded by a different predicate). | 
 |     RecVec Vars = RWDef->getValueAsListOfDefs("Variants"); | 
 |     for (Record *Variant : Vars) { | 
 |       // Visit each RW in the sequence selected by the current variant. | 
 |       RecVec Selected = Variant->getValueAsListOfDefs("Selected"); | 
 |       for (Record *SelDef : Selected) | 
 |         scanSchedRW(SelDef, RWDefs, RWSet); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Collect and sort all SchedReadWrites reachable via tablegen records. | 
 | // More may be inferred later when inferring new SchedClasses from variants. | 
 | void CodeGenSchedModels::collectSchedRW() { | 
 |   // Reserve idx=0 for invalid writes/reads. | 
 |   SchedWrites.resize(1); | 
 |   SchedReads.resize(1); | 
 |  | 
 |   SmallPtrSet<Record*, 16> RWSet; | 
 |  | 
 |   // Find all SchedReadWrites referenced by instruction defs. | 
 |   RecVec SWDefs, SRDefs; | 
 |   for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { | 
 |     Record *SchedDef = Inst->TheDef; | 
 |     if (SchedDef->isValueUnset("SchedRW")) | 
 |       continue; | 
 |     RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW"); | 
 |     for (Record *RW : RWs) { | 
 |       if (RW->isSubClassOf("SchedWrite")) | 
 |         scanSchedRW(RW, SWDefs, RWSet); | 
 |       else { | 
 |         assert(RW->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); | 
 |         scanSchedRW(RW, SRDefs, RWSet); | 
 |       } | 
 |     } | 
 |   } | 
 |   // Find all ReadWrites referenced by InstRW. | 
 |   RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); | 
 |   for (Record *InstRWDef : InstRWDefs) { | 
 |     // For all OperandReadWrites. | 
 |     RecVec RWDefs = InstRWDef->getValueAsListOfDefs("OperandReadWrites"); | 
 |     for (Record *RWDef : RWDefs) { | 
 |       if (RWDef->isSubClassOf("SchedWrite")) | 
 |         scanSchedRW(RWDef, SWDefs, RWSet); | 
 |       else { | 
 |         assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); | 
 |         scanSchedRW(RWDef, SRDefs, RWSet); | 
 |       } | 
 |     } | 
 |   } | 
 |   // Find all ReadWrites referenced by ItinRW. | 
 |   RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); | 
 |   for (Record *ItinRWDef : ItinRWDefs) { | 
 |     // For all OperandReadWrites. | 
 |     RecVec RWDefs = ItinRWDef->getValueAsListOfDefs("OperandReadWrites"); | 
 |     for (Record *RWDef : RWDefs) { | 
 |       if (RWDef->isSubClassOf("SchedWrite")) | 
 |         scanSchedRW(RWDef, SWDefs, RWSet); | 
 |       else { | 
 |         assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); | 
 |         scanSchedRW(RWDef, SRDefs, RWSet); | 
 |       } | 
 |     } | 
 |   } | 
 |   // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted | 
 |   // for the loop below that initializes Alias vectors. | 
 |   RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias"); | 
 |   llvm::sort(AliasDefs, LessRecord()); | 
 |   for (Record *ADef : AliasDefs) { | 
 |     Record *MatchDef = ADef->getValueAsDef("MatchRW"); | 
 |     Record *AliasDef = ADef->getValueAsDef("AliasRW"); | 
 |     if (MatchDef->isSubClassOf("SchedWrite")) { | 
 |       if (!AliasDef->isSubClassOf("SchedWrite")) | 
 |         PrintFatalError(ADef->getLoc(), "SchedWrite Alias must be SchedWrite"); | 
 |       scanSchedRW(AliasDef, SWDefs, RWSet); | 
 |     } | 
 |     else { | 
 |       assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); | 
 |       if (!AliasDef->isSubClassOf("SchedRead")) | 
 |         PrintFatalError(ADef->getLoc(), "SchedRead Alias must be SchedRead"); | 
 |       scanSchedRW(AliasDef, SRDefs, RWSet); | 
 |     } | 
 |   } | 
 |   // Sort and add the SchedReadWrites directly referenced by instructions or | 
 |   // itinerary resources. Index reads and writes in separate domains. | 
 |   llvm::sort(SWDefs, LessRecord()); | 
 |   for (Record *SWDef : SWDefs) { | 
 |     assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite"); | 
 |     SchedWrites.emplace_back(SchedWrites.size(), SWDef); | 
 |   } | 
 |   llvm::sort(SRDefs, LessRecord()); | 
 |   for (Record *SRDef : SRDefs) { | 
 |     assert(!getSchedRWIdx(SRDef, /*IsRead-*/true) && "duplicate SchedWrite"); | 
 |     SchedReads.emplace_back(SchedReads.size(), SRDef); | 
 |   } | 
 |   // Initialize WriteSequence vectors. | 
 |   for (CodeGenSchedRW &CGRW : SchedWrites) { | 
 |     if (!CGRW.IsSequence) | 
 |       continue; | 
 |     findRWs(CGRW.TheDef->getValueAsListOfDefs("Writes"), CGRW.Sequence, | 
 |             /*IsRead=*/false); | 
 |   } | 
 |   // Initialize Aliases vectors. | 
 |   for (Record *ADef : AliasDefs) { | 
 |     Record *AliasDef = ADef->getValueAsDef("AliasRW"); | 
 |     getSchedRW(AliasDef).IsAlias = true; | 
 |     Record *MatchDef = ADef->getValueAsDef("MatchRW"); | 
 |     CodeGenSchedRW &RW = getSchedRW(MatchDef); | 
 |     if (RW.IsAlias) | 
 |       PrintFatalError(ADef->getLoc(), "Cannot Alias an Alias"); | 
 |     RW.Aliases.push_back(ADef); | 
 |   } | 
 |   LLVM_DEBUG( | 
 |       dbgs() << "\n+++ SCHED READS and WRITES (collectSchedRW) +++\n"; | 
 |       for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { | 
 |         dbgs() << WIdx << ": "; | 
 |         SchedWrites[WIdx].dump(); | 
 |         dbgs() << '\n'; | 
 |       } for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; | 
 |              ++RIdx) { | 
 |         dbgs() << RIdx << ": "; | 
 |         SchedReads[RIdx].dump(); | 
 |         dbgs() << '\n'; | 
 |       } RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite"); | 
 |       for (Record *RWDef | 
 |            : RWDefs) { | 
 |         if (!getSchedRWIdx(RWDef, RWDef->isSubClassOf("SchedRead"))) { | 
 |           StringRef Name = RWDef->getName(); | 
 |           if (Name != "NoWrite" && Name != "ReadDefault") | 
 |             dbgs() << "Unused SchedReadWrite " << Name << '\n'; | 
 |         } | 
 |       }); | 
 | } | 
 |  | 
 | /// Compute a SchedWrite name from a sequence of writes. | 
 | std::string CodeGenSchedModels::genRWName(ArrayRef<unsigned> Seq, bool IsRead) { | 
 |   std::string Name("("); | 
 |   ListSeparator LS("_"); | 
 |   for (unsigned I : Seq) { | 
 |     Name += LS; | 
 |     Name += getSchedRW(I, IsRead).Name; | 
 |   } | 
 |   Name += ')'; | 
 |   return Name; | 
 | } | 
 |  | 
 | unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def, | 
 |                                            bool IsRead) const { | 
 |   const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; | 
 |   const auto I = find_if( | 
 |       RWVec, [Def](const CodeGenSchedRW &RW) { return RW.TheDef == Def; }); | 
 |   return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I); | 
 | } | 
 |  | 
 | bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const { | 
 |   for (const CodeGenSchedRW &Read : SchedReads) { | 
 |     Record *ReadDef = Read.TheDef; | 
 |     if (!ReadDef || !ReadDef->isSubClassOf("ProcReadAdvance")) | 
 |       continue; | 
 |  | 
 |     RecVec ValidWrites = ReadDef->getValueAsListOfDefs("ValidWrites"); | 
 |     if (is_contained(ValidWrites, WriteDef)) { | 
 |       return true; | 
 |     } | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | static void splitSchedReadWrites(const RecVec &RWDefs, | 
 |                                  RecVec &WriteDefs, RecVec &ReadDefs) { | 
 |   for (Record *RWDef : RWDefs) { | 
 |     if (RWDef->isSubClassOf("SchedWrite")) | 
 |       WriteDefs.push_back(RWDef); | 
 |     else { | 
 |       assert(RWDef->isSubClassOf("SchedRead") && "unknown SchedReadWrite"); | 
 |       ReadDefs.push_back(RWDef); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Split the SchedReadWrites defs and call findRWs for each list. | 
 | void CodeGenSchedModels::findRWs(const RecVec &RWDefs, | 
 |                                  IdxVec &Writes, IdxVec &Reads) const { | 
 |   RecVec WriteDefs; | 
 |   RecVec ReadDefs; | 
 |   splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs); | 
 |   findRWs(WriteDefs, Writes, false); | 
 |   findRWs(ReadDefs, Reads, true); | 
 | } | 
 |  | 
 | // Call getSchedRWIdx for all elements in a sequence of SchedRW defs. | 
 | void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs, | 
 |                                  bool IsRead) const { | 
 |   for (Record *RWDef : RWDefs) { | 
 |     unsigned Idx = getSchedRWIdx(RWDef, IsRead); | 
 |     assert(Idx && "failed to collect SchedReadWrite"); | 
 |     RWs.push_back(Idx); | 
 |   } | 
 | } | 
 |  | 
 | void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, | 
 |                                           bool IsRead) const { | 
 |   const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead); | 
 |   if (!SchedRW.IsSequence) { | 
 |     RWSeq.push_back(RWIdx); | 
 |     return; | 
 |   } | 
 |   int Repeat = | 
 |     SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1; | 
 |   for (int i = 0; i < Repeat; ++i) { | 
 |     for (unsigned I : SchedRW.Sequence) { | 
 |       expandRWSequence(I, RWSeq, IsRead); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Expand a SchedWrite as a sequence following any aliases that coincide with | 
 | // the given processor model. | 
 | void CodeGenSchedModels::expandRWSeqForProc( | 
 |   unsigned RWIdx, IdxVec &RWSeq, bool IsRead, | 
 |   const CodeGenProcModel &ProcModel) const { | 
 |  | 
 |   const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead); | 
 |   Record *AliasDef = nullptr; | 
 |   for (const Record *Rec : SchedWrite.Aliases) { | 
 |     const CodeGenSchedRW &AliasRW = getSchedRW(Rec->getValueAsDef("AliasRW")); | 
 |     if (Rec->getValueInit("SchedModel")->isComplete()) { | 
 |       Record *ModelDef = Rec->getValueAsDef("SchedModel"); | 
 |       if (&getProcModel(ModelDef) != &ProcModel) | 
 |         continue; | 
 |     } | 
 |     if (AliasDef) | 
 |       PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " | 
 |                       "defined for processor " + ProcModel.ModelName + | 
 |                       " Ensure only one SchedAlias exists per RW."); | 
 |     AliasDef = AliasRW.TheDef; | 
 |   } | 
 |   if (AliasDef) { | 
 |     expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead), | 
 |                        RWSeq, IsRead,ProcModel); | 
 |     return; | 
 |   } | 
 |   if (!SchedWrite.IsSequence) { | 
 |     RWSeq.push_back(RWIdx); | 
 |     return; | 
 |   } | 
 |   int Repeat = | 
 |     SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1; | 
 |   for (int I = 0, E = Repeat; I < E; ++I) { | 
 |     for (unsigned Idx : SchedWrite.Sequence) { | 
 |       expandRWSeqForProc(Idx, RWSeq, IsRead, ProcModel); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Find the existing SchedWrite that models this sequence of writes. | 
 | unsigned CodeGenSchedModels::findRWForSequence(ArrayRef<unsigned> Seq, | 
 |                                                bool IsRead) { | 
 |   std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; | 
 |  | 
 |   auto I = find_if(RWVec, [Seq](CodeGenSchedRW &RW) { | 
 |     return makeArrayRef(RW.Sequence) == Seq; | 
 |   }); | 
 |   // Index zero reserved for invalid RW. | 
 |   return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I); | 
 | } | 
 |  | 
 | /// Add this ReadWrite if it doesn't already exist. | 
 | unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq, | 
 |                                             bool IsRead) { | 
 |   assert(!Seq.empty() && "cannot insert empty sequence"); | 
 |   if (Seq.size() == 1) | 
 |     return Seq.back(); | 
 |  | 
 |   unsigned Idx = findRWForSequence(Seq, IsRead); | 
 |   if (Idx) | 
 |     return Idx; | 
 |  | 
 |   std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; | 
 |   unsigned RWIdx = RWVec.size(); | 
 |   CodeGenSchedRW SchedRW(RWIdx, IsRead, Seq, genRWName(Seq, IsRead)); | 
 |   RWVec.push_back(SchedRW); | 
 |   return RWIdx; | 
 | } | 
 |  | 
 | /// Visit all the instruction definitions for this target to gather and | 
 | /// enumerate the itinerary classes. These are the explicitly specified | 
 | /// SchedClasses. More SchedClasses may be inferred. | 
 | void CodeGenSchedModels::collectSchedClasses() { | 
 |  | 
 |   // NoItinerary is always the first class at Idx=0 | 
 |   assert(SchedClasses.empty() && "Expected empty sched class"); | 
 |   SchedClasses.emplace_back(0, "NoInstrModel", | 
 |                             Records.getDef("NoItinerary")); | 
 |   SchedClasses.back().ProcIndices.push_back(0); | 
 |  | 
 |   // Create a SchedClass for each unique combination of itinerary class and | 
 |   // SchedRW list. | 
 |   for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { | 
 |     Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary"); | 
 |     IdxVec Writes, Reads; | 
 |     if (!Inst->TheDef->isValueUnset("SchedRW")) | 
 |       findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); | 
 |  | 
 |     // ProcIdx == 0 indicates the class applies to all processors. | 
 |     unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/{0}); | 
 |     InstrClassMap[Inst->TheDef] = SCIdx; | 
 |   } | 
 |   // Create classes for InstRW defs. | 
 |   RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); | 
 |   llvm::sort(InstRWDefs, LessRecord()); | 
 |   LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n"); | 
 |   for (Record *RWDef : InstRWDefs) | 
 |     createInstRWClass(RWDef); | 
 |  | 
 |   NumInstrSchedClasses = SchedClasses.size(); | 
 |  | 
 |   bool EnableDump = false; | 
 |   LLVM_DEBUG(EnableDump = true); | 
 |   if (!EnableDump) | 
 |     return; | 
 |  | 
 |   LLVM_DEBUG( | 
 |       dbgs() | 
 |       << "\n+++ ITINERARIES and/or MACHINE MODELS (collectSchedClasses) +++\n"); | 
 |   for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { | 
 |     StringRef InstName = Inst->TheDef->getName(); | 
 |     unsigned SCIdx = getSchedClassIdx(*Inst); | 
 |     if (!SCIdx) { | 
 |       LLVM_DEBUG({ | 
 |         if (!Inst->hasNoSchedulingInfo) | 
 |           dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n'; | 
 |       }); | 
 |       continue; | 
 |     } | 
 |     CodeGenSchedClass &SC = getSchedClass(SCIdx); | 
 |     if (SC.ProcIndices[0] != 0) | 
 |       PrintFatalError(Inst->TheDef->getLoc(), "Instruction's sched class " | 
 |                       "must not be subtarget specific."); | 
 |  | 
 |     IdxVec ProcIndices; | 
 |     if (SC.ItinClassDef->getName() != "NoItinerary") { | 
 |       ProcIndices.push_back(0); | 
 |       dbgs() << "Itinerary for " << InstName << ": " | 
 |              << SC.ItinClassDef->getName() << '\n'; | 
 |     } | 
 |     if (!SC.Writes.empty()) { | 
 |       ProcIndices.push_back(0); | 
 |       LLVM_DEBUG({ | 
 |         dbgs() << "SchedRW machine model for " << InstName; | 
 |         for (unsigned int Write : SC.Writes) | 
 |           dbgs() << " " << SchedWrites[Write].Name; | 
 |         for (unsigned int Read : SC.Reads) | 
 |           dbgs() << " " << SchedReads[Read].Name; | 
 |         dbgs() << '\n'; | 
 |       }); | 
 |     } | 
 |     const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; | 
 |     for (Record *RWDef : RWDefs) { | 
 |       const CodeGenProcModel &ProcModel = | 
 |           getProcModel(RWDef->getValueAsDef("SchedModel")); | 
 |       ProcIndices.push_back(ProcModel.Index); | 
 |       LLVM_DEBUG(dbgs() << "InstRW on " << ProcModel.ModelName << " for " | 
 |                         << InstName); | 
 |       IdxVec Writes; | 
 |       IdxVec Reads; | 
 |       findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), | 
 |               Writes, Reads); | 
 |       LLVM_DEBUG({ | 
 |         for (unsigned WIdx : Writes) | 
 |           dbgs() << " " << SchedWrites[WIdx].Name; | 
 |         for (unsigned RIdx : Reads) | 
 |           dbgs() << " " << SchedReads[RIdx].Name; | 
 |         dbgs() << '\n'; | 
 |       }); | 
 |     } | 
 |     // If ProcIndices contains zero, the class applies to all processors. | 
 |     LLVM_DEBUG({ | 
 |       if (!llvm::is_contained(ProcIndices, 0)) { | 
 |         for (const CodeGenProcModel &PM : ProcModels) { | 
 |           if (!llvm::is_contained(ProcIndices, PM.Index)) | 
 |             dbgs() << "No machine model for " << Inst->TheDef->getName() | 
 |                    << " on processor " << PM.ModelName << '\n'; | 
 |         } | 
 |       } | 
 |     }); | 
 |   } | 
 | } | 
 |  | 
 | // Get the SchedClass index for an instruction. | 
 | unsigned | 
 | CodeGenSchedModels::getSchedClassIdx(const CodeGenInstruction &Inst) const { | 
 |   return InstrClassMap.lookup(Inst.TheDef); | 
 | } | 
 |  | 
 | std::string | 
 | CodeGenSchedModels::createSchedClassName(Record *ItinClassDef, | 
 |                                          ArrayRef<unsigned> OperWrites, | 
 |                                          ArrayRef<unsigned> OperReads) { | 
 |  | 
 |   std::string Name; | 
 |   if (ItinClassDef && ItinClassDef->getName() != "NoItinerary") | 
 |     Name = std::string(ItinClassDef->getName()); | 
 |   for (unsigned Idx : OperWrites) { | 
 |     if (!Name.empty()) | 
 |       Name += '_'; | 
 |     Name += SchedWrites[Idx].Name; | 
 |   } | 
 |   for (unsigned Idx : OperReads) { | 
 |     Name += '_'; | 
 |     Name += SchedReads[Idx].Name; | 
 |   } | 
 |   return Name; | 
 | } | 
 |  | 
 | std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) { | 
 |  | 
 |   std::string Name; | 
 |   ListSeparator LS("_"); | 
 |   for (const Record *InstDef : InstDefs) { | 
 |     Name += LS; | 
 |     Name += InstDef->getName(); | 
 |   } | 
 |   return Name; | 
 | } | 
 |  | 
 | /// Add an inferred sched class from an itinerary class and per-operand list of | 
 | /// SchedWrites and SchedReads. ProcIndices contains the set of IDs of | 
 | /// processors that may utilize this class. | 
 | unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef, | 
 |                                            ArrayRef<unsigned> OperWrites, | 
 |                                            ArrayRef<unsigned> OperReads, | 
 |                                            ArrayRef<unsigned> ProcIndices) { | 
 |   assert(!ProcIndices.empty() && "expect at least one ProcIdx"); | 
 |  | 
 |   auto IsKeyEqual = [=](const CodeGenSchedClass &SC) { | 
 |                      return SC.isKeyEqual(ItinClassDef, OperWrites, OperReads); | 
 |                    }; | 
 |  | 
 |   auto I = find_if(make_range(schedClassBegin(), schedClassEnd()), IsKeyEqual); | 
 |   unsigned Idx = I == schedClassEnd() ? 0 : std::distance(schedClassBegin(), I); | 
 |   if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) { | 
 |     IdxVec PI; | 
 |     std::set_union(SchedClasses[Idx].ProcIndices.begin(), | 
 |                    SchedClasses[Idx].ProcIndices.end(), | 
 |                    ProcIndices.begin(), ProcIndices.end(), | 
 |                    std::back_inserter(PI)); | 
 |     SchedClasses[Idx].ProcIndices = std::move(PI); | 
 |     return Idx; | 
 |   } | 
 |   Idx = SchedClasses.size(); | 
 |   SchedClasses.emplace_back(Idx, | 
 |                             createSchedClassName(ItinClassDef, OperWrites, | 
 |                                                  OperReads), | 
 |                             ItinClassDef); | 
 |   CodeGenSchedClass &SC = SchedClasses.back(); | 
 |   SC.Writes = OperWrites; | 
 |   SC.Reads = OperReads; | 
 |   SC.ProcIndices = ProcIndices; | 
 |  | 
 |   return Idx; | 
 | } | 
 |  | 
 | // Create classes for each set of opcodes that are in the same InstReadWrite | 
 | // definition across all processors. | 
 | void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { | 
 |   // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that | 
 |   // intersects with an existing class via a previous InstRWDef. Instrs that do | 
 |   // not intersect with an existing class refer back to their former class as | 
 |   // determined from ItinDef or SchedRW. | 
 |   SmallMapVector<unsigned, SmallVector<Record *, 8>, 4> ClassInstrs; | 
 |   // Sort Instrs into sets. | 
 |   const RecVec *InstDefs = Sets.expand(InstRWDef); | 
 |   if (InstDefs->empty()) | 
 |     PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); | 
 |  | 
 |   for (Record *InstDef : *InstDefs) { | 
 |     InstClassMapTy::const_iterator Pos = InstrClassMap.find(InstDef); | 
 |     if (Pos == InstrClassMap.end()) | 
 |       PrintFatalError(InstDef->getLoc(), "No sched class for instruction."); | 
 |     unsigned SCIdx = Pos->second; | 
 |     ClassInstrs[SCIdx].push_back(InstDef); | 
 |   } | 
 |   // For each set of Instrs, create a new class if necessary, and map or remap | 
 |   // the Instrs to it. | 
 |   for (auto &Entry : ClassInstrs) { | 
 |     unsigned OldSCIdx = Entry.first; | 
 |     ArrayRef<Record*> InstDefs = Entry.second; | 
 |     // If the all instrs in the current class are accounted for, then leave | 
 |     // them mapped to their old class. | 
 |     if (OldSCIdx) { | 
 |       const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs; | 
 |       if (!RWDefs.empty()) { | 
 |         const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]); | 
 |         unsigned OrigNumInstrs = | 
 |           count_if(*OrigInstDefs, [&](Record *OIDef) { | 
 |                      return InstrClassMap[OIDef] == OldSCIdx; | 
 |                    }); | 
 |         if (OrigNumInstrs == InstDefs.size()) { | 
 |           assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && | 
 |                  "expected a generic SchedClass"); | 
 |           Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); | 
 |           // Make sure we didn't already have a InstRW containing this | 
 |           // instruction on this model. | 
 |           for (Record *RWD : RWDefs) { | 
 |             if (RWD->getValueAsDef("SchedModel") == RWModelDef && | 
 |                 RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) { | 
 |               assert(!InstDefs.empty()); // Checked at function start. | 
 |               PrintError( | 
 |                   InstRWDef->getLoc(), | 
 |                   "Overlapping InstRW definition for \"" + | 
 |                       InstDefs.front()->getName() + | 
 |                       "\" also matches previous \"" + | 
 |                       RWD->getValue("Instrs")->getValue()->getAsString() + | 
 |                       "\"."); | 
 |               PrintFatalNote(RWD->getLoc(), "Previous match was here."); | 
 |             } | 
 |           } | 
 |           LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" | 
 |                             << SchedClasses[OldSCIdx].Name << " on " | 
 |                             << RWModelDef->getName() << "\n"); | 
 |           SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef); | 
 |           continue; | 
 |         } | 
 |       } | 
 |     } | 
 |     unsigned SCIdx = SchedClasses.size(); | 
 |     SchedClasses.emplace_back(SCIdx, createSchedClassName(InstDefs), nullptr); | 
 |     CodeGenSchedClass &SC = SchedClasses.back(); | 
 |     LLVM_DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on " | 
 |                       << InstRWDef->getValueAsDef("SchedModel")->getName() | 
 |                       << "\n"); | 
 |  | 
 |     // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. | 
 |     SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; | 
 |     SC.Writes = SchedClasses[OldSCIdx].Writes; | 
 |     SC.Reads = SchedClasses[OldSCIdx].Reads; | 
 |     SC.ProcIndices.push_back(0); | 
 |     // If we had an old class, copy it's InstRWs to this new class. | 
 |     if (OldSCIdx) { | 
 |       Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); | 
 |       for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) { | 
 |         if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) { | 
 |           assert(!InstDefs.empty()); // Checked at function start. | 
 |           PrintError( | 
 |               InstRWDef->getLoc(), | 
 |               "Overlapping InstRW definition for \"" + | 
 |                   InstDefs.front()->getName() + "\" also matches previous \"" + | 
 |                   OldRWDef->getValue("Instrs")->getValue()->getAsString() + | 
 |                   "\"."); | 
 |           PrintFatalNote(OldRWDef->getLoc(), "Previous match was here."); | 
 |         } | 
 |         assert(OldRWDef != InstRWDef && | 
 |                "SchedClass has duplicate InstRW def"); | 
 |         SC.InstRWs.push_back(OldRWDef); | 
 |       } | 
 |     } | 
 |     // Map each Instr to this new class. | 
 |     for (Record *InstDef : InstDefs) | 
 |       InstrClassMap[InstDef] = SCIdx; | 
 |     SC.InstRWs.push_back(InstRWDef); | 
 |   } | 
 | } | 
 |  | 
 | // True if collectProcItins found anything. | 
 | bool CodeGenSchedModels::hasItineraries() const { | 
 |   for (const CodeGenProcModel &PM : make_range(procModelBegin(),procModelEnd())) | 
 |     if (PM.hasItineraries()) | 
 |       return true; | 
 |   return false; | 
 | } | 
 |  | 
 | // Gather the processor itineraries. | 
 | void CodeGenSchedModels::collectProcItins() { | 
 |   LLVM_DEBUG(dbgs() << "\n+++ PROBLEM ITINERARIES (collectProcItins) +++\n"); | 
 |   for (CodeGenProcModel &ProcModel : ProcModels) { | 
 |     if (!ProcModel.hasItineraries()) | 
 |       continue; | 
 |  | 
 |     RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); | 
 |     assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect"); | 
 |  | 
 |     // Populate ItinDefList with Itinerary records. | 
 |     ProcModel.ItinDefList.resize(NumInstrSchedClasses); | 
 |  | 
 |     // Insert each itinerary data record in the correct position within | 
 |     // the processor model's ItinDefList. | 
 |     for (Record *ItinData : ItinRecords) { | 
 |       const Record *ItinDef = ItinData->getValueAsDef("TheClass"); | 
 |       bool FoundClass = false; | 
 |  | 
 |       for (const CodeGenSchedClass &SC : | 
 |            make_range(schedClassBegin(), schedClassEnd())) { | 
 |         // Multiple SchedClasses may share an itinerary. Update all of them. | 
 |         if (SC.ItinClassDef == ItinDef) { | 
 |           ProcModel.ItinDefList[SC.Index] = ItinData; | 
 |           FoundClass = true; | 
 |         } | 
 |       } | 
 |       if (!FoundClass) { | 
 |         LLVM_DEBUG(dbgs() << ProcModel.ItinsDef->getName() | 
 |                           << " missing class for itinerary " | 
 |                           << ItinDef->getName() << '\n'); | 
 |       } | 
 |     } | 
 |     // Check for missing itinerary entries. | 
 |     assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); | 
 |     LLVM_DEBUG( | 
 |         for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { | 
 |           if (!ProcModel.ItinDefList[i]) | 
 |             dbgs() << ProcModel.ItinsDef->getName() | 
 |                    << " missing itinerary for class " << SchedClasses[i].Name | 
 |                    << '\n'; | 
 |         }); | 
 |   } | 
 | } | 
 |  | 
 | // Gather the read/write types for each itinerary class. | 
 | void CodeGenSchedModels::collectProcItinRW() { | 
 |   RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); | 
 |   llvm::sort(ItinRWDefs, LessRecord()); | 
 |   for (Record *RWDef  : ItinRWDefs) { | 
 |     if (!RWDef->getValueInit("SchedModel")->isComplete()) | 
 |       PrintFatalError(RWDef->getLoc(), "SchedModel is undefined"); | 
 |     Record *ModelDef = RWDef->getValueAsDef("SchedModel"); | 
 |     ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef); | 
 |     if (I == ProcModelMap.end()) { | 
 |       PrintFatalError(RWDef->getLoc(), "Undefined SchedMachineModel " | 
 |                     + ModelDef->getName()); | 
 |     } | 
 |     ProcModels[I->second].ItinRWDefs.push_back(RWDef); | 
 |   } | 
 | } | 
 |  | 
 | // Gather the unsupported features for processor models. | 
 | void CodeGenSchedModels::collectProcUnsupportedFeatures() { | 
 |   for (CodeGenProcModel &ProcModel : ProcModels) | 
 |     append_range( | 
 |         ProcModel.UnsupportedFeaturesDefs, | 
 |         ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")); | 
 | } | 
 |  | 
 | /// Infer new classes from existing classes. In the process, this may create new | 
 | /// SchedWrites from sequences of existing SchedWrites. | 
 | void CodeGenSchedModels::inferSchedClasses() { | 
 |   LLVM_DEBUG( | 
 |       dbgs() << "\n+++ INFERRING SCHED CLASSES (inferSchedClasses) +++\n"); | 
 |   LLVM_DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n"); | 
 |  | 
 |   // Visit all existing classes and newly created classes. | 
 |   for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { | 
 |     assert(SchedClasses[Idx].Index == Idx && "bad SCIdx"); | 
 |  | 
 |     if (SchedClasses[Idx].ItinClassDef) | 
 |       inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx); | 
 |     if (!SchedClasses[Idx].InstRWs.empty()) | 
 |       inferFromInstRWs(Idx); | 
 |     if (!SchedClasses[Idx].Writes.empty()) { | 
 |       inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, | 
 |                   Idx, SchedClasses[Idx].ProcIndices); | 
 |     } | 
 |     assert(SchedClasses.size() < (NumInstrSchedClasses*6) && | 
 |            "too many SchedVariants"); | 
 |   } | 
 | } | 
 |  | 
 | /// Infer classes from per-processor itinerary resources. | 
 | void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef, | 
 |                                             unsigned FromClassIdx) { | 
 |   for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { | 
 |     const CodeGenProcModel &PM = ProcModels[PIdx]; | 
 |     // For all ItinRW entries. | 
 |     bool HasMatch = false; | 
 |     for (const Record *Rec : PM.ItinRWDefs) { | 
 |       RecVec Matched = Rec->getValueAsListOfDefs("MatchedItinClasses"); | 
 |       if (!llvm::is_contained(Matched, ItinClassDef)) | 
 |         continue; | 
 |       if (HasMatch) | 
 |         PrintFatalError(Rec->getLoc(), "Duplicate itinerary class " | 
 |                       + ItinClassDef->getName() | 
 |                       + " in ItinResources for " + PM.ModelName); | 
 |       HasMatch = true; | 
 |       IdxVec Writes, Reads; | 
 |       findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); | 
 |       inferFromRW(Writes, Reads, FromClassIdx, PIdx); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// Infer classes from per-processor InstReadWrite definitions. | 
 | void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) { | 
 |   for (unsigned I = 0, E = SchedClasses[SCIdx].InstRWs.size(); I != E; ++I) { | 
 |     assert(SchedClasses[SCIdx].InstRWs.size() == E && "InstrRWs was mutated!"); | 
 |     Record *Rec = SchedClasses[SCIdx].InstRWs[I]; | 
 |     const RecVec *InstDefs = Sets.expand(Rec); | 
 |     RecIter II = InstDefs->begin(), IE = InstDefs->end(); | 
 |     for (; II != IE; ++II) { | 
 |       if (InstrClassMap[*II] == SCIdx) | 
 |         break; | 
 |     } | 
 |     // If this class no longer has any instructions mapped to it, it has become | 
 |     // irrelevant. | 
 |     if (II == IE) | 
 |       continue; | 
 |     IdxVec Writes, Reads; | 
 |     findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); | 
 |     unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index; | 
 |     inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses. | 
 |     SchedClasses[SCIdx].InstRWProcIndices.insert(PIdx); | 
 |   } | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // Helper for substituteVariantOperand. | 
 | struct TransVariant { | 
 |   Record *VarOrSeqDef;  // Variant or sequence. | 
 |   unsigned RWIdx;       // Index of this variant or sequence's matched type. | 
 |   unsigned ProcIdx;     // Processor model index or zero for any. | 
 |   unsigned TransVecIdx; // Index into PredTransitions::TransVec. | 
 |  | 
 |   TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti): | 
 |     VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {} | 
 | }; | 
 |  | 
 | // Associate a predicate with the SchedReadWrite that it guards. | 
 | // RWIdx is the index of the read/write variant. | 
 | struct PredCheck { | 
 |   bool IsRead; | 
 |   unsigned RWIdx; | 
 |   Record *Predicate; | 
 |  | 
 |   PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {} | 
 | }; | 
 |  | 
 | // A Predicate transition is a list of RW sequences guarded by a PredTerm. | 
 | struct PredTransition { | 
 |   // A predicate term is a conjunction of PredChecks. | 
 |   SmallVector<PredCheck, 4> PredTerm; | 
 |   SmallVector<SmallVector<unsigned,4>, 16> WriteSequences; | 
 |   SmallVector<SmallVector<unsigned,4>, 16> ReadSequences; | 
 |   unsigned ProcIndex = 0; | 
 |  | 
 |   PredTransition() = default; | 
 |   PredTransition(ArrayRef<PredCheck> PT, unsigned ProcId) { | 
 |     PredTerm.assign(PT.begin(), PT.end()); | 
 |     ProcIndex = ProcId; | 
 |   } | 
 | }; | 
 |  | 
 | // Encapsulate a set of partially constructed transitions. | 
 | // The results are built by repeated calls to substituteVariants. | 
 | class PredTransitions { | 
 |   CodeGenSchedModels &SchedModels; | 
 |  | 
 | public: | 
 |   std::vector<PredTransition> TransVec; | 
 |  | 
 |   PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {} | 
 |  | 
 |   bool substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq, | 
 |                                 bool IsRead, unsigned StartIdx); | 
 |  | 
 |   bool substituteVariants(const PredTransition &Trans); | 
 |  | 
 | #ifndef NDEBUG | 
 |   void dump() const; | 
 | #endif | 
 |  | 
 | private: | 
 |   bool mutuallyExclusive(Record *PredDef, ArrayRef<Record *> Preds, | 
 |                          ArrayRef<PredCheck> Term); | 
 |   void getIntersectingVariants( | 
 |     const CodeGenSchedRW &SchedRW, unsigned TransIdx, | 
 |     std::vector<TransVariant> &IntersectingVariants); | 
 |   void pushVariant(const TransVariant &VInfo, bool IsRead); | 
 | }; | 
 |  | 
 | } // end anonymous namespace | 
 |  | 
 | // Return true if this predicate is mutually exclusive with a PredTerm. This | 
 | // degenerates into checking if the predicate is mutually exclusive with any | 
 | // predicate in the Term's conjunction. | 
 | // | 
 | // All predicates associated with a given SchedRW are considered mutually | 
 | // exclusive. This should work even if the conditions expressed by the | 
 | // predicates are not exclusive because the predicates for a given SchedWrite | 
 | // are always checked in the order they are defined in the .td file. Later | 
 | // conditions implicitly negate any prior condition. | 
 | bool PredTransitions::mutuallyExclusive(Record *PredDef, | 
 |                                         ArrayRef<Record *> Preds, | 
 |                                         ArrayRef<PredCheck> Term) { | 
 |   for (const PredCheck &PC: Term) { | 
 |     if (PC.Predicate == PredDef) | 
 |       return false; | 
 |  | 
 |     const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(PC.RWIdx, PC.IsRead); | 
 |     assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant"); | 
 |     RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); | 
 |     if (any_of(Variants, [PredDef](const Record *R) { | 
 |           return R->getValueAsDef("Predicate") == PredDef; | 
 |         })) { | 
 |       // To check if PredDef is mutually exclusive with PC we also need to | 
 |       // check that PC.Predicate is exclusive with all predicates from variant | 
 |       // we're expanding. Consider following RW sequence with two variants | 
 |       // (1 & 2), where A, B and C are predicates from corresponding SchedVars: | 
 |       // | 
 |       // 1:A/B - 2:C/B | 
 |       // | 
 |       // Here C is not mutually exclusive with variant (1), because A doesn't | 
 |       // exist in variant (2). This means we have possible transitions from A | 
 |       // to C and from A to B, and fully expanded sequence would look like: | 
 |       // | 
 |       // if (A & C) return ...; | 
 |       // if (A & B) return ...; | 
 |       // if (B) return ...; | 
 |       // | 
 |       // Now let's consider another sequence: | 
 |       // | 
 |       // 1:A/B - 2:A/B | 
 |       // | 
 |       // Here A in variant (2) is mutually exclusive with variant (1), because | 
 |       // A also exists in (2). This means A->B transition is impossible and | 
 |       // expanded sequence would look like: | 
 |       // | 
 |       // if (A) return ...; | 
 |       // if (B) return ...; | 
 |       if (!llvm::is_contained(Preds, PC.Predicate)) | 
 |         continue; | 
 |       return true; | 
 |     } | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | static std::vector<Record *> getAllPredicates(ArrayRef<TransVariant> Variants, | 
 |                                               unsigned ProcId) { | 
 |   std::vector<Record *> Preds; | 
 |   for (auto &Variant : Variants) { | 
 |     if (!Variant.VarOrSeqDef->isSubClassOf("SchedVar")) | 
 |       continue; | 
 |     Preds.push_back(Variant.VarOrSeqDef->getValueAsDef("Predicate")); | 
 |   } | 
 |   return Preds; | 
 | } | 
 |  | 
 | // Populate IntersectingVariants with any variants or aliased sequences of the | 
 | // given SchedRW whose processor indices and predicates are not mutually | 
 | // exclusive with the given transition. | 
 | void PredTransitions::getIntersectingVariants( | 
 |   const CodeGenSchedRW &SchedRW, unsigned TransIdx, | 
 |   std::vector<TransVariant> &IntersectingVariants) { | 
 |  | 
 |   bool GenericRW = false; | 
 |  | 
 |   std::vector<TransVariant> Variants; | 
 |   if (SchedRW.HasVariants) { | 
 |     unsigned VarProcIdx = 0; | 
 |     if (SchedRW.TheDef->getValueInit("SchedModel")->isComplete()) { | 
 |       Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel"); | 
 |       VarProcIdx = SchedModels.getProcModel(ModelDef).Index; | 
 |     } | 
 |     if (VarProcIdx == 0 || VarProcIdx == TransVec[TransIdx].ProcIndex) { | 
 |       // Push each variant. Assign TransVecIdx later. | 
 |       const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants"); | 
 |       for (Record *VarDef : VarDefs) | 
 |         Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0); | 
 |       if (VarProcIdx == 0) | 
 |         GenericRW = true; | 
 |     } | 
 |   } | 
 |   for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); | 
 |        AI != AE; ++AI) { | 
 |     // If either the SchedAlias itself or the SchedReadWrite that it aliases | 
 |     // to is defined within a processor model, constrain all variants to | 
 |     // that processor. | 
 |     unsigned AliasProcIdx = 0; | 
 |     if ((*AI)->getValueInit("SchedModel")->isComplete()) { | 
 |       Record *ModelDef = (*AI)->getValueAsDef("SchedModel"); | 
 |       AliasProcIdx = SchedModels.getProcModel(ModelDef).Index; | 
 |     } | 
 |     if (AliasProcIdx && AliasProcIdx != TransVec[TransIdx].ProcIndex) | 
 |       continue; | 
 |     if (!Variants.empty()) { | 
 |       const CodeGenProcModel &PM = | 
 |           *(SchedModels.procModelBegin() + AliasProcIdx); | 
 |       PrintFatalError((*AI)->getLoc(), | 
 |                       "Multiple variants defined for processor " + | 
 |                           PM.ModelName + | 
 |                           " Ensure only one SchedAlias exists per RW."); | 
 |     } | 
 |  | 
 |     const CodeGenSchedRW &AliasRW = | 
 |       SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); | 
 |  | 
 |     if (AliasRW.HasVariants) { | 
 |       const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants"); | 
 |       for (Record *VD : VarDefs) | 
 |         Variants.emplace_back(VD, AliasRW.Index, AliasProcIdx, 0); | 
 |     } | 
 |     if (AliasRW.IsSequence) | 
 |       Variants.emplace_back(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0); | 
 |     if (AliasProcIdx == 0) | 
 |       GenericRW = true; | 
 |   } | 
 |   std::vector<Record *> AllPreds = | 
 |       getAllPredicates(Variants, TransVec[TransIdx].ProcIndex); | 
 |   for (TransVariant &Variant : Variants) { | 
 |     // Don't expand variants if the processor models don't intersect. | 
 |     // A zero processor index means any processor. | 
 |     if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) { | 
 |       Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate"); | 
 |       if (mutuallyExclusive(PredDef, AllPreds, TransVec[TransIdx].PredTerm)) | 
 |         continue; | 
 |     } | 
 |  | 
 |     if (IntersectingVariants.empty()) { | 
 |       // The first variant builds on the existing transition. | 
 |       Variant.TransVecIdx = TransIdx; | 
 |       IntersectingVariants.push_back(Variant); | 
 |     } | 
 |     else { | 
 |       // Push another copy of the current transition for more variants. | 
 |       Variant.TransVecIdx = TransVec.size(); | 
 |       IntersectingVariants.push_back(Variant); | 
 |       TransVec.push_back(TransVec[TransIdx]); | 
 |     } | 
 |   } | 
 |   if (GenericRW && IntersectingVariants.empty()) { | 
 |     PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has " | 
 |                     "a matching predicate on any processor"); | 
 |   } | 
 | } | 
 |  | 
 | // Push the Reads/Writes selected by this variant onto the PredTransition | 
 | // specified by VInfo. | 
 | void PredTransitions:: | 
 | pushVariant(const TransVariant &VInfo, bool IsRead) { | 
 |   PredTransition &Trans = TransVec[VInfo.TransVecIdx]; | 
 |  | 
 |   // If this operand transition is reached through a processor-specific alias, | 
 |   // then the whole transition is specific to this processor. | 
 |   IdxVec SelectedRWs; | 
 |   if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) { | 
 |     Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate"); | 
 |     Trans.PredTerm.emplace_back(IsRead, VInfo.RWIdx,PredDef); | 
 |     RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected"); | 
 |     SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead); | 
 |   } | 
 |   else { | 
 |     assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") && | 
 |            "variant must be a SchedVariant or aliased WriteSequence"); | 
 |     SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead)); | 
 |   } | 
 |  | 
 |   const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead); | 
 |  | 
 |   SmallVectorImpl<SmallVector<unsigned,4>> &RWSequences = IsRead | 
 |     ? Trans.ReadSequences : Trans.WriteSequences; | 
 |   if (SchedRW.IsVariadic) { | 
 |     unsigned OperIdx = RWSequences.size()-1; | 
 |     // Make N-1 copies of this transition's last sequence. | 
 |     RWSequences.reserve(RWSequences.size() + SelectedRWs.size() - 1); | 
 |     RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1, | 
 |                        RWSequences[OperIdx]); | 
 |     // Push each of the N elements of the SelectedRWs onto a copy of the last | 
 |     // sequence (split the current operand into N operands). | 
 |     // Note that write sequences should be expanded within this loop--the entire | 
 |     // sequence belongs to a single operand. | 
 |     for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end(); | 
 |          RWI != RWE; ++RWI, ++OperIdx) { | 
 |       IdxVec ExpandedRWs; | 
 |       if (IsRead) | 
 |         ExpandedRWs.push_back(*RWI); | 
 |       else | 
 |         SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); | 
 |       llvm::append_range(RWSequences[OperIdx], ExpandedRWs); | 
 |     } | 
 |     assert(OperIdx == RWSequences.size() && "missed a sequence"); | 
 |   } | 
 |   else { | 
 |     // Push this transition's expanded sequence onto this transition's last | 
 |     // sequence (add to the current operand's sequence). | 
 |     SmallVectorImpl<unsigned> &Seq = RWSequences.back(); | 
 |     IdxVec ExpandedRWs; | 
 |     for (unsigned int SelectedRW : SelectedRWs) { | 
 |       if (IsRead) | 
 |         ExpandedRWs.push_back(SelectedRW); | 
 |       else | 
 |         SchedModels.expandRWSequence(SelectedRW, ExpandedRWs, IsRead); | 
 |     } | 
 |     llvm::append_range(Seq, ExpandedRWs); | 
 |   } | 
 | } | 
 |  | 
 | // RWSeq is a sequence of all Reads or all Writes for the next read or write | 
 | // operand. StartIdx is an index into TransVec where partial results | 
 | // starts. RWSeq must be applied to all transitions between StartIdx and the end | 
 | // of TransVec. | 
 | bool PredTransitions::substituteVariantOperand( | 
 |     const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) { | 
 |   bool Subst = false; | 
 |   // Visit each original RW within the current sequence. | 
 |   for (unsigned int RWI : RWSeq) { | 
 |     const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(RWI, IsRead); | 
 |     // Push this RW on all partial PredTransitions or distribute variants. | 
 |     // New PredTransitions may be pushed within this loop which should not be | 
 |     // revisited (TransEnd must be loop invariant). | 
 |     for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size(); | 
 |          TransIdx != TransEnd; ++TransIdx) { | 
 |       // Distribute this partial PredTransition across intersecting variants. | 
 |       // This will push a copies of TransVec[TransIdx] on the back of TransVec. | 
 |       std::vector<TransVariant> IntersectingVariants; | 
 |       getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants); | 
 |       // Now expand each variant on top of its copy of the transition. | 
 |       for (const TransVariant &IV : IntersectingVariants) | 
 |         pushVariant(IV, IsRead); | 
 |       if (IntersectingVariants.empty()) { | 
 |         if (IsRead) | 
 |           TransVec[TransIdx].ReadSequences.back().push_back(RWI); | 
 |         else | 
 |           TransVec[TransIdx].WriteSequences.back().push_back(RWI); | 
 |         continue; | 
 |       } else { | 
 |         Subst = true; | 
 |       } | 
 |     } | 
 |   } | 
 |   return Subst; | 
 | } | 
 |  | 
 | // For each variant of a Read/Write in Trans, substitute the sequence of | 
 | // Read/Writes guarded by the variant. This is exponential in the number of | 
 | // variant Read/Writes, but in practice detection of mutually exclusive | 
 | // predicates should result in linear growth in the total number variants. | 
 | // | 
 | // This is one step in a breadth-first search of nested variants. | 
 | bool PredTransitions::substituteVariants(const PredTransition &Trans) { | 
 |   // Build up a set of partial results starting at the back of | 
 |   // PredTransitions. Remember the first new transition. | 
 |   unsigned StartIdx = TransVec.size(); | 
 |   bool Subst = false; | 
 |   assert(Trans.ProcIndex != 0); | 
 |   TransVec.emplace_back(Trans.PredTerm, Trans.ProcIndex); | 
 |  | 
 |   // Visit each original write sequence. | 
 |   for (const auto &WriteSequence : Trans.WriteSequences) { | 
 |     // Push a new (empty) write sequence onto all partial Transitions. | 
 |     for (std::vector<PredTransition>::iterator I = | 
 |            TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { | 
 |       I->WriteSequences.emplace_back(); | 
 |     } | 
 |     Subst |= | 
 |         substituteVariantOperand(WriteSequence, /*IsRead=*/false, StartIdx); | 
 |   } | 
 |   // Visit each original read sequence. | 
 |   for (const auto &ReadSequence : Trans.ReadSequences) { | 
 |     // Push a new (empty) read sequence onto all partial Transitions. | 
 |     for (std::vector<PredTransition>::iterator I = | 
 |            TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { | 
 |       I->ReadSequences.emplace_back(); | 
 |     } | 
 |     Subst |= substituteVariantOperand(ReadSequence, /*IsRead=*/true, StartIdx); | 
 |   } | 
 |   return Subst; | 
 | } | 
 |  | 
 | static void addSequences(CodeGenSchedModels &SchedModels, | 
 |                          const SmallVectorImpl<SmallVector<unsigned, 4>> &Seqs, | 
 |                          IdxVec &Result, bool IsRead) { | 
 |   for (const auto &S : Seqs) | 
 |     if (!S.empty()) | 
 |       Result.push_back(SchedModels.findOrInsertRW(S, IsRead)); | 
 | } | 
 |  | 
 | #ifndef NDEBUG | 
 | static void dumpRecVec(const RecVec &RV) { | 
 |   for (const Record *R : RV) | 
 |     dbgs() << R->getName() << ", "; | 
 | } | 
 | #endif | 
 |  | 
 | static void dumpTransition(const CodeGenSchedModels &SchedModels, | 
 |                            const CodeGenSchedClass &FromSC, | 
 |                            const CodeGenSchedTransition &SCTrans, | 
 |                            const RecVec &Preds) { | 
 |   LLVM_DEBUG(dbgs() << "Adding transition from " << FromSC.Name << "(" | 
 |                     << FromSC.Index << ") to " | 
 |                     << SchedModels.getSchedClass(SCTrans.ToClassIdx).Name << "(" | 
 |                     << SCTrans.ToClassIdx << ") on pred term: ("; | 
 |              dumpRecVec(Preds); | 
 |              dbgs() << ") on processor (" << SCTrans.ProcIndex << ")\n"); | 
 | } | 
 | // Create a new SchedClass for each variant found by inferFromRW. Pass | 
 | static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, | 
 |                                  unsigned FromClassIdx, | 
 |                                  CodeGenSchedModels &SchedModels) { | 
 |   // For each PredTransition, create a new CodeGenSchedTransition, which usually | 
 |   // requires creating a new SchedClass. | 
 |   for (const auto &LastTransition : LastTransitions) { | 
 |     // Variant expansion (substituteVariants) may create unconditional | 
 |     // transitions. We don't need to build sched classes for them. | 
 |     if (LastTransition.PredTerm.empty()) | 
 |       continue; | 
 |     IdxVec OperWritesVariant, OperReadsVariant; | 
 |     addSequences(SchedModels, LastTransition.WriteSequences, OperWritesVariant, | 
 |                  false); | 
 |     addSequences(SchedModels, LastTransition.ReadSequences, OperReadsVariant, | 
 |                  true); | 
 |     CodeGenSchedTransition SCTrans; | 
 |  | 
 |     // Transition should not contain processor indices already assigned to | 
 |     // InstRWs in this scheduling class. | 
 |     const CodeGenSchedClass &FromSC = SchedModels.getSchedClass(FromClassIdx); | 
 |     if (FromSC.InstRWProcIndices.count(LastTransition.ProcIndex)) | 
 |       continue; | 
 |     SCTrans.ProcIndex = LastTransition.ProcIndex; | 
 |     SCTrans.ToClassIdx = | 
 |         SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant, | 
 |                                   OperReadsVariant, LastTransition.ProcIndex); | 
 |  | 
 |     // The final PredTerm is unique set of predicates guarding the transition. | 
 |     RecVec Preds; | 
 |     transform(LastTransition.PredTerm, std::back_inserter(Preds), | 
 |               [](const PredCheck &P) { return P.Predicate; }); | 
 |     Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end()); | 
 |     dumpTransition(SchedModels, FromSC, SCTrans, Preds); | 
 |     SCTrans.PredTerm = std::move(Preds); | 
 |     SchedModels.getSchedClass(FromClassIdx) | 
 |         .Transitions.push_back(std::move(SCTrans)); | 
 |   } | 
 | } | 
 |  | 
 | std::vector<unsigned> CodeGenSchedModels::getAllProcIndices() const { | 
 |   std::vector<unsigned> ProcIdVec; | 
 |   for (const auto &PM : ProcModelMap) | 
 |     if (PM.second != 0) | 
 |       ProcIdVec.push_back(PM.second); | 
 |   // The order of the keys (Record pointers) of ProcModelMap are not stable. | 
 |   // Sort to stabalize the values. | 
 |   llvm::sort(ProcIdVec); | 
 |   return ProcIdVec; | 
 | } | 
 |  | 
 | static std::vector<PredTransition> | 
 | makePerProcessorTransitions(const PredTransition &Trans, | 
 |                             ArrayRef<unsigned> ProcIndices) { | 
 |   std::vector<PredTransition> PerCpuTransVec; | 
 |   for (unsigned ProcId : ProcIndices) { | 
 |     assert(ProcId != 0); | 
 |     PerCpuTransVec.push_back(Trans); | 
 |     PerCpuTransVec.back().ProcIndex = ProcId; | 
 |   } | 
 |   return PerCpuTransVec; | 
 | } | 
 |  | 
 | // Create new SchedClasses for the given ReadWrite list. If any of the | 
 | // ReadWrites refers to a SchedVariant, create a new SchedClass for each variant | 
 | // of the ReadWrite list, following Aliases if necessary. | 
 | void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites, | 
 |                                      ArrayRef<unsigned> OperReads, | 
 |                                      unsigned FromClassIdx, | 
 |                                      ArrayRef<unsigned> ProcIndices) { | 
 |   LLVM_DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); | 
 |              dbgs() << ") "); | 
 |   // Create a seed transition with an empty PredTerm and the expanded sequences | 
 |   // of SchedWrites for the current SchedClass. | 
 |   std::vector<PredTransition> LastTransitions; | 
 |   LastTransitions.emplace_back(); | 
 |  | 
 |   for (unsigned WriteIdx : OperWrites) { | 
 |     IdxVec WriteSeq; | 
 |     expandRWSequence(WriteIdx, WriteSeq, /*IsRead=*/false); | 
 |     LastTransitions[0].WriteSequences.emplace_back(); | 
 |     SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences.back(); | 
 |     Seq.append(WriteSeq.begin(), WriteSeq.end()); | 
 |     LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); | 
 |   } | 
 |   LLVM_DEBUG(dbgs() << " Reads: "); | 
 |   for (unsigned ReadIdx : OperReads) { | 
 |     IdxVec ReadSeq; | 
 |     expandRWSequence(ReadIdx, ReadSeq, /*IsRead=*/true); | 
 |     LastTransitions[0].ReadSequences.emplace_back(); | 
 |     SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences.back(); | 
 |     Seq.append(ReadSeq.begin(), ReadSeq.end()); | 
 |     LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); | 
 |   } | 
 |   LLVM_DEBUG(dbgs() << '\n'); | 
 |  | 
 |   LastTransitions = makePerProcessorTransitions( | 
 |       LastTransitions[0], llvm::is_contained(ProcIndices, 0) | 
 |                               ? ArrayRef<unsigned>(getAllProcIndices()) | 
 |                               : ProcIndices); | 
 |   // Collect all PredTransitions for individual operands. | 
 |   // Iterate until no variant writes remain. | 
 |   bool SubstitutedAny; | 
 |   do { | 
 |     SubstitutedAny = false; | 
 |     PredTransitions Transitions(*this); | 
 |     for (const PredTransition &Trans : LastTransitions) | 
 |       SubstitutedAny |= Transitions.substituteVariants(Trans); | 
 |     LLVM_DEBUG(Transitions.dump()); | 
 |     LastTransitions.swap(Transitions.TransVec); | 
 |   } while (SubstitutedAny); | 
 |  | 
 |   // WARNING: We are about to mutate the SchedClasses vector. Do not refer to | 
 |   // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions. | 
 |   inferFromTransitions(LastTransitions, FromClassIdx, *this); | 
 | } | 
 |  | 
 | // Check if any processor resource group contains all resource records in | 
 | // SubUnits. | 
 | bool CodeGenSchedModels::hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM) { | 
 |   for (Record *ProcResourceDef : PM.ProcResourceDefs) { | 
 |     if (!ProcResourceDef->isSubClassOf("ProcResGroup")) | 
 |       continue; | 
 |     RecVec SuperUnits = ProcResourceDef->getValueAsListOfDefs("Resources"); | 
 |     RecIter RI = SubUnits.begin(), RE = SubUnits.end(); | 
 |     for ( ; RI != RE; ++RI) { | 
 |       if (!is_contained(SuperUnits, *RI)) { | 
 |         break; | 
 |       } | 
 |     } | 
 |     if (RI == RE) | 
 |       return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | // Verify that overlapping groups have a common supergroup. | 
 | void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) { | 
 |   for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) { | 
 |     if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup")) | 
 |       continue; | 
 |     RecVec CheckUnits = | 
 |       PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources"); | 
 |     for (unsigned j = i+1; j < e; ++j) { | 
 |       if (!PM.ProcResourceDefs[j]->isSubClassOf("ProcResGroup")) | 
 |         continue; | 
 |       RecVec OtherUnits = | 
 |         PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources"); | 
 |       if (std::find_first_of(CheckUnits.begin(), CheckUnits.end(), | 
 |                              OtherUnits.begin(), OtherUnits.end()) | 
 |           != CheckUnits.end()) { | 
 |         // CheckUnits and OtherUnits overlap | 
 |         llvm::append_range(OtherUnits, CheckUnits); | 
 |         if (!hasSuperGroup(OtherUnits, PM)) { | 
 |           PrintFatalError((PM.ProcResourceDefs[i])->getLoc(), | 
 |                           "proc resource group overlaps with " | 
 |                           + PM.ProcResourceDefs[j]->getName() | 
 |                           + " but no supergroup contains both."); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Collect all the RegisterFile definitions available in this target. | 
 | void CodeGenSchedModels::collectRegisterFiles() { | 
 |   RecVec RegisterFileDefs = Records.getAllDerivedDefinitions("RegisterFile"); | 
 |  | 
 |   // RegisterFiles is the vector of CodeGenRegisterFile. | 
 |   for (Record *RF : RegisterFileDefs) { | 
 |     // For each register file definition, construct a CodeGenRegisterFile object | 
 |     // and add it to the appropriate scheduling model. | 
 |     CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel")); | 
 |     PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(),RF)); | 
 |     CodeGenRegisterFile &CGRF = PM.RegisterFiles.back(); | 
 |     CGRF.MaxMovesEliminatedPerCycle = | 
 |         RF->getValueAsInt("MaxMovesEliminatedPerCycle"); | 
 |     CGRF.AllowZeroMoveEliminationOnly = | 
 |         RF->getValueAsBit("AllowZeroMoveEliminationOnly"); | 
 |  | 
 |     // Now set the number of physical registers as well as the cost of registers | 
 |     // in each register class. | 
 |     CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs"); | 
 |     if (!CGRF.NumPhysRegs) { | 
 |       PrintFatalError(RF->getLoc(), | 
 |                       "Invalid RegisterFile with zero physical registers"); | 
 |     } | 
 |  | 
 |     RecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses"); | 
 |     std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts"); | 
 |     ListInit *MoveElimInfo = RF->getValueAsListInit("AllowMoveElimination"); | 
 |     for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) { | 
 |       int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1; | 
 |  | 
 |       bool AllowMoveElim = false; | 
 |       if (MoveElimInfo->size() > I) { | 
 |         BitInit *Val = cast<BitInit>(MoveElimInfo->getElement(I)); | 
 |         AllowMoveElim = Val->getValue(); | 
 |       } | 
 |  | 
 |       CGRF.Costs.emplace_back(RegisterClasses[I], Cost, AllowMoveElim); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Collect and sort WriteRes, ReadAdvance, and ProcResources. | 
 | void CodeGenSchedModels::collectProcResources() { | 
 |   ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits"); | 
 |   ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); | 
 |  | 
 |   // Add any subtarget-specific SchedReadWrites that are directly associated | 
 |   // with processor resources. Refer to the parent SchedClass's ProcIndices to | 
 |   // determine which processors they apply to. | 
 |   for (const CodeGenSchedClass &SC : | 
 |        make_range(schedClassBegin(), schedClassEnd())) { | 
 |     if (SC.ItinClassDef) { | 
 |       collectItinProcResources(SC.ItinClassDef); | 
 |       continue; | 
 |     } | 
 |  | 
 |     // This class may have a default ReadWrite list which can be overriden by | 
 |     // InstRW definitions. | 
 |     for (Record *RW : SC.InstRWs) { | 
 |       Record *RWModelDef = RW->getValueAsDef("SchedModel"); | 
 |       unsigned PIdx = getProcModel(RWModelDef).Index; | 
 |       IdxVec Writes, Reads; | 
 |       findRWs(RW->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); | 
 |       collectRWResources(Writes, Reads, PIdx); | 
 |     } | 
 |  | 
 |     collectRWResources(SC.Writes, SC.Reads, SC.ProcIndices); | 
 |   } | 
 |   // Add resources separately defined by each subtarget. | 
 |   RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes"); | 
 |   for (Record *WR : WRDefs) { | 
 |     Record *ModelDef = WR->getValueAsDef("SchedModel"); | 
 |     addWriteRes(WR, getProcModel(ModelDef).Index); | 
 |   } | 
 |   RecVec SWRDefs = Records.getAllDerivedDefinitions("SchedWriteRes"); | 
 |   for (Record *SWR : SWRDefs) { | 
 |     Record *ModelDef = SWR->getValueAsDef("SchedModel"); | 
 |     addWriteRes(SWR, getProcModel(ModelDef).Index); | 
 |   } | 
 |   RecVec RADefs = Records.getAllDerivedDefinitions("ReadAdvance"); | 
 |   for (Record *RA : RADefs) { | 
 |     Record *ModelDef = RA->getValueAsDef("SchedModel"); | 
 |     addReadAdvance(RA, getProcModel(ModelDef).Index); | 
 |   } | 
 |   RecVec SRADefs = Records.getAllDerivedDefinitions("SchedReadAdvance"); | 
 |   for (Record *SRA : SRADefs) { | 
 |     if (SRA->getValueInit("SchedModel")->isComplete()) { | 
 |       Record *ModelDef = SRA->getValueAsDef("SchedModel"); | 
 |       addReadAdvance(SRA, getProcModel(ModelDef).Index); | 
 |     } | 
 |   } | 
 |   // Add ProcResGroups that are defined within this processor model, which may | 
 |   // not be directly referenced but may directly specify a buffer size. | 
 |   RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); | 
 |   for (Record *PRG : ProcResGroups) { | 
 |     if (!PRG->getValueInit("SchedModel")->isComplete()) | 
 |       continue; | 
 |     CodeGenProcModel &PM = getProcModel(PRG->getValueAsDef("SchedModel")); | 
 |     if (!is_contained(PM.ProcResourceDefs, PRG)) | 
 |       PM.ProcResourceDefs.push_back(PRG); | 
 |   } | 
 |   // Add ProcResourceUnits unconditionally. | 
 |   for (Record *PRU : Records.getAllDerivedDefinitions("ProcResourceUnits")) { | 
 |     if (!PRU->getValueInit("SchedModel")->isComplete()) | 
 |       continue; | 
 |     CodeGenProcModel &PM = getProcModel(PRU->getValueAsDef("SchedModel")); | 
 |     if (!is_contained(PM.ProcResourceDefs, PRU)) | 
 |       PM.ProcResourceDefs.push_back(PRU); | 
 |   } | 
 |   // Finalize each ProcModel by sorting the record arrays. | 
 |   for (CodeGenProcModel &PM : ProcModels) { | 
 |     llvm::sort(PM.WriteResDefs, LessRecord()); | 
 |     llvm::sort(PM.ReadAdvanceDefs, LessRecord()); | 
 |     llvm::sort(PM.ProcResourceDefs, LessRecord()); | 
 |     LLVM_DEBUG( | 
 |         PM.dump(); dbgs() << "WriteResDefs: "; for (auto WriteResDef | 
 |                                                     : PM.WriteResDefs) { | 
 |           if (WriteResDef->isSubClassOf("WriteRes")) | 
 |             dbgs() << WriteResDef->getValueAsDef("WriteType")->getName() << " "; | 
 |           else | 
 |             dbgs() << WriteResDef->getName() << " "; | 
 |         } dbgs() << "\nReadAdvanceDefs: "; | 
 |         for (Record *ReadAdvanceDef | 
 |              : PM.ReadAdvanceDefs) { | 
 |           if (ReadAdvanceDef->isSubClassOf("ReadAdvance")) | 
 |             dbgs() << ReadAdvanceDef->getValueAsDef("ReadType")->getName() | 
 |                    << " "; | 
 |           else | 
 |             dbgs() << ReadAdvanceDef->getName() << " "; | 
 |         } dbgs() | 
 |         << "\nProcResourceDefs: "; | 
 |         for (Record *ProcResourceDef | 
 |              : PM.ProcResourceDefs) { | 
 |           dbgs() << ProcResourceDef->getName() << " "; | 
 |         } dbgs() | 
 |         << '\n'); | 
 |     verifyProcResourceGroups(PM); | 
 |   } | 
 |  | 
 |   ProcResourceDefs.clear(); | 
 |   ProcResGroups.clear(); | 
 | } | 
 |  | 
 | void CodeGenSchedModels::checkCompleteness() { | 
 |   bool Complete = true; | 
 |   for (const CodeGenProcModel &ProcModel : procModels()) { | 
 |     const bool HasItineraries = ProcModel.hasItineraries(); | 
 |     if (!ProcModel.ModelDef->getValueAsBit("CompleteModel")) | 
 |       continue; | 
 |     for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { | 
 |       if (Inst->hasNoSchedulingInfo) | 
 |         continue; | 
 |       if (ProcModel.isUnsupported(*Inst)) | 
 |         continue; | 
 |       unsigned SCIdx = getSchedClassIdx(*Inst); | 
 |       if (!SCIdx) { | 
 |         if (Inst->TheDef->isValueUnset("SchedRW")) { | 
 |           PrintError(Inst->TheDef->getLoc(), | 
 |                      "No schedule information for instruction '" + | 
 |                          Inst->TheDef->getName() + "' in SchedMachineModel '" + | 
 |                      ProcModel.ModelDef->getName() + "'"); | 
 |           Complete = false; | 
 |         } | 
 |         continue; | 
 |       } | 
 |  | 
 |       const CodeGenSchedClass &SC = getSchedClass(SCIdx); | 
 |       if (!SC.Writes.empty()) | 
 |         continue; | 
 |       if (HasItineraries && SC.ItinClassDef != nullptr && | 
 |           SC.ItinClassDef->getName() != "NoItinerary") | 
 |         continue; | 
 |  | 
 |       const RecVec &InstRWs = SC.InstRWs; | 
 |       auto I = find_if(InstRWs, [&ProcModel](const Record *R) { | 
 |         return R->getValueAsDef("SchedModel") == ProcModel.ModelDef; | 
 |       }); | 
 |       if (I == InstRWs.end()) { | 
 |         PrintError(Inst->TheDef->getLoc(), "'" + ProcModel.ModelName + | 
 |                                                "' lacks information for '" + | 
 |                                                Inst->TheDef->getName() + "'"); | 
 |         Complete = false; | 
 |       } | 
 |     } | 
 |   } | 
 |   if (!Complete) { | 
 |     errs() << "\n\nIncomplete schedule models found.\n" | 
 |       << "- Consider setting 'CompleteModel = 0' while developing new models.\n" | 
 |       << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n" | 
 |       << "- Instructions should usually have Sched<[...]> as a superclass, " | 
 |          "you may temporarily use an empty list.\n" | 
 |       << "- Instructions related to unsupported features can be excluded with " | 
 |          "list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the " | 
 |          "processor model.\n\n"; | 
 |     PrintFatalError("Incomplete schedule model"); | 
 |   } | 
 | } | 
 |  | 
 | // Collect itinerary class resources for each processor. | 
 | void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) { | 
 |   for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { | 
 |     const CodeGenProcModel &PM = ProcModels[PIdx]; | 
 |     // For all ItinRW entries. | 
 |     bool HasMatch = false; | 
 |     for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end(); | 
 |          II != IE; ++II) { | 
 |       RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); | 
 |       if (!llvm::is_contained(Matched, ItinClassDef)) | 
 |         continue; | 
 |       if (HasMatch) | 
 |         PrintFatalError((*II)->getLoc(), "Duplicate itinerary class " | 
 |                         + ItinClassDef->getName() | 
 |                         + " in ItinResources for " + PM.ModelName); | 
 |       HasMatch = true; | 
 |       IdxVec Writes, Reads; | 
 |       findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); | 
 |       collectRWResources(Writes, Reads, PIdx); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void CodeGenSchedModels::collectRWResources(unsigned RWIdx, bool IsRead, | 
 |                                             ArrayRef<unsigned> ProcIndices) { | 
 |   const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead); | 
 |   if (SchedRW.TheDef) { | 
 |     if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) { | 
 |       for (unsigned Idx : ProcIndices) | 
 |         addWriteRes(SchedRW.TheDef, Idx); | 
 |     } | 
 |     else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) { | 
 |       for (unsigned Idx : ProcIndices) | 
 |         addReadAdvance(SchedRW.TheDef, Idx); | 
 |     } | 
 |   } | 
 |   for (auto *Alias : SchedRW.Aliases) { | 
 |     IdxVec AliasProcIndices; | 
 |     if (Alias->getValueInit("SchedModel")->isComplete()) { | 
 |       AliasProcIndices.push_back( | 
 |           getProcModel(Alias->getValueAsDef("SchedModel")).Index); | 
 |     } else | 
 |       AliasProcIndices = ProcIndices; | 
 |     const CodeGenSchedRW &AliasRW = getSchedRW(Alias->getValueAsDef("AliasRW")); | 
 |     assert(AliasRW.IsRead == IsRead && "cannot alias reads to writes"); | 
 |  | 
 |     IdxVec ExpandedRWs; | 
 |     expandRWSequence(AliasRW.Index, ExpandedRWs, IsRead); | 
 |     for (unsigned int ExpandedRW : ExpandedRWs) { | 
 |       collectRWResources(ExpandedRW, IsRead, AliasProcIndices); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Collect resources for a set of read/write types and processor indices. | 
 | void CodeGenSchedModels::collectRWResources(ArrayRef<unsigned> Writes, | 
 |                                             ArrayRef<unsigned> Reads, | 
 |                                             ArrayRef<unsigned> ProcIndices) { | 
 |   for (unsigned Idx : Writes) | 
 |     collectRWResources(Idx, /*IsRead=*/false, ProcIndices); | 
 |  | 
 |   for (unsigned Idx : Reads) | 
 |     collectRWResources(Idx, /*IsRead=*/true, ProcIndices); | 
 | } | 
 |  | 
 | // Find the processor's resource units for this kind of resource. | 
 | Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, | 
 |                                              const CodeGenProcModel &PM, | 
 |                                              ArrayRef<SMLoc> Loc) const { | 
 |   if (ProcResKind->isSubClassOf("ProcResourceUnits")) | 
 |     return ProcResKind; | 
 |  | 
 |   Record *ProcUnitDef = nullptr; | 
 |   assert(!ProcResourceDefs.empty()); | 
 |   assert(!ProcResGroups.empty()); | 
 |  | 
 |   for (Record *ProcResDef : ProcResourceDefs) { | 
 |     if (ProcResDef->getValueAsDef("Kind") == ProcResKind | 
 |         && ProcResDef->getValueAsDef("SchedModel") == PM.ModelDef) { | 
 |       if (ProcUnitDef) { | 
 |         PrintFatalError(Loc, | 
 |                         "Multiple ProcessorResourceUnits associated with " | 
 |                         + ProcResKind->getName()); | 
 |       } | 
 |       ProcUnitDef = ProcResDef; | 
 |     } | 
 |   } | 
 |   for (Record *ProcResGroup : ProcResGroups) { | 
 |     if (ProcResGroup == ProcResKind | 
 |         && ProcResGroup->getValueAsDef("SchedModel") == PM.ModelDef) { | 
 |       if (ProcUnitDef) { | 
 |         PrintFatalError(Loc, | 
 |                         "Multiple ProcessorResourceUnits associated with " | 
 |                         + ProcResKind->getName()); | 
 |       } | 
 |       ProcUnitDef = ProcResGroup; | 
 |     } | 
 |   } | 
 |   if (!ProcUnitDef) { | 
 |     PrintFatalError(Loc, | 
 |                     "No ProcessorResources associated with " | 
 |                     + ProcResKind->getName()); | 
 |   } | 
 |   return ProcUnitDef; | 
 | } | 
 |  | 
 | // Iteratively add a resource and its super resources. | 
 | void CodeGenSchedModels::addProcResource(Record *ProcResKind, | 
 |                                          CodeGenProcModel &PM, | 
 |                                          ArrayRef<SMLoc> Loc) { | 
 |   while (true) { | 
 |     Record *ProcResUnits = findProcResUnits(ProcResKind, PM, Loc); | 
 |  | 
 |     // See if this ProcResource is already associated with this processor. | 
 |     if (is_contained(PM.ProcResourceDefs, ProcResUnits)) | 
 |       return; | 
 |  | 
 |     PM.ProcResourceDefs.push_back(ProcResUnits); | 
 |     if (ProcResUnits->isSubClassOf("ProcResGroup")) | 
 |       return; | 
 |  | 
 |     if (!ProcResUnits->getValueInit("Super")->isComplete()) | 
 |       return; | 
 |  | 
 |     ProcResKind = ProcResUnits->getValueAsDef("Super"); | 
 |   } | 
 | } | 
 |  | 
 | // Add resources for a SchedWrite to this processor if they don't exist. | 
 | void CodeGenSchedModels::addWriteRes(Record *ProcWriteResDef, unsigned PIdx) { | 
 |   assert(PIdx && "don't add resources to an invalid Processor model"); | 
 |  | 
 |   RecVec &WRDefs = ProcModels[PIdx].WriteResDefs; | 
 |   if (is_contained(WRDefs, ProcWriteResDef)) | 
 |     return; | 
 |   WRDefs.push_back(ProcWriteResDef); | 
 |  | 
 |   // Visit ProcResourceKinds referenced by the newly discovered WriteRes. | 
 |   RecVec ProcResDefs = ProcWriteResDef->getValueAsListOfDefs("ProcResources"); | 
 |   for (auto *ProcResDef : ProcResDefs) { | 
 |     addProcResource(ProcResDef, ProcModels[PIdx], ProcWriteResDef->getLoc()); | 
 |   } | 
 | } | 
 |  | 
 | // Add resources for a ReadAdvance to this processor if they don't exist. | 
 | void CodeGenSchedModels::addReadAdvance(Record *ProcReadAdvanceDef, | 
 |                                         unsigned PIdx) { | 
 |   RecVec &RADefs = ProcModels[PIdx].ReadAdvanceDefs; | 
 |   if (is_contained(RADefs, ProcReadAdvanceDef)) | 
 |     return; | 
 |   RADefs.push_back(ProcReadAdvanceDef); | 
 | } | 
 |  | 
 | unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const { | 
 |   RecIter PRPos = find(ProcResourceDefs, PRDef); | 
 |   if (PRPos == ProcResourceDefs.end()) | 
 |     PrintFatalError(PRDef->getLoc(), "ProcResource def is not included in " | 
 |                     "the ProcResources list for " + ModelName); | 
 |   // Idx=0 is reserved for invalid. | 
 |   return 1 + (PRPos - ProcResourceDefs.begin()); | 
 | } | 
 |  | 
 | bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const { | 
 |   for (const Record *TheDef : UnsupportedFeaturesDefs) { | 
 |     for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) { | 
 |       if (TheDef->getName() == PredDef->getName()) | 
 |         return true; | 
 |     } | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | #ifndef NDEBUG | 
 | void CodeGenProcModel::dump() const { | 
 |   dbgs() << Index << ": " << ModelName << " " | 
 |          << (ModelDef ? ModelDef->getName() : "inferred") << " " | 
 |          << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n'; | 
 | } | 
 |  | 
 | void CodeGenSchedRW::dump() const { | 
 |   dbgs() << Name << (IsVariadic ? " (V) " : " "); | 
 |   if (IsSequence) { | 
 |     dbgs() << "("; | 
 |     dumpIdxVec(Sequence); | 
 |     dbgs() << ")"; | 
 |   } | 
 | } | 
 |  | 
 | void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { | 
 |   dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n' | 
 |          << "  Writes: "; | 
 |   for (unsigned i = 0, N = Writes.size(); i < N; ++i) { | 
 |     SchedModels->getSchedWrite(Writes[i]).dump(); | 
 |     if (i < N-1) { | 
 |       dbgs() << '\n'; | 
 |       dbgs().indent(10); | 
 |     } | 
 |   } | 
 |   dbgs() << "\n  Reads: "; | 
 |   for (unsigned i = 0, N = Reads.size(); i < N; ++i) { | 
 |     SchedModels->getSchedRead(Reads[i]).dump(); | 
 |     if (i < N-1) { | 
 |       dbgs() << '\n'; | 
 |       dbgs().indent(10); | 
 |     } | 
 |   } | 
 |   dbgs() << "\n  ProcIdx: "; dumpIdxVec(ProcIndices); | 
 |   if (!Transitions.empty()) { | 
 |     dbgs() << "\n Transitions for Proc "; | 
 |     for (const CodeGenSchedTransition &Transition : Transitions) { | 
 |       dbgs() << Transition.ProcIndex << ", "; | 
 |     } | 
 |   } | 
 |   dbgs() << '\n'; | 
 | } | 
 |  | 
 | void PredTransitions::dump() const { | 
 |   dbgs() << "Expanded Variants:\n"; | 
 |   for (const auto &TI : TransVec) { | 
 |     dbgs() << "{"; | 
 |     ListSeparator LS; | 
 |     for (const PredCheck &PC : TI.PredTerm) | 
 |       dbgs() << LS << SchedModels.getSchedRW(PC.RWIdx, PC.IsRead).Name << ":" | 
 |              << PC.Predicate->getName(); | 
 |     dbgs() << "},\n  => {"; | 
 |     for (SmallVectorImpl<SmallVector<unsigned, 4>>::const_iterator | 
 |              WSI = TI.WriteSequences.begin(), | 
 |              WSE = TI.WriteSequences.end(); | 
 |          WSI != WSE; ++WSI) { | 
 |       dbgs() << "("; | 
 |       ListSeparator LS; | 
 |       for (unsigned N : *WSI) | 
 |         dbgs() << LS << SchedModels.getSchedWrite(N).Name; | 
 |       dbgs() << "),"; | 
 |     } | 
 |     dbgs() << "}\n"; | 
 |   } | 
 | } | 
 | #endif // NDEBUG |