|  | //===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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/SmallSet.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 : make_range(Expr->arg_begin(), Expr->arg_end())) { | 
|  | 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 = 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", llvm::make_unique<InstrsOp>()); | 
|  | Sets.addOperator("instregex", llvm::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(); | 
|  |  | 
|  | checkCompleteness(); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Collect optional processor information. | 
|  | void CodeGenSchedModels::collectOptionalProcessorInfo() { | 
|  | // Find register file definitions for each processor. | 
|  | collectRegisterFiles(); | 
|  |  | 
|  | // Collect processor RetireControlUnit descriptors if available. | 
|  | collectRetireControlUnits(); | 
|  |  | 
|  | // Find pfm counter definitions for each processor. | 
|  | collectPfmCounters(); | 
|  |  | 
|  | checkCompleteness(); | 
|  | } | 
|  |  | 
|  | /// Gather all processor models. | 
|  | void CodeGenSchedModels::collectProcModels() { | 
|  | RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor"); | 
|  | llvm::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); | 
|  |  | 
|  | // 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 = 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.begin(), AliasDefs.end(), 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.begin(), SWDefs.end(), LessRecord()); | 
|  | for (Record *SWDef : SWDefs) { | 
|  | assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite"); | 
|  | SchedWrites.emplace_back(SchedWrites.size(), SWDef); | 
|  | } | 
|  | llvm::sort(SRDefs.begin(), SRDefs.end(), 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("("); | 
|  | for (auto I = Seq.begin(), E = Seq.end(); I != E; ++I) { | 
|  | if (I != Seq.begin()) | 
|  | Name += '_'; | 
|  | 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.begin(), InstRWDefs.end(), 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 (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; | 
|  | ++WI) | 
|  | dbgs() << " " << SchedWrites[*WI].Name; | 
|  | for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI) | 
|  | dbgs() << " " << SchedReads[*RI].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 (!std::count(ProcIndices.begin(), ProcIndices.end(), 0)) { | 
|  | for (const CodeGenProcModel &PM : ProcModels) { | 
|  | if (!std::count(ProcIndices.begin(), ProcIndices.end(), 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 = 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; | 
|  | for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) { | 
|  | if (I != InstDefs.begin()) | 
|  | Name += '_'; | 
|  | Name += (*I)->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")) { | 
|  | for (Record *Inst : InstDefs) { | 
|  | PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " + | 
|  | Inst->getName() + " also matches " + | 
|  | RWD->getValue("Instrs")->getValue()->getAsString()); | 
|  | } | 
|  | } | 
|  | } | 
|  | 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) { | 
|  | for (Record *InstDef : InstDefs) { | 
|  | PrintFatalError(OldRWDef->getLoc(), "Overlapping InstRW def " + | 
|  | InstDef->getName() + " also matches " + | 
|  | OldRWDef->getValue("Instrs")->getValue()->getAsString()); | 
|  | } | 
|  | } | 
|  | 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.begin(), ItinRWDefs.end(), 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) { | 
|  | for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) { | 
|  | ProcModel.UnsupportedFeaturesDefs.push_back(Pred); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// 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 (!std::count(Matched.begin(), Matched.end(), 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. | 
|  | } | 
|  | } | 
|  |  | 
|  | 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; | 
|  | SmallVector<unsigned, 4> ProcIndices; | 
|  | }; | 
|  |  | 
|  | // 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) {} | 
|  |  | 
|  | void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq, | 
|  | bool IsRead, unsigned StartIdx); | 
|  |  | 
|  | void substituteVariants(const PredTransition &Trans); | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | void dump() const; | 
|  | #endif | 
|  |  | 
|  | private: | 
|  | bool mutuallyExclusive(Record *PredDef, 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<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; | 
|  | })) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool hasAliasedVariants(const CodeGenSchedRW &RW, | 
|  | CodeGenSchedModels &SchedModels) { | 
|  | if (RW.HasVariants) | 
|  | return true; | 
|  |  | 
|  | for (Record *Alias : RW.Aliases) { | 
|  | const CodeGenSchedRW &AliasRW = | 
|  | SchedModels.getSchedRW(Alias->getValueAsDef("AliasRW")); | 
|  | if (AliasRW.HasVariants) | 
|  | return true; | 
|  | if (AliasRW.IsSequence) { | 
|  | IdxVec ExpandedRWs; | 
|  | SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead); | 
|  | for (unsigned SI : ExpandedRWs) { | 
|  | if (hasAliasedVariants(SchedModels.getSchedRW(SI, AliasRW.IsRead), | 
|  | SchedModels)) | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool hasVariant(ArrayRef<PredTransition> Transitions, | 
|  | CodeGenSchedModels &SchedModels) { | 
|  | for (const PredTransition &PTI : Transitions) { | 
|  | for (const SmallVectorImpl<unsigned> &WSI : PTI.WriteSequences) | 
|  | for (unsigned WI : WSI) | 
|  | if (hasAliasedVariants(SchedModels.getSchedWrite(WI), SchedModels)) | 
|  | return true; | 
|  |  | 
|  | for (const SmallVectorImpl<unsigned> &RSI : PTI.ReadSequences) | 
|  | for (unsigned RI : RSI) | 
|  | if (hasAliasedVariants(SchedModels.getSchedRead(RI), SchedModels)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // 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; | 
|  | } | 
|  | // 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; | 
|  | } | 
|  | 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; | 
|  | } | 
|  | for (TransVariant &Variant : Variants) { | 
|  | // Don't expand variants if the processor models don't intersect. | 
|  | // A zero processor index means any processor. | 
|  | SmallVectorImpl<unsigned> &ProcIndices = TransVec[TransIdx].ProcIndices; | 
|  | if (ProcIndices[0] && Variant.ProcIdx) { | 
|  | unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(), | 
|  | Variant.ProcIdx); | 
|  | if (!Cnt) | 
|  | continue; | 
|  | if (Cnt > 1) { | 
|  | const CodeGenProcModel &PM = | 
|  | *(SchedModels.procModelBegin() + Variant.ProcIdx); | 
|  | PrintFatalError(Variant.VarOrSeqDef->getLoc(), | 
|  | "Multiple variants defined for processor " + | 
|  | PM.ModelName + | 
|  | " Ensure only one SchedAlias exists per RW."); | 
|  | } | 
|  | } | 
|  | if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) { | 
|  | Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate"); | 
|  | if (mutuallyExclusive(PredDef, 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. | 
|  | if (VInfo.ProcIdx != 0) | 
|  | Trans.ProcIndices.assign(1, VInfo.ProcIdx); | 
|  |  | 
|  | 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.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); | 
|  | RWSequences[OperIdx].insert(RWSequences[OperIdx].end(), | 
|  | ExpandedRWs.begin(), ExpandedRWs.end()); | 
|  | } | 
|  | 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 (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end(); | 
|  | RWI != RWE; ++RWI) { | 
|  | if (IsRead) | 
|  | ExpandedRWs.push_back(*RWI); | 
|  | else | 
|  | SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); | 
|  | } | 
|  | Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | void PredTransitions::substituteVariantOperand( | 
|  | const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) { | 
|  |  | 
|  | // Visit each original RW within the current sequence. | 
|  | for (SmallVectorImpl<unsigned>::const_iterator | 
|  | RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) { | 
|  | 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) { | 
|  | // In the common case, push RW onto the current operand's sequence. | 
|  | if (!hasAliasedVariants(SchedRW, SchedModels)) { | 
|  | if (IsRead) | 
|  | TransVec[TransIdx].ReadSequences.back().push_back(*RWI); | 
|  | else | 
|  | TransVec[TransIdx].WriteSequences.back().push_back(*RWI); | 
|  | continue; | 
|  | } | 
|  | // 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 (std::vector<TransVariant>::const_iterator | 
|  | IVI = IntersectingVariants.begin(), | 
|  | IVE = IntersectingVariants.end(); | 
|  | IVI != IVE; ++IVI) { | 
|  | pushVariant(*IVI, IsRead); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | void 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(); | 
|  | TransVec.emplace_back(); | 
|  | TransVec.back().PredTerm = Trans.PredTerm; | 
|  | TransVec.back().ProcIndices = Trans.ProcIndices; | 
|  |  | 
|  | // Visit each original write sequence. | 
|  | for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator | 
|  | WSI = Trans.WriteSequences.begin(), WSE = Trans.WriteSequences.end(); | 
|  | WSI != WSE; ++WSI) { | 
|  | // 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(); | 
|  | } | 
|  | substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx); | 
|  | } | 
|  | // Visit each original read sequence. | 
|  | for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator | 
|  | RSI = Trans.ReadSequences.begin(), RSE = Trans.ReadSequences.end(); | 
|  | RSI != RSE; ++RSI) { | 
|  | // 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(); | 
|  | } | 
|  | substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx); | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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 (ArrayRef<PredTransition>::iterator | 
|  | I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) { | 
|  | IdxVec OperWritesVariant; | 
|  | transform(I->WriteSequences, std::back_inserter(OperWritesVariant), | 
|  | [&SchedModels](ArrayRef<unsigned> WS) { | 
|  | return SchedModels.findOrInsertRW(WS, /*IsRead=*/false); | 
|  | }); | 
|  | IdxVec OperReadsVariant; | 
|  | transform(I->ReadSequences, std::back_inserter(OperReadsVariant), | 
|  | [&SchedModels](ArrayRef<unsigned> RS) { | 
|  | return SchedModels.findOrInsertRW(RS, /*IsRead=*/true); | 
|  | }); | 
|  | CodeGenSchedTransition SCTrans; | 
|  | SCTrans.ToClassIdx = | 
|  | SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant, | 
|  | OperReadsVariant, I->ProcIndices); | 
|  | SCTrans.ProcIndices.assign(I->ProcIndices.begin(), I->ProcIndices.end()); | 
|  | // The final PredTerm is unique set of predicates guarding the transition. | 
|  | RecVec Preds; | 
|  | transform(I->PredTerm, std::back_inserter(Preds), | 
|  | [](const PredCheck &P) { | 
|  | return P.Predicate; | 
|  | }); | 
|  | Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end()); | 
|  | SCTrans.PredTerm = std::move(Preds); | 
|  | SchedModels.getSchedClass(FromClassIdx) | 
|  | .Transitions.push_back(std::move(SCTrans)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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(); | 
|  | LastTransitions.back().ProcIndices.append(ProcIndices.begin(), | 
|  | ProcIndices.end()); | 
|  |  | 
|  | 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'); | 
|  |  | 
|  | // Collect all PredTransitions for individual operands. | 
|  | // Iterate until no variant writes remain. | 
|  | while (hasVariant(LastTransitions, *this)) { | 
|  | PredTransitions Transitions(*this); | 
|  | for (const PredTransition &Trans : LastTransitions) | 
|  | Transitions.substituteVariants(Trans); | 
|  | LLVM_DEBUG(Transitions.dump()); | 
|  | LastTransitions.swap(Transitions.TransVec); | 
|  | } | 
|  | // If the first transition has no variants, nothing to do. | 
|  | if (LastTransitions[0].PredTerm.empty()) | 
|  | return; | 
|  |  | 
|  | // 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 (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) { | 
|  | if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup")) | 
|  | continue; | 
|  | RecVec SuperUnits = | 
|  | PM.ProcResourceDefs[i]->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 | 
|  | OtherUnits.insert(OtherUnits.end(), CheckUnits.begin(), | 
|  | CheckUnits.end()); | 
|  | 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(); | 
|  |  | 
|  | // Now set the number of physical registers as well as the cost of registers | 
|  | // in each register class. | 
|  | CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs"); | 
|  | RecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses"); | 
|  | std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts"); | 
|  | for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) { | 
|  | int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1; | 
|  | CGRF.Costs.emplace_back(RegisterClasses[I], Cost); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Collect all the RegisterFile definitions available in this target. | 
|  | void CodeGenSchedModels::collectPfmCounters() { | 
|  | for (Record *Def : Records.getAllDerivedDefinitions("PfmIssueCounter")) { | 
|  | CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); | 
|  | PM.PfmIssueCounterDefs.emplace_back(Def); | 
|  | } | 
|  | for (Record *Def : Records.getAllDerivedDefinitions("PfmCycleCounter")) { | 
|  | CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); | 
|  | if (PM.PfmCycleCounterDef) { | 
|  | PrintFatalError(Def->getLoc(), | 
|  | "multiple cycle counters for " + | 
|  | Def->getValueAsDef("SchedModel")->getName()); | 
|  | } | 
|  | PM.PfmCycleCounterDef = Def; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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.begin(), PM.WriteResDefs.end(), | 
|  | LessRecord()); | 
|  | llvm::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(), | 
|  | LessRecord()); | 
|  | llvm::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(), | 
|  | LessRecord()); | 
|  | LLVM_DEBUG( | 
|  | PM.dump(); | 
|  | dbgs() << "WriteResDefs: "; for (RecIter RI = PM.WriteResDefs.begin(), | 
|  | RE = PM.WriteResDefs.end(); | 
|  | RI != RE; ++RI) { | 
|  | if ((*RI)->isSubClassOf("WriteRes")) | 
|  | dbgs() << (*RI)->getValueAsDef("WriteType")->getName() << " "; | 
|  | else | 
|  | dbgs() << (*RI)->getName() << " "; | 
|  | } dbgs() << "\nReadAdvanceDefs: "; | 
|  | for (RecIter RI = PM.ReadAdvanceDefs.begin(), | 
|  | RE = PM.ReadAdvanceDefs.end(); | 
|  | RI != RE; ++RI) { | 
|  | if ((*RI)->isSubClassOf("ReadAdvance")) | 
|  | dbgs() << (*RI)->getValueAsDef("ReadType")->getName() << " "; | 
|  | else | 
|  | dbgs() << (*RI)->getName() << " "; | 
|  | } dbgs() | 
|  | << "\nProcResourceDefs: "; | 
|  | for (RecIter RI = PM.ProcResourceDefs.begin(), | 
|  | RE = PM.ProcResourceDefs.end(); | 
|  | RI != RE; ++RI) { dbgs() << (*RI)->getName() << " "; } dbgs() | 
|  | << '\n'); | 
|  | verifyProcResourceGroups(PM); | 
|  | } | 
|  |  | 
|  | ProcResourceDefs.clear(); | 
|  | ProcResGroups.clear(); | 
|  | } | 
|  |  | 
|  | void CodeGenSchedModels::checkCompleteness() { | 
|  | bool Complete = true; | 
|  | bool HadCompleteModel = false; | 
|  | 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") && !HadCompleteModel) { | 
|  | PrintError("No schedule information for instruction '" | 
|  | + Inst->TheDef->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("'" + ProcModel.ModelName + "' lacks information for '" + | 
|  | Inst->TheDef->getName() + "'"); | 
|  | Complete = false; | 
|  | } | 
|  | } | 
|  | HadCompleteModel = true; | 
|  | } | 
|  | 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 (!std::count(Matched.begin(), Matched.end(), 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 (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); | 
|  | AI != AE; ++AI) { | 
|  | IdxVec AliasProcIndices; | 
|  | if ((*AI)->getValueInit("SchedModel")->isComplete()) { | 
|  | AliasProcIndices.push_back( | 
|  | getProcModel((*AI)->getValueAsDef("SchedModel")).Index); | 
|  | } | 
|  | else | 
|  | AliasProcIndices = ProcIndices; | 
|  | const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW")); | 
|  | assert(AliasRW.IsRead == IsRead && "cannot alias reads to writes"); | 
|  |  | 
|  | IdxVec ExpandedRWs; | 
|  | expandRWSequence(AliasRW.Index, ExpandedRWs, IsRead); | 
|  | for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end(); | 
|  | SI != SE; ++SI) { | 
|  | collectRWResources(*SI, 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 (RecIter WritePRI = ProcResDefs.begin(), WritePRE = ProcResDefs.end(); | 
|  | WritePRI != WritePRE; ++WritePRI) { | 
|  | addProcResource(*WritePRI, 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); dbgs() << '\n'; | 
|  | if (!Transitions.empty()) { | 
|  | dbgs() << "\n Transitions for Proc "; | 
|  | for (const CodeGenSchedTransition &Transition : Transitions) { | 
|  | dumpIdxVec(Transition.ProcIndices); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void PredTransitions::dump() const { | 
|  | dbgs() << "Expanded Variants:\n"; | 
|  | for (std::vector<PredTransition>::const_iterator | 
|  | TI = TransVec.begin(), TE = TransVec.end(); TI != TE; ++TI) { | 
|  | dbgs() << "{"; | 
|  | for (SmallVectorImpl<PredCheck>::const_iterator | 
|  | PCI = TI->PredTerm.begin(), PCE = TI->PredTerm.end(); | 
|  | PCI != PCE; ++PCI) { | 
|  | if (PCI != TI->PredTerm.begin()) | 
|  | dbgs() << ", "; | 
|  | dbgs() << SchedModels.getSchedRW(PCI->RWIdx, PCI->IsRead).Name | 
|  | << ":" << PCI->Predicate->getName(); | 
|  | } | 
|  | dbgs() << "},\n  => {"; | 
|  | for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator | 
|  | WSI = TI->WriteSequences.begin(), WSE = TI->WriteSequences.end(); | 
|  | WSI != WSE; ++WSI) { | 
|  | dbgs() << "("; | 
|  | for (SmallVectorImpl<unsigned>::const_iterator | 
|  | WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) { | 
|  | if (WI != WSI->begin()) | 
|  | dbgs() << ", "; | 
|  | dbgs() << SchedModels.getSchedWrite(*WI).Name; | 
|  | } | 
|  | dbgs() << "),"; | 
|  | } | 
|  | dbgs() << "}\n"; | 
|  | } | 
|  | } | 
|  | #endif // NDEBUG |