1fa3d789dSPierre van Houtryve //===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===// 2fa3d789dSPierre van Houtryve // 3fa3d789dSPierre van Houtryve // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fa3d789dSPierre van Houtryve // See https://llvm.org/LICENSE.txt for license information. 5fa3d789dSPierre van Houtryve // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fa3d789dSPierre van Houtryve // 7fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===// 8fa3d789dSPierre van Houtryve // 9fa3d789dSPierre van Houtryve // This file defines structures to encapsulate the machine model as described in 10fa3d789dSPierre van Houtryve // the target description. 11fa3d789dSPierre van Houtryve // 12fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===// 13fa3d789dSPierre van Houtryve 14fa3d789dSPierre van Houtryve #include "CodeGenSchedule.h" 15fa3d789dSPierre van Houtryve #include "CodeGenInstruction.h" 16fa3d789dSPierre van Houtryve #include "CodeGenTarget.h" 178ce5a32fSRahul Joshi #include "Utils.h" 18fa3d789dSPierre van Houtryve #include "llvm/ADT/MapVector.h" 19fa3d789dSPierre van Houtryve #include "llvm/ADT/STLExtras.h" 20fa3d789dSPierre van Houtryve #include "llvm/ADT/SmallPtrSet.h" 21fa3d789dSPierre van Houtryve #include "llvm/ADT/SmallVector.h" 22fa3d789dSPierre van Houtryve #include "llvm/Support/Casting.h" 23fa3d789dSPierre van Houtryve #include "llvm/Support/Debug.h" 24fa3d789dSPierre van Houtryve #include "llvm/Support/Regex.h" 25fa3d789dSPierre van Houtryve #include "llvm/Support/raw_ostream.h" 26fa3d789dSPierre van Houtryve #include "llvm/TableGen/Error.h" 27fa3d789dSPierre van Houtryve #include <algorithm> 28fa3d789dSPierre van Houtryve #include <iterator> 29fa3d789dSPierre van Houtryve #include <utility> 30fa3d789dSPierre van Houtryve 31fa3d789dSPierre van Houtryve using namespace llvm; 32fa3d789dSPierre van Houtryve 33fa3d789dSPierre van Houtryve #define DEBUG_TYPE "subtarget-emitter" 34fa3d789dSPierre van Houtryve 35fa3d789dSPierre van Houtryve #ifndef NDEBUG 36fa3d789dSPierre van Houtryve static void dumpIdxVec(ArrayRef<unsigned> V) { 37fa3d789dSPierre van Houtryve for (unsigned Idx : V) 38fa3d789dSPierre van Houtryve dbgs() << Idx << ", "; 39fa3d789dSPierre van Houtryve } 40fa3d789dSPierre van Houtryve #endif 41fa3d789dSPierre van Houtryve 42fa3d789dSPierre van Houtryve namespace { 43fa3d789dSPierre van Houtryve 44fa3d789dSPierre van Houtryve // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. 45fa3d789dSPierre van Houtryve struct InstrsOp : public SetTheory::Operator { 46d7da79f2SRahul Joshi void apply(SetTheory &ST, const DagInit *Expr, SetTheory::RecSet &Elts, 47fa3d789dSPierre van Houtryve ArrayRef<SMLoc> Loc) override { 48fa3d789dSPierre van Houtryve ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); 49fa3d789dSPierre van Houtryve } 50fa3d789dSPierre van Houtryve }; 51fa3d789dSPierre van Houtryve 52fa3d789dSPierre van Houtryve // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. 53fa3d789dSPierre van Houtryve struct InstRegexOp : public SetTheory::Operator { 54fa3d789dSPierre van Houtryve const CodeGenTarget &Target; 55fa3d789dSPierre van Houtryve InstRegexOp(const CodeGenTarget &t) : Target(t) {} 56fa3d789dSPierre van Houtryve 57fa3d789dSPierre van Houtryve /// Remove any text inside of parentheses from S. 58fa3d789dSPierre van Houtryve static std::string removeParens(llvm::StringRef S) { 59fa3d789dSPierre van Houtryve std::string Result; 60fa3d789dSPierre van Houtryve unsigned Paren = 0; 61fa3d789dSPierre van Houtryve // NB: We don't care about escaped parens here. 62fa3d789dSPierre van Houtryve for (char C : S) { 63fa3d789dSPierre van Houtryve switch (C) { 64fa3d789dSPierre van Houtryve case '(': 65fa3d789dSPierre van Houtryve ++Paren; 66fa3d789dSPierre van Houtryve break; 67fa3d789dSPierre van Houtryve case ')': 68fa3d789dSPierre van Houtryve --Paren; 69fa3d789dSPierre van Houtryve break; 70fa3d789dSPierre van Houtryve default: 71fa3d789dSPierre van Houtryve if (Paren == 0) 72fa3d789dSPierre van Houtryve Result += C; 73fa3d789dSPierre van Houtryve } 74fa3d789dSPierre van Houtryve } 75fa3d789dSPierre van Houtryve return Result; 76fa3d789dSPierre van Houtryve } 77fa3d789dSPierre van Houtryve 78d7da79f2SRahul Joshi void apply(SetTheory &ST, const DagInit *Expr, SetTheory::RecSet &Elts, 79fa3d789dSPierre van Houtryve ArrayRef<SMLoc> Loc) override { 80fa3d789dSPierre van Houtryve ArrayRef<const CodeGenInstruction *> Instructions = 81fa3d789dSPierre van Houtryve Target.getInstructionsByEnumValue(); 82fa3d789dSPierre van Houtryve 83fa3d789dSPierre van Houtryve unsigned NumGeneric = Target.getNumFixedInstructions(); 84fa3d789dSPierre van Houtryve unsigned NumPseudos = Target.getNumPseudoInstructions(); 85fa3d789dSPierre van Houtryve auto Generics = Instructions.slice(0, NumGeneric); 86fa3d789dSPierre van Houtryve auto Pseudos = Instructions.slice(NumGeneric, NumPseudos); 87fa3d789dSPierre van Houtryve auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos); 88fa3d789dSPierre van Houtryve 8962e2c7fbSRahul Joshi for (const Init *Arg : Expr->getArgs()) { 9062e2c7fbSRahul Joshi const StringInit *SI = dyn_cast<StringInit>(Arg); 91fa3d789dSPierre van Houtryve if (!SI) 92fa3d789dSPierre van Houtryve PrintFatalError(Loc, "instregex requires pattern string: " + 93fa3d789dSPierre van Houtryve Expr->getAsString()); 94fa3d789dSPierre van Houtryve StringRef Original = SI->getValue(); 95fa3d789dSPierre van Houtryve // Drop an explicit ^ anchor to not interfere with prefix search. 96fa3d789dSPierre van Houtryve bool HadAnchor = Original.consume_front("^"); 97fa3d789dSPierre van Houtryve 98fa3d789dSPierre van Houtryve // Extract a prefix that we can binary search on. 99fa3d789dSPierre van Houtryve static const char RegexMetachars[] = "()^$|*+?.[]\\{}"; 100fa3d789dSPierre van Houtryve auto FirstMeta = Original.find_first_of(RegexMetachars); 101fa3d789dSPierre van Houtryve if (FirstMeta != StringRef::npos && FirstMeta > 0) { 102fa3d789dSPierre van Houtryve // If we have a regex like ABC* we can only use AB as the prefix, as 103fa3d789dSPierre van Houtryve // the * acts on C. 104fa3d789dSPierre van Houtryve switch (Original[FirstMeta]) { 105fa3d789dSPierre van Houtryve case '+': 106fa3d789dSPierre van Houtryve case '*': 107fa3d789dSPierre van Houtryve case '?': 108fa3d789dSPierre van Houtryve --FirstMeta; 109fa3d789dSPierre van Houtryve break; 110fa3d789dSPierre van Houtryve default: 111fa3d789dSPierre van Houtryve break; 112fa3d789dSPierre van Houtryve } 113fa3d789dSPierre van Houtryve } 114fa3d789dSPierre van Houtryve 115fa3d789dSPierre van Houtryve // Look for top-level | or ?. We cannot optimize them to binary search. 116fa3d789dSPierre van Houtryve if (removeParens(Original).find_first_of("|?") != std::string::npos) 117fa3d789dSPierre van Houtryve FirstMeta = 0; 118fa3d789dSPierre van Houtryve 119fa3d789dSPierre van Houtryve std::optional<Regex> Regexpr; 120fa3d789dSPierre van Houtryve StringRef Prefix = Original.substr(0, FirstMeta); 121fa3d789dSPierre van Houtryve StringRef PatStr = Original.substr(FirstMeta); 122fa3d789dSPierre van Houtryve if (!PatStr.empty()) { 123fa3d789dSPierre van Houtryve // For the rest use a python-style prefix match. 124fa3d789dSPierre van Houtryve std::string pat = std::string(PatStr); 125fa3d789dSPierre van Houtryve // Add ^ anchor. If we had one originally, don't need the group. 126fa3d789dSPierre van Houtryve if (HadAnchor) { 127fa3d789dSPierre van Houtryve pat.insert(0, "^"); 128fa3d789dSPierre van Houtryve } else { 129fa3d789dSPierre van Houtryve pat.insert(0, "^("); 130fa3d789dSPierre van Houtryve pat.insert(pat.end(), ')'); 131fa3d789dSPierre van Houtryve } 132fa3d789dSPierre van Houtryve Regexpr = Regex(pat); 133fa3d789dSPierre van Houtryve } 134fa3d789dSPierre van Houtryve 135fa3d789dSPierre van Houtryve int NumMatches = 0; 136fa3d789dSPierre van Houtryve 137fa3d789dSPierre van Houtryve // The generic opcodes are unsorted, handle them manually. 138fa3d789dSPierre van Houtryve for (auto *Inst : Generics) { 139fa3d789dSPierre van Houtryve StringRef InstName = Inst->TheDef->getName(); 140fa3d789dSPierre van Houtryve if (InstName.starts_with(Prefix) && 141fa3d789dSPierre van Houtryve (!Regexpr || Regexpr->match(InstName.substr(Prefix.size())))) { 142fa3d789dSPierre van Houtryve Elts.insert(Inst->TheDef); 143fa3d789dSPierre van Houtryve NumMatches++; 144fa3d789dSPierre van Houtryve } 145fa3d789dSPierre van Houtryve } 146fa3d789dSPierre van Houtryve 147fa3d789dSPierre van Houtryve // Target instructions are split into two ranges: pseudo instructions 148fa3d789dSPierre van Houtryve // first, than non-pseudos. Each range is in lexicographical order 149fa3d789dSPierre van Houtryve // sorted by name. Find the sub-ranges that start with our prefix. 150fa3d789dSPierre van Houtryve struct Comp { 151fa3d789dSPierre van Houtryve bool operator()(const CodeGenInstruction *LHS, StringRef RHS) { 152fa3d789dSPierre van Houtryve return LHS->TheDef->getName() < RHS; 153fa3d789dSPierre van Houtryve } 154fa3d789dSPierre van Houtryve bool operator()(StringRef LHS, const CodeGenInstruction *RHS) { 155fa3d789dSPierre van Houtryve return LHS < RHS->TheDef->getName() && 156fa3d789dSPierre van Houtryve !RHS->TheDef->getName().starts_with(LHS); 157fa3d789dSPierre van Houtryve } 158fa3d789dSPierre van Houtryve }; 159fa3d789dSPierre van Houtryve auto Range1 = 160fa3d789dSPierre van Houtryve std::equal_range(Pseudos.begin(), Pseudos.end(), Prefix, Comp()); 161fa3d789dSPierre van Houtryve auto Range2 = std::equal_range(NonPseudos.begin(), NonPseudos.end(), 162fa3d789dSPierre van Houtryve Prefix, Comp()); 163fa3d789dSPierre van Houtryve 164fa3d789dSPierre van Houtryve // For these ranges we know that instruction names start with the prefix. 165fa3d789dSPierre van Houtryve // Check if there's a regex that needs to be checked. 166fa3d789dSPierre van Houtryve const auto HandleNonGeneric = [&](const CodeGenInstruction *Inst) { 167fa3d789dSPierre van Houtryve StringRef InstName = Inst->TheDef->getName(); 168fa3d789dSPierre van Houtryve if (!Regexpr || Regexpr->match(InstName.substr(Prefix.size()))) { 169fa3d789dSPierre van Houtryve Elts.insert(Inst->TheDef); 170fa3d789dSPierre van Houtryve NumMatches++; 171fa3d789dSPierre van Houtryve } 172fa3d789dSPierre van Houtryve }; 173fa3d789dSPierre van Houtryve std::for_each(Range1.first, Range1.second, HandleNonGeneric); 174fa3d789dSPierre van Houtryve std::for_each(Range2.first, Range2.second, HandleNonGeneric); 175fa3d789dSPierre van Houtryve 176fa3d789dSPierre van Houtryve if (0 == NumMatches) 177fa3d789dSPierre van Houtryve PrintFatalError(Loc, "instregex has no matches: " + Original); 178fa3d789dSPierre van Houtryve } 179fa3d789dSPierre van Houtryve } 180fa3d789dSPierre van Houtryve }; 181fa3d789dSPierre van Houtryve 182fa3d789dSPierre van Houtryve } // end anonymous namespace 183fa3d789dSPierre van Houtryve 184fa3d789dSPierre van Houtryve /// CodeGenModels ctor interprets machine model records and populates maps. 1853ae71d15SRahul Joshi CodeGenSchedModels::CodeGenSchedModels(const RecordKeeper &RK, 186fa3d789dSPierre van Houtryve const CodeGenTarget &TGT) 187fa3d789dSPierre van Houtryve : Records(RK), Target(TGT) { 188fa3d789dSPierre van Houtryve 189fa3d789dSPierre van Houtryve Sets.addFieldExpander("InstRW", "Instrs"); 190fa3d789dSPierre van Houtryve 191fa3d789dSPierre van Houtryve // Allow Set evaluation to recognize the dags used in InstRW records: 192fa3d789dSPierre van Houtryve // (instrs Op1, Op1...) 193fa3d789dSPierre van Houtryve Sets.addOperator("instrs", std::make_unique<InstrsOp>()); 194fa3d789dSPierre van Houtryve Sets.addOperator("instregex", std::make_unique<InstRegexOp>(Target)); 195fa3d789dSPierre van Houtryve 196fa3d789dSPierre van Houtryve // Instantiate a CodeGenProcModel for each SchedMachineModel with the values 197fa3d789dSPierre van Houtryve // that are explicitly referenced in tablegen records. Resources associated 198fa3d789dSPierre van Houtryve // with each processor will be derived later. Populate ProcModelMap with the 199fa3d789dSPierre van Houtryve // CodeGenProcModel instances. 200fa3d789dSPierre van Houtryve collectProcModels(); 201fa3d789dSPierre van Houtryve 202fa3d789dSPierre van Houtryve // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly 203fa3d789dSPierre van Houtryve // defined, and populate SchedReads and SchedWrites vectors. Implicit 204fa3d789dSPierre van Houtryve // SchedReadWrites that represent sequences derived from expanded variant will 205fa3d789dSPierre van Houtryve // be inferred later. 206fa3d789dSPierre van Houtryve collectSchedRW(); 207fa3d789dSPierre van Houtryve 208fa3d789dSPierre van Houtryve // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly 209fa3d789dSPierre van Houtryve // required by an instruction definition, and populate SchedClassIdxMap. Set 210fa3d789dSPierre van Houtryve // NumItineraryClasses to the number of explicit itinerary classes referenced 211fa3d789dSPierre van Houtryve // by instructions. Set NumInstrSchedClasses to the number of itinerary 212fa3d789dSPierre van Houtryve // classes plus any classes implied by instructions that derive from class 213fa3d789dSPierre van Houtryve // Sched and provide SchedRW list. This does not infer any new classes from 214fa3d789dSPierre van Houtryve // SchedVariant. 215fa3d789dSPierre van Houtryve collectSchedClasses(); 216fa3d789dSPierre van Houtryve 217fa3d789dSPierre van Houtryve // Find instruction itineraries for each processor. Sort and populate 218fa3d789dSPierre van Houtryve // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires 219fa3d789dSPierre van Houtryve // all itinerary classes to be discovered. 220fa3d789dSPierre van Houtryve collectProcItins(); 221fa3d789dSPierre van Houtryve 222fa3d789dSPierre van Houtryve // Find ItinRW records for each processor and itinerary class. 223fa3d789dSPierre van Houtryve // (For per-operand resources mapped to itinerary classes). 224fa3d789dSPierre van Houtryve collectProcItinRW(); 225fa3d789dSPierre van Houtryve 226fa3d789dSPierre van Houtryve // Find UnsupportedFeatures records for each processor. 227fa3d789dSPierre van Houtryve // (For per-operand resources mapped to itinerary classes). 228fa3d789dSPierre van Houtryve collectProcUnsupportedFeatures(); 229fa3d789dSPierre van Houtryve 230fa3d789dSPierre van Houtryve // Infer new SchedClasses from SchedVariant. 231fa3d789dSPierre van Houtryve inferSchedClasses(); 232fa3d789dSPierre van Houtryve 233fa3d789dSPierre van Houtryve // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and 234fa3d789dSPierre van Houtryve // ProcResourceDefs. 235fa3d789dSPierre van Houtryve LLVM_DEBUG( 236fa3d789dSPierre van Houtryve dbgs() << "\n+++ RESOURCE DEFINITIONS (collectProcResources) +++\n"); 237fa3d789dSPierre van Houtryve collectProcResources(); 238fa3d789dSPierre van Houtryve 239fa3d789dSPierre van Houtryve // Collect optional processor description. 240fa3d789dSPierre van Houtryve collectOptionalProcessorInfo(); 241fa3d789dSPierre van Houtryve 242fa3d789dSPierre van Houtryve // Check MCInstPredicate definitions. 243fa3d789dSPierre van Houtryve checkMCInstPredicates(); 244fa3d789dSPierre van Houtryve 245fa3d789dSPierre van Houtryve // Check STIPredicate definitions. 246fa3d789dSPierre van Houtryve checkSTIPredicates(); 247fa3d789dSPierre van Houtryve 248fa3d789dSPierre van Houtryve // Find STIPredicate definitions for each processor model, and construct 249fa3d789dSPierre van Houtryve // STIPredicateFunction objects. 250fa3d789dSPierre van Houtryve collectSTIPredicates(); 251fa3d789dSPierre van Houtryve 252fa3d789dSPierre van Houtryve checkCompleteness(); 253fa3d789dSPierre van Houtryve } 254fa3d789dSPierre van Houtryve 255fa3d789dSPierre van Houtryve void CodeGenSchedModels::checkSTIPredicates() const { 256fa3d789dSPierre van Houtryve DenseMap<StringRef, const Record *> Declarations; 257fa3d789dSPierre van Houtryve 258fa3d789dSPierre van Houtryve // There cannot be multiple declarations with the same name. 2593ae71d15SRahul Joshi for (const Record *R : Records.getAllDerivedDefinitions("STIPredicateDecl")) { 260fa3d789dSPierre van Houtryve StringRef Name = R->getValueAsString("Name"); 26107ff786eSKazu Hirata const auto [It, Inserted] = Declarations.try_emplace(Name, R); 26207ff786eSKazu Hirata if (Inserted) 263fa3d789dSPierre van Houtryve continue; 264fa3d789dSPierre van Houtryve 265fa3d789dSPierre van Houtryve PrintError(R->getLoc(), "STIPredicate " + Name + " multiply declared."); 266fa3d789dSPierre van Houtryve PrintFatalNote(It->second->getLoc(), "Previous declaration was here."); 267fa3d789dSPierre van Houtryve } 268fa3d789dSPierre van Houtryve 269fa3d789dSPierre van Houtryve // Disallow InstructionEquivalenceClasses with an empty instruction list. 2703ae71d15SRahul Joshi for (const Record *R : 2713ae71d15SRahul Joshi Records.getAllDerivedDefinitions("InstructionEquivalenceClass")) { 272c29dfb33SRahul Joshi if (R->getValueAsListOfDefs("Opcodes").empty()) { 273fa3d789dSPierre van Houtryve PrintFatalError(R->getLoc(), "Invalid InstructionEquivalenceClass " 274fa3d789dSPierre van Houtryve "defined with an empty opcode list."); 275fa3d789dSPierre van Houtryve } 276fa3d789dSPierre van Houtryve } 277fa3d789dSPierre van Houtryve } 278fa3d789dSPierre van Houtryve 279fa3d789dSPierre van Houtryve // Used by function `processSTIPredicate` to construct a mask of machine 280fa3d789dSPierre van Houtryve // instruction operands. 281fa3d789dSPierre van Houtryve static APInt constructOperandMask(ArrayRef<int64_t> Indices) { 282fa3d789dSPierre van Houtryve APInt OperandMask; 283fa3d789dSPierre van Houtryve if (Indices.empty()) 284fa3d789dSPierre van Houtryve return OperandMask; 285fa3d789dSPierre van Houtryve 286fa3d789dSPierre van Houtryve int64_t MaxIndex = *llvm::max_element(Indices); 287fa3d789dSPierre van Houtryve assert(MaxIndex >= 0 && "Invalid negative indices in input!"); 288fa3d789dSPierre van Houtryve OperandMask = OperandMask.zext(MaxIndex + 1); 289fa3d789dSPierre van Houtryve for (const int64_t Index : Indices) { 290fa3d789dSPierre van Houtryve assert(Index >= 0 && "Invalid negative indices!"); 291fa3d789dSPierre van Houtryve OperandMask.setBit(Index); 292fa3d789dSPierre van Houtryve } 293fa3d789dSPierre van Houtryve 294fa3d789dSPierre van Houtryve return OperandMask; 295fa3d789dSPierre van Houtryve } 296fa3d789dSPierre van Houtryve 297fa3d789dSPierre van Houtryve static void processSTIPredicate(STIPredicateFunction &Fn, 298fa3d789dSPierre van Houtryve const ProcModelMapTy &ProcModelMap) { 299fa3d789dSPierre van Houtryve DenseMap<const Record *, unsigned> Opcode2Index; 300fa3d789dSPierre van Houtryve using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>; 301fa3d789dSPierre van Houtryve std::vector<OpcodeMapPair> OpcodeMappings; 302fa3d789dSPierre van Houtryve std::vector<std::pair<APInt, APInt>> OpcodeMasks; 303fa3d789dSPierre van Houtryve 304fa3d789dSPierre van Houtryve DenseMap<const Record *, unsigned> Predicate2Index; 305fa3d789dSPierre van Houtryve unsigned NumUniquePredicates = 0; 306fa3d789dSPierre van Houtryve 307fa3d789dSPierre van Houtryve // Number unique predicates and opcodes used by InstructionEquivalenceClass 308fa3d789dSPierre van Houtryve // definitions. Each unique opcode will be associated with an OpcodeInfo 309fa3d789dSPierre van Houtryve // object. 310fa3d789dSPierre van Houtryve for (const Record *Def : Fn.getDefinitions()) { 311a140931bSRahul Joshi ConstRecVec Classes = Def->getValueAsListOfDefs("Classes"); 312fa3d789dSPierre van Houtryve for (const Record *EC : Classes) { 313fa3d789dSPierre van Houtryve const Record *Pred = EC->getValueAsDef("Predicate"); 314818d6e56SKazu Hirata if (Predicate2Index.try_emplace(Pred, NumUniquePredicates).second) 315818d6e56SKazu Hirata ++NumUniquePredicates; 316fa3d789dSPierre van Houtryve 317a140931bSRahul Joshi ConstRecVec Opcodes = EC->getValueAsListOfDefs("Opcodes"); 318fa3d789dSPierre van Houtryve for (const Record *Opcode : Opcodes) { 319818d6e56SKazu Hirata if (Opcode2Index.try_emplace(Opcode, OpcodeMappings.size()).second) 320fa3d789dSPierre van Houtryve OpcodeMappings.emplace_back(Opcode, OpcodeInfo()); 321fa3d789dSPierre van Houtryve } 322fa3d789dSPierre van Houtryve } 323fa3d789dSPierre van Houtryve } 324fa3d789dSPierre van Houtryve 325fa3d789dSPierre van Houtryve // Initialize vector `OpcodeMasks` with default values. We want to keep track 326fa3d789dSPierre van Houtryve // of which processors "use" which opcodes. We also want to be able to 327fa3d789dSPierre van Houtryve // identify predicates that are used by different processors for a same 328fa3d789dSPierre van Houtryve // opcode. 329fa3d789dSPierre van Houtryve // This information is used later on by this algorithm to sort OpcodeMapping 330fa3d789dSPierre van Houtryve // elements based on their processor and predicate sets. 331fa3d789dSPierre van Houtryve OpcodeMasks.resize(OpcodeMappings.size()); 332fa3d789dSPierre van Houtryve APInt DefaultProcMask(ProcModelMap.size(), 0); 333fa3d789dSPierre van Houtryve APInt DefaultPredMask(NumUniquePredicates, 0); 334fa3d789dSPierre van Houtryve for (std::pair<APInt, APInt> &MaskPair : OpcodeMasks) 3354e8c9d28SJay Foad MaskPair = {DefaultProcMask, DefaultPredMask}; 336fa3d789dSPierre van Houtryve 337fa3d789dSPierre van Houtryve // Construct a OpcodeInfo object for every unique opcode declared by an 338fa3d789dSPierre van Houtryve // InstructionEquivalenceClass definition. 339fa3d789dSPierre van Houtryve for (const Record *Def : Fn.getDefinitions()) { 340a140931bSRahul Joshi ConstRecVec Classes = Def->getValueAsListOfDefs("Classes"); 341fa3d789dSPierre van Houtryve const Record *SchedModel = Def->getValueAsDef("SchedModel"); 342fa3d789dSPierre van Houtryve unsigned ProcIndex = ProcModelMap.find(SchedModel)->second; 343fa3d789dSPierre van Houtryve APInt ProcMask(ProcModelMap.size(), 0); 344fa3d789dSPierre van Houtryve ProcMask.setBit(ProcIndex); 345fa3d789dSPierre van Houtryve 346fa3d789dSPierre van Houtryve for (const Record *EC : Classes) { 347a140931bSRahul Joshi ConstRecVec Opcodes = EC->getValueAsListOfDefs("Opcodes"); 348fa3d789dSPierre van Houtryve 349fa3d789dSPierre van Houtryve std::vector<int64_t> OpIndices = 350fa3d789dSPierre van Houtryve EC->getValueAsListOfInts("OperandIndices"); 351fa3d789dSPierre van Houtryve APInt OperandMask = constructOperandMask(OpIndices); 352fa3d789dSPierre van Houtryve 353fa3d789dSPierre van Houtryve const Record *Pred = EC->getValueAsDef("Predicate"); 354fa3d789dSPierre van Houtryve APInt PredMask(NumUniquePredicates, 0); 355fa3d789dSPierre van Houtryve PredMask.setBit(Predicate2Index[Pred]); 356fa3d789dSPierre van Houtryve 357fa3d789dSPierre van Houtryve for (const Record *Opcode : Opcodes) { 358fa3d789dSPierre van Houtryve unsigned OpcodeIdx = Opcode2Index[Opcode]; 359fa3d789dSPierre van Houtryve if (OpcodeMasks[OpcodeIdx].first[ProcIndex]) { 360fa3d789dSPierre van Houtryve std::string Message = 361fa3d789dSPierre van Houtryve "Opcode " + Opcode->getName().str() + 362fa3d789dSPierre van Houtryve " used by multiple InstructionEquivalenceClass definitions."; 363fa3d789dSPierre van Houtryve PrintFatalError(EC->getLoc(), Message); 364fa3d789dSPierre van Houtryve } 365fa3d789dSPierre van Houtryve OpcodeMasks[OpcodeIdx].first |= ProcMask; 366fa3d789dSPierre van Houtryve OpcodeMasks[OpcodeIdx].second |= PredMask; 367fa3d789dSPierre van Houtryve OpcodeInfo &OI = OpcodeMappings[OpcodeIdx].second; 368fa3d789dSPierre van Houtryve 369fa3d789dSPierre van Houtryve OI.addPredicateForProcModel(ProcMask, OperandMask, Pred); 370fa3d789dSPierre van Houtryve } 371fa3d789dSPierre van Houtryve } 372fa3d789dSPierre van Houtryve } 373fa3d789dSPierre van Houtryve 374fa3d789dSPierre van Houtryve // Sort OpcodeMappings elements based on their CPU and predicate masks. 375fa3d789dSPierre van Houtryve // As a last resort, order elements by opcode identifier. 376fa3d789dSPierre van Houtryve llvm::sort( 377fa3d789dSPierre van Houtryve OpcodeMappings, [&](const OpcodeMapPair &Lhs, const OpcodeMapPair &Rhs) { 378fa3d789dSPierre van Houtryve unsigned LhsIdx = Opcode2Index[Lhs.first]; 379fa3d789dSPierre van Houtryve unsigned RhsIdx = Opcode2Index[Rhs.first]; 380fa3d789dSPierre van Houtryve const std::pair<APInt, APInt> &LhsMasks = OpcodeMasks[LhsIdx]; 381fa3d789dSPierre van Houtryve const std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx]; 382fa3d789dSPierre van Houtryve 383fa3d789dSPierre van Houtryve auto PopulationCountAndLeftBit = 384fa3d789dSPierre van Houtryve [](const APInt &Other) -> std::pair<int, int> { 3854e8c9d28SJay Foad return {Other.popcount(), -Other.countl_zero()}; 386fa3d789dSPierre van Houtryve }; 387fa3d789dSPierre van Houtryve auto lhsmask_first = PopulationCountAndLeftBit(LhsMasks.first); 388fa3d789dSPierre van Houtryve auto rhsmask_first = PopulationCountAndLeftBit(RhsMasks.first); 389fa3d789dSPierre van Houtryve if (lhsmask_first != rhsmask_first) 390fa3d789dSPierre van Houtryve return lhsmask_first < rhsmask_first; 391fa3d789dSPierre van Houtryve 392fa3d789dSPierre van Houtryve auto lhsmask_second = PopulationCountAndLeftBit(LhsMasks.second); 393fa3d789dSPierre van Houtryve auto rhsmask_second = PopulationCountAndLeftBit(RhsMasks.second); 394fa3d789dSPierre van Houtryve if (lhsmask_second != rhsmask_second) 395fa3d789dSPierre van Houtryve return lhsmask_second < rhsmask_second; 396fa3d789dSPierre van Houtryve 397fa3d789dSPierre van Houtryve return LhsIdx < RhsIdx; 398fa3d789dSPierre van Houtryve }); 399fa3d789dSPierre van Houtryve 400fa3d789dSPierre van Houtryve // Now construct opcode groups. Groups are used by the SubtargetEmitter when 401fa3d789dSPierre van Houtryve // expanding the body of a STIPredicate function. In particular, each opcode 402fa3d789dSPierre van Houtryve // group is expanded into a sequence of labels in a switch statement. 403fa3d789dSPierre van Houtryve // It identifies opcodes for which different processors define same predicates 404fa3d789dSPierre van Houtryve // and same opcode masks. 405fa3d789dSPierre van Houtryve for (OpcodeMapPair &Info : OpcodeMappings) 406fa3d789dSPierre van Houtryve Fn.addOpcode(Info.first, std::move(Info.second)); 407fa3d789dSPierre van Houtryve } 408fa3d789dSPierre van Houtryve 409fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectSTIPredicates() { 410fa3d789dSPierre van Houtryve // Map STIPredicateDecl records to elements of vector 411fa3d789dSPierre van Houtryve // CodeGenSchedModels::STIPredicates. 412fa3d789dSPierre van Houtryve DenseMap<const Record *, unsigned> Decl2Index; 4133ae71d15SRahul Joshi for (const Record *R : Records.getAllDerivedDefinitions("STIPredicate")) { 414fa3d789dSPierre van Houtryve const Record *Decl = R->getValueAsDef("Declaration"); 415fa3d789dSPierre van Houtryve 41676af93fbSKazu Hirata const auto It = Decl2Index.find(Decl); 41776af93fbSKazu Hirata if (It == Decl2Index.end()) { 41876af93fbSKazu Hirata Decl2Index[Decl] = STIPredicates.size(); 419fa3d789dSPierre van Houtryve STIPredicateFunction Predicate(Decl); 420fa3d789dSPierre van Houtryve Predicate.addDefinition(R); 421fa3d789dSPierre van Houtryve STIPredicates.emplace_back(std::move(Predicate)); 422fa3d789dSPierre van Houtryve continue; 423fa3d789dSPierre van Houtryve } 424fa3d789dSPierre van Houtryve 425fa3d789dSPierre van Houtryve STIPredicateFunction &PreviousDef = STIPredicates[It->second]; 426fa3d789dSPierre van Houtryve PreviousDef.addDefinition(R); 427fa3d789dSPierre van Houtryve } 428fa3d789dSPierre van Houtryve 429fa3d789dSPierre van Houtryve for (STIPredicateFunction &Fn : STIPredicates) 430fa3d789dSPierre van Houtryve processSTIPredicate(Fn, ProcModelMap); 431fa3d789dSPierre van Houtryve } 432fa3d789dSPierre van Houtryve 433fa3d789dSPierre van Houtryve void OpcodeInfo::addPredicateForProcModel(const llvm::APInt &CpuMask, 434fa3d789dSPierre van Houtryve const llvm::APInt &OperandMask, 435fa3d789dSPierre van Houtryve const Record *Predicate) { 436fa3d789dSPierre van Houtryve auto It = llvm::find_if( 437fa3d789dSPierre van Houtryve Predicates, [&OperandMask, &Predicate](const PredicateInfo &P) { 438fa3d789dSPierre van Houtryve return P.Predicate == Predicate && P.OperandMask == OperandMask; 439fa3d789dSPierre van Houtryve }); 440fa3d789dSPierre van Houtryve if (It == Predicates.end()) { 441fa3d789dSPierre van Houtryve Predicates.emplace_back(CpuMask, OperandMask, Predicate); 442fa3d789dSPierre van Houtryve return; 443fa3d789dSPierre van Houtryve } 444fa3d789dSPierre van Houtryve It->ProcModelMask |= CpuMask; 445fa3d789dSPierre van Houtryve } 446fa3d789dSPierre van Houtryve 447fa3d789dSPierre van Houtryve void CodeGenSchedModels::checkMCInstPredicates() const { 448fa3d789dSPierre van Houtryve // A target cannot have multiple TIIPredicate definitions with a same name. 4493ae71d15SRahul Joshi llvm::StringMap<const Record *> TIIPredicates; 4503ae71d15SRahul Joshi for (const Record *TIIPred : 4513ae71d15SRahul Joshi Records.getAllDerivedDefinitions("TIIPredicate")) { 452fa3d789dSPierre van Houtryve StringRef Name = TIIPred->getValueAsString("FunctionName"); 453818d6e56SKazu Hirata auto [It, Inserted] = TIIPredicates.try_emplace(Name, TIIPred); 454818d6e56SKazu Hirata if (Inserted) 455fa3d789dSPierre van Houtryve continue; 456fa3d789dSPierre van Houtryve 457fa3d789dSPierre van Houtryve PrintError(TIIPred->getLoc(), 458fa3d789dSPierre van Houtryve "TIIPredicate " + Name + " is multiply defined."); 459fa3d789dSPierre van Houtryve PrintFatalNote(It->second->getLoc(), 460fa3d789dSPierre van Houtryve " Previous definition of " + Name + " was here."); 461fa3d789dSPierre van Houtryve } 462fa3d789dSPierre van Houtryve } 463fa3d789dSPierre van Houtryve 464fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectRetireControlUnits() { 4653ae71d15SRahul Joshi for (const Record *RCU : 4663ae71d15SRahul Joshi Records.getAllDerivedDefinitions("RetireControlUnit")) { 467fa3d789dSPierre van Houtryve CodeGenProcModel &PM = getProcModel(RCU->getValueAsDef("SchedModel")); 468fa3d789dSPierre van Houtryve if (PM.RetireControlUnit) { 469fa3d789dSPierre van Houtryve PrintError(RCU->getLoc(), 470fa3d789dSPierre van Houtryve "Expected a single RetireControlUnit definition"); 471fa3d789dSPierre van Houtryve PrintNote(PM.RetireControlUnit->getLoc(), 472fa3d789dSPierre van Houtryve "Previous definition of RetireControlUnit was here"); 473fa3d789dSPierre van Houtryve } 474fa3d789dSPierre van Houtryve PM.RetireControlUnit = RCU; 475fa3d789dSPierre van Houtryve } 476fa3d789dSPierre van Houtryve } 477fa3d789dSPierre van Houtryve 478fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectLoadStoreQueueInfo() { 4793ae71d15SRahul Joshi for (const Record *Queue : Records.getAllDerivedDefinitions("MemoryQueue")) { 480fa3d789dSPierre van Houtryve CodeGenProcModel &PM = getProcModel(Queue->getValueAsDef("SchedModel")); 481fa3d789dSPierre van Houtryve if (Queue->isSubClassOf("LoadQueue")) { 482fa3d789dSPierre van Houtryve if (PM.LoadQueue) { 483fa3d789dSPierre van Houtryve PrintError(Queue->getLoc(), "Expected a single LoadQueue definition"); 484fa3d789dSPierre van Houtryve PrintNote(PM.LoadQueue->getLoc(), 485fa3d789dSPierre van Houtryve "Previous definition of LoadQueue was here"); 486fa3d789dSPierre van Houtryve } 487fa3d789dSPierre van Houtryve 488fa3d789dSPierre van Houtryve PM.LoadQueue = Queue; 489fa3d789dSPierre van Houtryve } 490fa3d789dSPierre van Houtryve 491fa3d789dSPierre van Houtryve if (Queue->isSubClassOf("StoreQueue")) { 492fa3d789dSPierre van Houtryve if (PM.StoreQueue) { 493fa3d789dSPierre van Houtryve PrintError(Queue->getLoc(), "Expected a single StoreQueue definition"); 494fa3d789dSPierre van Houtryve PrintNote(PM.StoreQueue->getLoc(), 495fa3d789dSPierre van Houtryve "Previous definition of StoreQueue was here"); 496fa3d789dSPierre van Houtryve } 497fa3d789dSPierre van Houtryve 498fa3d789dSPierre van Houtryve PM.StoreQueue = Queue; 499fa3d789dSPierre van Houtryve } 500fa3d789dSPierre van Houtryve } 501fa3d789dSPierre van Houtryve } 502fa3d789dSPierre van Houtryve 503fa3d789dSPierre van Houtryve /// Collect optional processor information. 504fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectOptionalProcessorInfo() { 505fa3d789dSPierre van Houtryve // Find register file definitions for each processor. 506fa3d789dSPierre van Houtryve collectRegisterFiles(); 507fa3d789dSPierre van Houtryve 508fa3d789dSPierre van Houtryve // Collect processor RetireControlUnit descriptors if available. 509fa3d789dSPierre van Houtryve collectRetireControlUnits(); 510fa3d789dSPierre van Houtryve 511fa3d789dSPierre van Houtryve // Collect information about load/store queues. 512fa3d789dSPierre van Houtryve collectLoadStoreQueueInfo(); 513fa3d789dSPierre van Houtryve 514fa3d789dSPierre van Houtryve checkCompleteness(); 515fa3d789dSPierre van Houtryve } 516fa3d789dSPierre van Houtryve 517fa3d789dSPierre van Houtryve /// Gather all processor models. 518fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectProcModels() { 5193ae71d15SRahul Joshi std::vector<const Record *> ProcRecords = 5203ae71d15SRahul Joshi Records.getAllDerivedDefinitions("Processor"); 521fa3d789dSPierre van Houtryve 5228ce5a32fSRahul Joshi // Sort and check duplicate Processor name. 5238ce5a32fSRahul Joshi sortAndReportDuplicates(ProcRecords, "Processor"); 524fa3d789dSPierre van Houtryve 525fa3d789dSPierre van Houtryve // Reserve space because we can. Reallocation would be ok. 526fa3d789dSPierre van Houtryve ProcModels.reserve(ProcRecords.size() + 1); 527fa3d789dSPierre van Houtryve 528fa3d789dSPierre van Houtryve // Use idx=0 for NoModel/NoItineraries. 529667815ccSRahul Joshi const Record *NoModelDef = Records.getDef("NoSchedModel"); 530667815ccSRahul Joshi const Record *NoItinsDef = Records.getDef("NoItineraries"); 531fa3d789dSPierre van Houtryve ProcModels.emplace_back(0, "NoSchedModel", NoModelDef, NoItinsDef); 532fa3d789dSPierre van Houtryve ProcModelMap[NoModelDef] = 0; 533fa3d789dSPierre van Houtryve 534fa3d789dSPierre van Houtryve // For each processor, find a unique machine model. 535fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "+++ PROCESSOR MODELs (addProcModel) +++\n"); 5363ae71d15SRahul Joshi for (const Record *ProcRecord : ProcRecords) 537fa3d789dSPierre van Houtryve addProcModel(ProcRecord); 538fa3d789dSPierre van Houtryve } 539fa3d789dSPierre van Houtryve 540fa3d789dSPierre van Houtryve /// Get a unique processor model based on the defined MachineModel and 541fa3d789dSPierre van Houtryve /// ProcessorItineraries. 5423ae71d15SRahul Joshi void CodeGenSchedModels::addProcModel(const Record *ProcDef) { 5433ae71d15SRahul Joshi const Record *ModelKey = getModelOrItinDef(ProcDef); 5444e8c9d28SJay Foad if (!ProcModelMap.try_emplace(ModelKey, ProcModels.size()).second) 545fa3d789dSPierre van Houtryve return; 546fa3d789dSPierre van Houtryve 547fa3d789dSPierre van Houtryve std::string Name = std::string(ModelKey->getName()); 548fa3d789dSPierre van Houtryve if (ModelKey->isSubClassOf("SchedMachineModel")) { 549d256b9e8SRahul Joshi const Record *ItinsDef = ModelKey->getValueAsDef("Itineraries"); 550fa3d789dSPierre van Houtryve ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef); 551fa3d789dSPierre van Houtryve } else { 552fa3d789dSPierre van Houtryve // An itinerary is defined without a machine model. Infer a new model. 553fa3d789dSPierre van Houtryve if (!ModelKey->getValueAsListOfDefs("IID").empty()) 554fa3d789dSPierre van Houtryve Name = Name + "Model"; 555fa3d789dSPierre van Houtryve ProcModels.emplace_back(ProcModels.size(), Name, 556fa3d789dSPierre van Houtryve ProcDef->getValueAsDef("SchedModel"), ModelKey); 557fa3d789dSPierre van Houtryve } 558fa3d789dSPierre van Houtryve LLVM_DEBUG(ProcModels.back().dump()); 559fa3d789dSPierre van Houtryve } 560fa3d789dSPierre van Houtryve 561fa3d789dSPierre van Houtryve // Recursively find all reachable SchedReadWrite records. 5623ae71d15SRahul Joshi static void scanSchedRW(const Record *RWDef, ConstRecVec &RWDefs, 5633ae71d15SRahul Joshi SmallPtrSet<const Record *, 16> &RWSet) { 564fa3d789dSPierre van Houtryve if (!RWSet.insert(RWDef).second) 565fa3d789dSPierre van Houtryve return; 566fa3d789dSPierre van Houtryve RWDefs.push_back(RWDef); 567fa3d789dSPierre van Houtryve // Reads don't currently have sequence records, but it can be added later. 568fa3d789dSPierre van Houtryve if (RWDef->isSubClassOf("WriteSequence")) { 5693ae71d15SRahul Joshi for (const Record *WSRec : RWDef->getValueAsListOfDefs("Writes")) 570fa3d789dSPierre van Houtryve scanSchedRW(WSRec, RWDefs, RWSet); 571fa3d789dSPierre van Houtryve } else if (RWDef->isSubClassOf("SchedVariant")) { 572fa3d789dSPierre van Houtryve // Visit each variant (guarded by a different predicate). 5733ae71d15SRahul Joshi for (const Record *Variant : RWDef->getValueAsListOfDefs("Variants")) { 574fa3d789dSPierre van Houtryve // Visit each RW in the sequence selected by the current variant. 575c29dfb33SRahul Joshi for (const Record *SelDef : Variant->getValueAsListOfDefs("Selected")) 576fa3d789dSPierre van Houtryve scanSchedRW(SelDef, RWDefs, RWSet); 577fa3d789dSPierre van Houtryve } 578fa3d789dSPierre van Houtryve } 579fa3d789dSPierre van Houtryve } 580fa3d789dSPierre van Houtryve 581fa3d789dSPierre van Houtryve // Collect and sort all SchedReadWrites reachable via tablegen records. 582fa3d789dSPierre van Houtryve // More may be inferred later when inferring new SchedClasses from variants. 583fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectSchedRW() { 584fa3d789dSPierre van Houtryve // Reserve idx=0 for invalid writes/reads. 585fa3d789dSPierre van Houtryve SchedWrites.resize(1); 586fa3d789dSPierre van Houtryve SchedReads.resize(1); 587fa3d789dSPierre van Houtryve 5883ae71d15SRahul Joshi SmallPtrSet<const Record *, 16> RWSet; 589fa3d789dSPierre van Houtryve 590fa3d789dSPierre van Houtryve // Find all SchedReadWrites referenced by instruction defs. 5913ae71d15SRahul Joshi ConstRecVec SWDefs, SRDefs; 592fa3d789dSPierre van Houtryve for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { 59337865681SRahul Joshi const Record *SchedDef = Inst->TheDef; 594fa3d789dSPierre van Houtryve if (SchedDef->isValueUnset("SchedRW")) 595fa3d789dSPierre van Houtryve continue; 596c29dfb33SRahul Joshi for (const Record *RW : SchedDef->getValueAsListOfDefs("SchedRW")) { 597fa3d789dSPierre van Houtryve if (RW->isSubClassOf("SchedWrite")) 598fa3d789dSPierre van Houtryve scanSchedRW(RW, SWDefs, RWSet); 599fa3d789dSPierre van Houtryve else { 600fa3d789dSPierre van Houtryve assert(RW->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); 601fa3d789dSPierre van Houtryve scanSchedRW(RW, SRDefs, RWSet); 602fa3d789dSPierre van Houtryve } 603fa3d789dSPierre van Houtryve } 604fa3d789dSPierre van Houtryve } 605fa3d789dSPierre van Houtryve // Find all ReadWrites referenced by InstRW. 6063ae71d15SRahul Joshi for (const Record *InstRWDef : Records.getAllDerivedDefinitions("InstRW")) { 607fa3d789dSPierre van Houtryve // For all OperandReadWrites. 608c29dfb33SRahul Joshi for (const Record *RWDef : 609c29dfb33SRahul Joshi InstRWDef->getValueAsListOfDefs("OperandReadWrites")) { 610fa3d789dSPierre van Houtryve if (RWDef->isSubClassOf("SchedWrite")) 611fa3d789dSPierre van Houtryve scanSchedRW(RWDef, SWDefs, RWSet); 612fa3d789dSPierre van Houtryve else { 613fa3d789dSPierre van Houtryve assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); 614fa3d789dSPierre van Houtryve scanSchedRW(RWDef, SRDefs, RWSet); 615fa3d789dSPierre van Houtryve } 616fa3d789dSPierre van Houtryve } 617fa3d789dSPierre van Houtryve } 618fa3d789dSPierre van Houtryve // Find all ReadWrites referenced by ItinRW. 6193ae71d15SRahul Joshi for (const Record *ItinRWDef : Records.getAllDerivedDefinitions("ItinRW")) { 620fa3d789dSPierre van Houtryve // For all OperandReadWrites. 621c29dfb33SRahul Joshi for (const Record *RWDef : 622c29dfb33SRahul Joshi ItinRWDef->getValueAsListOfDefs("OperandReadWrites")) { 623fa3d789dSPierre van Houtryve if (RWDef->isSubClassOf("SchedWrite")) 624fa3d789dSPierre van Houtryve scanSchedRW(RWDef, SWDefs, RWSet); 625fa3d789dSPierre van Houtryve else { 626fa3d789dSPierre van Houtryve assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); 627fa3d789dSPierre van Houtryve scanSchedRW(RWDef, SRDefs, RWSet); 628fa3d789dSPierre van Houtryve } 629fa3d789dSPierre van Houtryve } 630fa3d789dSPierre van Houtryve } 631fa3d789dSPierre van Houtryve // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted 6323ae71d15SRahul Joshi // for the loop below that initializes Alias vectors (which they already 6333ae71d15SRahul Joshi // are by RecordKeeper::getAllDerivedDefinitions). 6343ae71d15SRahul Joshi ArrayRef<const Record *> AliasDefs = 6353ae71d15SRahul Joshi Records.getAllDerivedDefinitions("SchedAlias"); 6363ae71d15SRahul Joshi for (const Record *ADef : AliasDefs) { 6373ae71d15SRahul Joshi const Record *MatchDef = ADef->getValueAsDef("MatchRW"); 6383ae71d15SRahul Joshi const Record *AliasDef = ADef->getValueAsDef("AliasRW"); 639fa3d789dSPierre van Houtryve if (MatchDef->isSubClassOf("SchedWrite")) { 640fa3d789dSPierre van Houtryve if (!AliasDef->isSubClassOf("SchedWrite")) 641fa3d789dSPierre van Houtryve PrintFatalError(ADef->getLoc(), "SchedWrite Alias must be SchedWrite"); 642fa3d789dSPierre van Houtryve scanSchedRW(AliasDef, SWDefs, RWSet); 643fa3d789dSPierre van Houtryve } else { 644fa3d789dSPierre van Houtryve assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); 645fa3d789dSPierre van Houtryve if (!AliasDef->isSubClassOf("SchedRead")) 646fa3d789dSPierre van Houtryve PrintFatalError(ADef->getLoc(), "SchedRead Alias must be SchedRead"); 647fa3d789dSPierre van Houtryve scanSchedRW(AliasDef, SRDefs, RWSet); 648fa3d789dSPierre van Houtryve } 649fa3d789dSPierre van Houtryve } 650fa3d789dSPierre van Houtryve // Sort and add the SchedReadWrites directly referenced by instructions or 651fa3d789dSPierre van Houtryve // itinerary resources. Index reads and writes in separate domains. 652fa3d789dSPierre van Houtryve llvm::sort(SWDefs, LessRecord()); 6533ae71d15SRahul Joshi for (const Record *SWDef : SWDefs) { 654fa3d789dSPierre van Houtryve assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite"); 655fa3d789dSPierre van Houtryve SchedWrites.emplace_back(SchedWrites.size(), SWDef); 656fa3d789dSPierre van Houtryve } 657fa3d789dSPierre van Houtryve llvm::sort(SRDefs, LessRecord()); 6583ae71d15SRahul Joshi for (const Record *SRDef : SRDefs) { 659fa3d789dSPierre van Houtryve assert(!getSchedRWIdx(SRDef, /*IsRead-*/ true) && "duplicate SchedWrite"); 660fa3d789dSPierre van Houtryve SchedReads.emplace_back(SchedReads.size(), SRDef); 661fa3d789dSPierre van Houtryve } 662fa3d789dSPierre van Houtryve // Initialize WriteSequence vectors. 663fa3d789dSPierre van Houtryve for (CodeGenSchedRW &CGRW : SchedWrites) { 664fa3d789dSPierre van Houtryve if (!CGRW.IsSequence) 665fa3d789dSPierre van Houtryve continue; 666a140931bSRahul Joshi findRWs(CGRW.TheDef->getValueAsListOfDefs("Writes"), CGRW.Sequence, 667fa3d789dSPierre van Houtryve /*IsRead=*/false); 668fa3d789dSPierre van Houtryve } 669fa3d789dSPierre van Houtryve // Initialize Aliases vectors. 6703ae71d15SRahul Joshi for (const Record *ADef : AliasDefs) { 671d256b9e8SRahul Joshi const Record *AliasDef = ADef->getValueAsDef("AliasRW"); 672fa3d789dSPierre van Houtryve getSchedRW(AliasDef).IsAlias = true; 673d256b9e8SRahul Joshi const Record *MatchDef = ADef->getValueAsDef("MatchRW"); 674fa3d789dSPierre van Houtryve CodeGenSchedRW &RW = getSchedRW(MatchDef); 675fa3d789dSPierre van Houtryve if (RW.IsAlias) 676fa3d789dSPierre van Houtryve PrintFatalError(ADef->getLoc(), "Cannot Alias an Alias"); 677fa3d789dSPierre van Houtryve RW.Aliases.push_back(ADef); 678fa3d789dSPierre van Houtryve } 679fa3d789dSPierre van Houtryve LLVM_DEBUG( 680fa3d789dSPierre van Houtryve dbgs() << "\n+++ SCHED READS and WRITES (collectSchedRW) +++\n"; 681fa3d789dSPierre van Houtryve for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { 682fa3d789dSPierre van Houtryve dbgs() << WIdx << ": "; 683fa3d789dSPierre van Houtryve SchedWrites[WIdx].dump(); 684fa3d789dSPierre van Houtryve dbgs() << '\n'; 685fa3d789dSPierre van Houtryve } for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; 686fa3d789dSPierre van Houtryve ++RIdx) { 687fa3d789dSPierre van Houtryve dbgs() << RIdx << ": "; 688fa3d789dSPierre van Houtryve SchedReads[RIdx].dump(); 689fa3d789dSPierre van Houtryve dbgs() << '\n'; 6903ae71d15SRahul Joshi } for (const Record *RWDef 6913ae71d15SRahul Joshi : Records.getAllDerivedDefinitions("SchedReadWrite")) { 692fa3d789dSPierre van Houtryve if (!getSchedRWIdx(RWDef, RWDef->isSubClassOf("SchedRead"))) { 693fa3d789dSPierre van Houtryve StringRef Name = RWDef->getName(); 694fa3d789dSPierre van Houtryve if (Name != "NoWrite" && Name != "ReadDefault") 695fa3d789dSPierre van Houtryve dbgs() << "Unused SchedReadWrite " << Name << '\n'; 696fa3d789dSPierre van Houtryve } 697fa3d789dSPierre van Houtryve }); 698fa3d789dSPierre van Houtryve } 699fa3d789dSPierre van Houtryve 700fa3d789dSPierre van Houtryve /// Compute a SchedWrite name from a sequence of writes. 701fa3d789dSPierre van Houtryve std::string CodeGenSchedModels::genRWName(ArrayRef<unsigned> Seq, bool IsRead) { 702fa3d789dSPierre van Houtryve std::string Name("("); 703fa3d789dSPierre van Houtryve ListSeparator LS("_"); 704fa3d789dSPierre van Houtryve for (unsigned I : Seq) { 705fa3d789dSPierre van Houtryve Name += LS; 706fa3d789dSPierre van Houtryve Name += getSchedRW(I, IsRead).Name; 707fa3d789dSPierre van Houtryve } 708fa3d789dSPierre van Houtryve Name += ')'; 709fa3d789dSPierre van Houtryve return Name; 710fa3d789dSPierre van Houtryve } 711fa3d789dSPierre van Houtryve 712fa3d789dSPierre van Houtryve unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def, 713fa3d789dSPierre van Houtryve bool IsRead) const { 714fa3d789dSPierre van Houtryve const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; 715fa3d789dSPierre van Houtryve const auto I = find_if( 716fa3d789dSPierre van Houtryve RWVec, [Def](const CodeGenSchedRW &RW) { return RW.TheDef == Def; }); 717fa3d789dSPierre van Houtryve return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I); 718fa3d789dSPierre van Houtryve } 719fa3d789dSPierre van Houtryve 720c29dfb33SRahul Joshi static void splitSchedReadWrites(const ConstRecVec &RWDefs, 721c29dfb33SRahul Joshi ConstRecVec &WriteDefs, 722c29dfb33SRahul Joshi ConstRecVec &ReadDefs) { 723c29dfb33SRahul Joshi for (const Record *RWDef : RWDefs) { 724fa3d789dSPierre van Houtryve if (RWDef->isSubClassOf("SchedWrite")) 725fa3d789dSPierre van Houtryve WriteDefs.push_back(RWDef); 726fa3d789dSPierre van Houtryve else { 727fa3d789dSPierre van Houtryve assert(RWDef->isSubClassOf("SchedRead") && "unknown SchedReadWrite"); 728fa3d789dSPierre van Houtryve ReadDefs.push_back(RWDef); 729fa3d789dSPierre van Houtryve } 730fa3d789dSPierre van Houtryve } 731fa3d789dSPierre van Houtryve } 732fa3d789dSPierre van Houtryve 733fa3d789dSPierre van Houtryve // Split the SchedReadWrites defs and call findRWs for each list. 734c29dfb33SRahul Joshi void CodeGenSchedModels::findRWs(const ConstRecVec &RWDefs, IdxVec &Writes, 735fa3d789dSPierre van Houtryve IdxVec &Reads) const { 736c29dfb33SRahul Joshi ConstRecVec WriteDefs; 737c29dfb33SRahul Joshi ConstRecVec ReadDefs; 738fa3d789dSPierre van Houtryve splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs); 739fa3d789dSPierre van Houtryve findRWs(WriteDefs, Writes, false); 740fa3d789dSPierre van Houtryve findRWs(ReadDefs, Reads, true); 741fa3d789dSPierre van Houtryve } 742fa3d789dSPierre van Houtryve 743fa3d789dSPierre van Houtryve // Call getSchedRWIdx for all elements in a sequence of SchedRW defs. 744c29dfb33SRahul Joshi void CodeGenSchedModels::findRWs(const ConstRecVec &RWDefs, IdxVec &RWs, 745fa3d789dSPierre van Houtryve bool IsRead) const { 746c29dfb33SRahul Joshi for (const Record *RWDef : RWDefs) { 747fa3d789dSPierre van Houtryve unsigned Idx = getSchedRWIdx(RWDef, IsRead); 748fa3d789dSPierre van Houtryve assert(Idx && "failed to collect SchedReadWrite"); 749fa3d789dSPierre van Houtryve RWs.push_back(Idx); 750fa3d789dSPierre van Houtryve } 751fa3d789dSPierre van Houtryve } 752fa3d789dSPierre van Houtryve 753fa3d789dSPierre van Houtryve void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, 754fa3d789dSPierre van Houtryve bool IsRead) const { 755fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead); 756fa3d789dSPierre van Houtryve if (!SchedRW.IsSequence) { 757fa3d789dSPierre van Houtryve RWSeq.push_back(RWIdx); 758fa3d789dSPierre van Houtryve return; 759fa3d789dSPierre van Houtryve } 760fa3d789dSPierre van Houtryve int Repeat = SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1; 761fa3d789dSPierre van Houtryve for (int i = 0; i < Repeat; ++i) { 762fa3d789dSPierre van Houtryve for (unsigned I : SchedRW.Sequence) { 763fa3d789dSPierre van Houtryve expandRWSequence(I, RWSeq, IsRead); 764fa3d789dSPierre van Houtryve } 765fa3d789dSPierre van Houtryve } 766fa3d789dSPierre van Houtryve } 767fa3d789dSPierre van Houtryve 768fa3d789dSPierre van Houtryve // Expand a SchedWrite as a sequence following any aliases that coincide with 769fa3d789dSPierre van Houtryve // the given processor model. 770fa3d789dSPierre van Houtryve void CodeGenSchedModels::expandRWSeqForProc( 771fa3d789dSPierre van Houtryve unsigned RWIdx, IdxVec &RWSeq, bool IsRead, 772fa3d789dSPierre van Houtryve const CodeGenProcModel &ProcModel) const { 773fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead); 7743ae71d15SRahul Joshi const Record *AliasDef = nullptr; 775fa3d789dSPierre van Houtryve for (const Record *Rec : SchedWrite.Aliases) { 776fa3d789dSPierre van Houtryve const CodeGenSchedRW &AliasRW = getSchedRW(Rec->getValueAsDef("AliasRW")); 777fa3d789dSPierre van Houtryve if (Rec->getValueInit("SchedModel")->isComplete()) { 778d256b9e8SRahul Joshi const Record *ModelDef = Rec->getValueAsDef("SchedModel"); 779fa3d789dSPierre van Houtryve if (&getProcModel(ModelDef) != &ProcModel) 780fa3d789dSPierre van Houtryve continue; 781fa3d789dSPierre van Houtryve } 782fa3d789dSPierre van Houtryve if (AliasDef) 783fa3d789dSPierre van Houtryve PrintFatalError(AliasRW.TheDef->getLoc(), 784fa3d789dSPierre van Houtryve "Multiple aliases " 785fa3d789dSPierre van Houtryve "defined for processor " + 786fa3d789dSPierre van Houtryve ProcModel.ModelName + 787fa3d789dSPierre van Houtryve " Ensure only one SchedAlias exists per RW."); 788fa3d789dSPierre van Houtryve AliasDef = AliasRW.TheDef; 789fa3d789dSPierre van Houtryve } 790fa3d789dSPierre van Houtryve if (AliasDef) { 791fa3d789dSPierre van Houtryve expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead), RWSeq, IsRead, 792fa3d789dSPierre van Houtryve ProcModel); 793fa3d789dSPierre van Houtryve return; 794fa3d789dSPierre van Houtryve } 795fa3d789dSPierre van Houtryve if (!SchedWrite.IsSequence) { 796fa3d789dSPierre van Houtryve RWSeq.push_back(RWIdx); 797fa3d789dSPierre van Houtryve return; 798fa3d789dSPierre van Houtryve } 799fa3d789dSPierre van Houtryve int Repeat = 800fa3d789dSPierre van Houtryve SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1; 801fa3d789dSPierre van Houtryve for (int I = 0, E = Repeat; I < E; ++I) { 802fa3d789dSPierre van Houtryve for (unsigned Idx : SchedWrite.Sequence) { 803fa3d789dSPierre van Houtryve expandRWSeqForProc(Idx, RWSeq, IsRead, ProcModel); 804fa3d789dSPierre van Houtryve } 805fa3d789dSPierre van Houtryve } 806fa3d789dSPierre van Houtryve } 807fa3d789dSPierre van Houtryve 808fa3d789dSPierre van Houtryve /// Add this ReadWrite if it doesn't already exist. 809fa3d789dSPierre van Houtryve unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq, 810fa3d789dSPierre van Houtryve bool IsRead) { 811fa3d789dSPierre van Houtryve assert(!Seq.empty() && "cannot insert empty sequence"); 812fa3d789dSPierre van Houtryve if (Seq.size() == 1) 813fa3d789dSPierre van Houtryve return Seq.back(); 814fa3d789dSPierre van Houtryve 815fa3d789dSPierre van Houtryve std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; 8169cd12b56SCraig Topper 8179cd12b56SCraig Topper auto I = find_if(RWVec, [Seq](CodeGenSchedRW &RW) { 8189cd12b56SCraig Topper return ArrayRef(RW.Sequence) == Seq; 8199cd12b56SCraig Topper }); 8209cd12b56SCraig Topper if (I != RWVec.end()) 8219cd12b56SCraig Topper return std::distance(RWVec.begin(), I); 8229cd12b56SCraig Topper 823fa3d789dSPierre van Houtryve unsigned RWIdx = RWVec.size(); 824fa3d789dSPierre van Houtryve CodeGenSchedRW SchedRW(RWIdx, IsRead, Seq, genRWName(Seq, IsRead)); 825fa3d789dSPierre van Houtryve RWVec.push_back(SchedRW); 826fa3d789dSPierre van Houtryve return RWIdx; 827fa3d789dSPierre van Houtryve } 828fa3d789dSPierre van Houtryve 829fa3d789dSPierre van Houtryve /// Visit all the instruction definitions for this target to gather and 830fa3d789dSPierre van Houtryve /// enumerate the itinerary classes. These are the explicitly specified 831fa3d789dSPierre van Houtryve /// SchedClasses. More SchedClasses may be inferred. 832fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectSchedClasses() { 833fa3d789dSPierre van Houtryve 834fa3d789dSPierre van Houtryve // NoItinerary is always the first class at Idx=0 835fa3d789dSPierre van Houtryve assert(SchedClasses.empty() && "Expected empty sched class"); 836fa3d789dSPierre van Houtryve SchedClasses.emplace_back(0, "NoInstrModel", Records.getDef("NoItinerary")); 837fa3d789dSPierre van Houtryve SchedClasses.back().ProcIndices.push_back(0); 838fa3d789dSPierre van Houtryve 839fa3d789dSPierre van Houtryve // Create a SchedClass for each unique combination of itinerary class and 840fa3d789dSPierre van Houtryve // SchedRW list. 841fa3d789dSPierre van Houtryve for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { 842d256b9e8SRahul Joshi const Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary"); 843fa3d789dSPierre van Houtryve IdxVec Writes, Reads; 844fa3d789dSPierre van Houtryve if (!Inst->TheDef->isValueUnset("SchedRW")) 845a140931bSRahul Joshi findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); 846fa3d789dSPierre van Houtryve 847fa3d789dSPierre van Houtryve // ProcIdx == 0 indicates the class applies to all processors. 848fa3d789dSPierre van Houtryve unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/ {0}); 849fa3d789dSPierre van Houtryve InstrClassMap[Inst->TheDef] = SCIdx; 850fa3d789dSPierre van Houtryve } 851fa3d789dSPierre van Houtryve // Create classes for InstRW defs. 852fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n"); 8533ae71d15SRahul Joshi for (const Record *RWDef : Records.getAllDerivedDefinitions("InstRW")) 854fa3d789dSPierre van Houtryve createInstRWClass(RWDef); 855fa3d789dSPierre van Houtryve 856fa3d789dSPierre van Houtryve NumInstrSchedClasses = SchedClasses.size(); 857fa3d789dSPierre van Houtryve 858fa3d789dSPierre van Houtryve bool EnableDump = false; 859fa3d789dSPierre van Houtryve LLVM_DEBUG(EnableDump = true); 860fa3d789dSPierre van Houtryve if (!EnableDump) 861fa3d789dSPierre van Houtryve return; 862fa3d789dSPierre van Houtryve 863fa3d789dSPierre van Houtryve LLVM_DEBUG( 864fa3d789dSPierre van Houtryve dbgs() 865fa3d789dSPierre van Houtryve << "\n+++ ITINERARIES and/or MACHINE MODELS (collectSchedClasses) +++\n"); 866fa3d789dSPierre van Houtryve for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { 867fa3d789dSPierre van Houtryve StringRef InstName = Inst->TheDef->getName(); 868fa3d789dSPierre van Houtryve unsigned SCIdx = getSchedClassIdx(*Inst); 869fa3d789dSPierre van Houtryve if (!SCIdx) { 870fa3d789dSPierre van Houtryve LLVM_DEBUG({ 871fa3d789dSPierre van Houtryve if (!Inst->hasNoSchedulingInfo) 872fa3d789dSPierre van Houtryve dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n'; 873fa3d789dSPierre van Houtryve }); 874fa3d789dSPierre van Houtryve continue; 875fa3d789dSPierre van Houtryve } 876fa3d789dSPierre van Houtryve CodeGenSchedClass &SC = getSchedClass(SCIdx); 877fa3d789dSPierre van Houtryve if (SC.ProcIndices[0] != 0) 878fa3d789dSPierre van Houtryve PrintFatalError(Inst->TheDef->getLoc(), 879fa3d789dSPierre van Houtryve "Instruction's sched class " 880fa3d789dSPierre van Houtryve "must not be subtarget specific."); 881fa3d789dSPierre van Houtryve 882fa3d789dSPierre van Houtryve IdxVec ProcIndices; 883fa3d789dSPierre van Houtryve if (SC.ItinClassDef->getName() != "NoItinerary") { 884fa3d789dSPierre van Houtryve ProcIndices.push_back(0); 885fa3d789dSPierre van Houtryve dbgs() << "Itinerary for " << InstName << ": " 886fa3d789dSPierre van Houtryve << SC.ItinClassDef->getName() << '\n'; 887fa3d789dSPierre van Houtryve } 888fa3d789dSPierre van Houtryve if (!SC.Writes.empty()) { 889fa3d789dSPierre van Houtryve ProcIndices.push_back(0); 890fa3d789dSPierre van Houtryve LLVM_DEBUG({ 891fa3d789dSPierre van Houtryve dbgs() << "SchedRW machine model for " << InstName; 892fa3d789dSPierre van Houtryve for (unsigned int Write : SC.Writes) 893fa3d789dSPierre van Houtryve dbgs() << " " << SchedWrites[Write].Name; 894fa3d789dSPierre van Houtryve for (unsigned int Read : SC.Reads) 895fa3d789dSPierre van Houtryve dbgs() << " " << SchedReads[Read].Name; 896fa3d789dSPierre van Houtryve dbgs() << '\n'; 897fa3d789dSPierre van Houtryve }); 898fa3d789dSPierre van Houtryve } 8993ae71d15SRahul Joshi for (const Record *RWDef : SchedClasses[SCIdx].InstRWs) { 900fa3d789dSPierre van Houtryve const CodeGenProcModel &ProcModel = 901fa3d789dSPierre van Houtryve getProcModel(RWDef->getValueAsDef("SchedModel")); 902fa3d789dSPierre van Houtryve ProcIndices.push_back(ProcModel.Index); 903fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "InstRW on " << ProcModel.ModelName << " for " 904fa3d789dSPierre van Houtryve << InstName); 905fa3d789dSPierre van Houtryve IdxVec Writes; 906fa3d789dSPierre van Houtryve IdxVec Reads; 907a140931bSRahul Joshi findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); 908fa3d789dSPierre van Houtryve LLVM_DEBUG({ 909fa3d789dSPierre van Houtryve for (unsigned WIdx : Writes) 910fa3d789dSPierre van Houtryve dbgs() << " " << SchedWrites[WIdx].Name; 911fa3d789dSPierre van Houtryve for (unsigned RIdx : Reads) 912fa3d789dSPierre van Houtryve dbgs() << " " << SchedReads[RIdx].Name; 913fa3d789dSPierre van Houtryve dbgs() << '\n'; 914fa3d789dSPierre van Houtryve }); 915fa3d789dSPierre van Houtryve } 916fa3d789dSPierre van Houtryve // If ProcIndices contains zero, the class applies to all processors. 917fa3d789dSPierre van Houtryve LLVM_DEBUG({ 918fa3d789dSPierre van Houtryve if (!llvm::is_contained(ProcIndices, 0)) { 919fa3d789dSPierre van Houtryve for (const CodeGenProcModel &PM : ProcModels) { 920fa3d789dSPierre van Houtryve if (!llvm::is_contained(ProcIndices, PM.Index)) 921fa3d789dSPierre van Houtryve dbgs() << "No machine model for " << Inst->TheDef->getName() 922fa3d789dSPierre van Houtryve << " on processor " << PM.ModelName << '\n'; 923fa3d789dSPierre van Houtryve } 924fa3d789dSPierre van Houtryve } 925fa3d789dSPierre van Houtryve }); 926fa3d789dSPierre van Houtryve } 927fa3d789dSPierre van Houtryve } 928fa3d789dSPierre van Houtryve 929fa3d789dSPierre van Houtryve // Get the SchedClass index for an instruction. 930fa3d789dSPierre van Houtryve unsigned 931fa3d789dSPierre van Houtryve CodeGenSchedModels::getSchedClassIdx(const CodeGenInstruction &Inst) const { 932fa3d789dSPierre van Houtryve return InstrClassMap.lookup(Inst.TheDef); 933fa3d789dSPierre van Houtryve } 934fa3d789dSPierre van Houtryve 935fa3d789dSPierre van Houtryve std::string 936c29dfb33SRahul Joshi CodeGenSchedModels::createSchedClassName(const Record *ItinClassDef, 937fa3d789dSPierre van Houtryve ArrayRef<unsigned> OperWrites, 938fa3d789dSPierre van Houtryve ArrayRef<unsigned> OperReads) { 939fa3d789dSPierre van Houtryve std::string Name; 940fa3d789dSPierre van Houtryve if (ItinClassDef && ItinClassDef->getName() != "NoItinerary") 941fa3d789dSPierre van Houtryve Name = std::string(ItinClassDef->getName()); 942fa3d789dSPierre van Houtryve for (unsigned Idx : OperWrites) { 943fa3d789dSPierre van Houtryve if (!Name.empty()) 944fa3d789dSPierre van Houtryve Name += '_'; 945fa3d789dSPierre van Houtryve Name += SchedWrites[Idx].Name; 946fa3d789dSPierre van Houtryve } 947fa3d789dSPierre van Houtryve for (unsigned Idx : OperReads) { 948fa3d789dSPierre van Houtryve Name += '_'; 949fa3d789dSPierre van Houtryve Name += SchedReads[Idx].Name; 950fa3d789dSPierre van Houtryve } 951fa3d789dSPierre van Houtryve return Name; 952fa3d789dSPierre van Houtryve } 953fa3d789dSPierre van Houtryve 95416510149SRahul Joshi std::string 95516510149SRahul Joshi CodeGenSchedModels::createSchedClassName(const ConstRecVec &InstDefs) { 956fa3d789dSPierre van Houtryve std::string Name; 957fa3d789dSPierre van Houtryve ListSeparator LS("_"); 958fa3d789dSPierre van Houtryve for (const Record *InstDef : InstDefs) { 959fa3d789dSPierre van Houtryve Name += LS; 960fa3d789dSPierre van Houtryve Name += InstDef->getName(); 961fa3d789dSPierre van Houtryve } 962fa3d789dSPierre van Houtryve return Name; 963fa3d789dSPierre van Houtryve } 964fa3d789dSPierre van Houtryve 965fa3d789dSPierre van Houtryve /// Add an inferred sched class from an itinerary class and per-operand list of 966fa3d789dSPierre van Houtryve /// SchedWrites and SchedReads. ProcIndices contains the set of IDs of 967fa3d789dSPierre van Houtryve /// processors that may utilize this class. 968c29dfb33SRahul Joshi unsigned CodeGenSchedModels::addSchedClass(const Record *ItinClassDef, 969fa3d789dSPierre van Houtryve ArrayRef<unsigned> OperWrites, 970fa3d789dSPierre van Houtryve ArrayRef<unsigned> OperReads, 971fa3d789dSPierre van Houtryve ArrayRef<unsigned> ProcIndices) { 972fa3d789dSPierre van Houtryve assert(!ProcIndices.empty() && "expect at least one ProcIdx"); 973fa3d789dSPierre van Houtryve 974fa3d789dSPierre van Houtryve auto IsKeyEqual = [=](const CodeGenSchedClass &SC) { 975fa3d789dSPierre van Houtryve return SC.isKeyEqual(ItinClassDef, OperWrites, OperReads); 976fa3d789dSPierre van Houtryve }; 977fa3d789dSPierre van Houtryve 978bc386a82SCraig Topper auto I = find_if(SchedClasses, IsKeyEqual); 979bc386a82SCraig Topper unsigned Idx = 980bc386a82SCraig Topper I == SchedClasses.end() ? 0 : std::distance(SchedClasses.begin(), I); 981fa3d789dSPierre van Houtryve if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) { 982fa3d789dSPierre van Houtryve IdxVec PI; 983fa3d789dSPierre van Houtryve std::set_union(SchedClasses[Idx].ProcIndices.begin(), 984fa3d789dSPierre van Houtryve SchedClasses[Idx].ProcIndices.end(), ProcIndices.begin(), 985fa3d789dSPierre van Houtryve ProcIndices.end(), std::back_inserter(PI)); 986fa3d789dSPierre van Houtryve SchedClasses[Idx].ProcIndices = std::move(PI); 987fa3d789dSPierre van Houtryve return Idx; 988fa3d789dSPierre van Houtryve } 989fa3d789dSPierre van Houtryve Idx = SchedClasses.size(); 990fa3d789dSPierre van Houtryve SchedClasses.emplace_back( 991fa3d789dSPierre van Houtryve Idx, createSchedClassName(ItinClassDef, OperWrites, OperReads), 992fa3d789dSPierre van Houtryve ItinClassDef); 993fa3d789dSPierre van Houtryve CodeGenSchedClass &SC = SchedClasses.back(); 994fa3d789dSPierre van Houtryve SC.Writes = OperWrites; 995fa3d789dSPierre van Houtryve SC.Reads = OperReads; 996fa3d789dSPierre van Houtryve SC.ProcIndices = ProcIndices; 997fa3d789dSPierre van Houtryve 998fa3d789dSPierre van Houtryve return Idx; 999fa3d789dSPierre van Houtryve } 1000fa3d789dSPierre van Houtryve 1001fa3d789dSPierre van Houtryve // Create classes for each set of opcodes that are in the same InstReadWrite 1002fa3d789dSPierre van Houtryve // definition across all processors. 10033ae71d15SRahul Joshi void CodeGenSchedModels::createInstRWClass(const Record *InstRWDef) { 1004fa3d789dSPierre van Houtryve // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that 1005fa3d789dSPierre van Houtryve // intersects with an existing class via a previous InstRWDef. Instrs that do 1006fa3d789dSPierre van Houtryve // not intersect with an existing class refer back to their former class as 1007fa3d789dSPierre van Houtryve // determined from ItinDef or SchedRW. 100816510149SRahul Joshi SmallMapVector<unsigned, SmallVector<const Record *, 8>, 4> ClassInstrs; 1009fa3d789dSPierre van Houtryve // Sort Instrs into sets. 101016510149SRahul Joshi const ConstRecVec *InstDefs = Sets.expand(InstRWDef); 1011fa3d789dSPierre van Houtryve if (InstDefs->empty()) 1012fa3d789dSPierre van Houtryve PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); 1013fa3d789dSPierre van Houtryve 101416510149SRahul Joshi for (const Record *InstDef : *InstDefs) { 1015fa3d789dSPierre van Houtryve InstClassMapTy::const_iterator Pos = InstrClassMap.find(InstDef); 1016fa3d789dSPierre van Houtryve if (Pos == InstrClassMap.end()) 1017fa3d789dSPierre van Houtryve PrintFatalError(InstDef->getLoc(), "No sched class for instruction."); 1018fa3d789dSPierre van Houtryve unsigned SCIdx = Pos->second; 1019fa3d789dSPierre van Houtryve ClassInstrs[SCIdx].push_back(InstDef); 1020fa3d789dSPierre van Houtryve } 1021fa3d789dSPierre van Houtryve // For each set of Instrs, create a new class if necessary, and map or remap 1022fa3d789dSPierre van Houtryve // the Instrs to it. 1023fa3d789dSPierre van Houtryve for (auto &Entry : ClassInstrs) { 1024fa3d789dSPierre van Houtryve unsigned OldSCIdx = Entry.first; 102516510149SRahul Joshi ArrayRef<const Record *> InstDefs = Entry.second; 1026fa3d789dSPierre van Houtryve // If the all instrs in the current class are accounted for, then leave 1027fa3d789dSPierre van Houtryve // them mapped to their old class. 1028fa3d789dSPierre van Houtryve if (OldSCIdx) { 10293ae71d15SRahul Joshi const ConstRecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs; 1030fa3d789dSPierre van Houtryve if (!RWDefs.empty()) { 103116510149SRahul Joshi const ConstRecVec *OrigInstDefs = Sets.expand(RWDefs[0]); 103216510149SRahul Joshi unsigned OrigNumInstrs = 103316510149SRahul Joshi count_if(*OrigInstDefs, [&](const Record *OIDef) { 1034fa3d789dSPierre van Houtryve return InstrClassMap[OIDef] == OldSCIdx; 1035fa3d789dSPierre van Houtryve }); 1036fa3d789dSPierre van Houtryve if (OrigNumInstrs == InstDefs.size()) { 1037fa3d789dSPierre van Houtryve assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && 1038fa3d789dSPierre van Houtryve "expected a generic SchedClass"); 1039d256b9e8SRahul Joshi const Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); 1040fa3d789dSPierre van Houtryve // Make sure we didn't already have a InstRW containing this 1041fa3d789dSPierre van Houtryve // instruction on this model. 10423ae71d15SRahul Joshi for (const Record *RWD : RWDefs) { 1043fa3d789dSPierre van Houtryve if (RWD->getValueAsDef("SchedModel") == RWModelDef && 1044fa3d789dSPierre van Houtryve RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) { 1045fa3d789dSPierre van Houtryve assert(!InstDefs.empty()); // Checked at function start. 1046fa3d789dSPierre van Houtryve PrintError( 1047fa3d789dSPierre van Houtryve InstRWDef->getLoc(), 1048fa3d789dSPierre van Houtryve "Overlapping InstRW definition for \"" + 1049fa3d789dSPierre van Houtryve InstDefs.front()->getName() + 1050fa3d789dSPierre van Houtryve "\" also matches previous \"" + 1051fa3d789dSPierre van Houtryve RWD->getValue("Instrs")->getValue()->getAsString() + 1052fa3d789dSPierre van Houtryve "\"."); 1053fa3d789dSPierre van Houtryve PrintFatalNote(RWD->getLoc(), "Previous match was here."); 1054fa3d789dSPierre van Houtryve } 1055fa3d789dSPierre van Houtryve } 1056fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" 1057fa3d789dSPierre van Houtryve << SchedClasses[OldSCIdx].Name << " on " 1058fa3d789dSPierre van Houtryve << RWModelDef->getName() << "\n"); 1059fa3d789dSPierre van Houtryve SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef); 1060fa3d789dSPierre van Houtryve continue; 1061fa3d789dSPierre van Houtryve } 1062fa3d789dSPierre van Houtryve } 1063fa3d789dSPierre van Houtryve } 1064fa3d789dSPierre van Houtryve unsigned SCIdx = SchedClasses.size(); 1065fa3d789dSPierre van Houtryve SchedClasses.emplace_back(SCIdx, createSchedClassName(InstDefs), nullptr); 1066fa3d789dSPierre van Houtryve CodeGenSchedClass &SC = SchedClasses.back(); 1067fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on " 1068fa3d789dSPierre van Houtryve << InstRWDef->getValueAsDef("SchedModel")->getName() 1069fa3d789dSPierre van Houtryve << "\n"); 1070fa3d789dSPierre van Houtryve 1071fa3d789dSPierre van Houtryve // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. 1072fa3d789dSPierre van Houtryve SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; 1073fa3d789dSPierre van Houtryve SC.Writes = SchedClasses[OldSCIdx].Writes; 1074fa3d789dSPierre van Houtryve SC.Reads = SchedClasses[OldSCIdx].Reads; 1075fa3d789dSPierre van Houtryve SC.ProcIndices.push_back(0); 1076fa3d789dSPierre van Houtryve // If we had an old class, copy it's InstRWs to this new class. 1077fa3d789dSPierre van Houtryve if (OldSCIdx) { 10783ae71d15SRahul Joshi const Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); 10793ae71d15SRahul Joshi for (const Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) { 1080fa3d789dSPierre van Houtryve if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) { 1081fa3d789dSPierre van Houtryve assert(!InstDefs.empty()); // Checked at function start. 1082fa3d789dSPierre van Houtryve PrintError( 1083fa3d789dSPierre van Houtryve InstRWDef->getLoc(), 1084fa3d789dSPierre van Houtryve "Overlapping InstRW definition for \"" + 1085fa3d789dSPierre van Houtryve InstDefs.front()->getName() + "\" also matches previous \"" + 1086fa3d789dSPierre van Houtryve OldRWDef->getValue("Instrs")->getValue()->getAsString() + 1087fa3d789dSPierre van Houtryve "\"."); 1088fa3d789dSPierre van Houtryve PrintFatalNote(OldRWDef->getLoc(), "Previous match was here."); 1089fa3d789dSPierre van Houtryve } 1090fa3d789dSPierre van Houtryve assert(OldRWDef != InstRWDef && "SchedClass has duplicate InstRW def"); 1091fa3d789dSPierre van Houtryve SC.InstRWs.push_back(OldRWDef); 1092fa3d789dSPierre van Houtryve } 1093fa3d789dSPierre van Houtryve } 1094fa3d789dSPierre van Houtryve // Map each Instr to this new class. 109516510149SRahul Joshi for (const Record *InstDef : InstDefs) 1096fa3d789dSPierre van Houtryve InstrClassMap[InstDef] = SCIdx; 1097fa3d789dSPierre van Houtryve SC.InstRWs.push_back(InstRWDef); 1098fa3d789dSPierre van Houtryve } 1099fa3d789dSPierre van Houtryve } 1100fa3d789dSPierre van Houtryve 1101fa3d789dSPierre van Houtryve // True if collectProcItins found anything. 1102fa3d789dSPierre van Houtryve bool CodeGenSchedModels::hasItineraries() const { 1103bc386a82SCraig Topper for (const CodeGenProcModel &PM : procModels()) 1104fa3d789dSPierre van Houtryve if (PM.hasItineraries()) 1105fa3d789dSPierre van Houtryve return true; 1106fa3d789dSPierre van Houtryve return false; 1107fa3d789dSPierre van Houtryve } 1108fa3d789dSPierre van Houtryve 1109fa3d789dSPierre van Houtryve // Gather the processor itineraries. 1110fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectProcItins() { 1111fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "\n+++ PROBLEM ITINERARIES (collectProcItins) +++\n"); 1112fa3d789dSPierre van Houtryve for (CodeGenProcModel &ProcModel : ProcModels) { 1113fa3d789dSPierre van Houtryve if (!ProcModel.hasItineraries()) 1114fa3d789dSPierre van Houtryve continue; 1115fa3d789dSPierre van Houtryve 1116a140931bSRahul Joshi ConstRecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); 1117fa3d789dSPierre van Houtryve assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect"); 1118fa3d789dSPierre van Houtryve 1119fa3d789dSPierre van Houtryve // Populate ItinDefList with Itinerary records. 1120fa3d789dSPierre van Houtryve ProcModel.ItinDefList.resize(NumInstrSchedClasses); 1121fa3d789dSPierre van Houtryve 1122fa3d789dSPierre van Houtryve // Insert each itinerary data record in the correct position within 1123fa3d789dSPierre van Houtryve // the processor model's ItinDefList. 1124c29dfb33SRahul Joshi for (const Record *ItinData : ItinRecords) { 1125fa3d789dSPierre van Houtryve const Record *ItinDef = ItinData->getValueAsDef("TheClass"); 1126fa3d789dSPierre van Houtryve bool FoundClass = false; 1127fa3d789dSPierre van Houtryve 1128bc386a82SCraig Topper for (const CodeGenSchedClass &SC : schedClasses()) { 1129fa3d789dSPierre van Houtryve // Multiple SchedClasses may share an itinerary. Update all of them. 1130fa3d789dSPierre van Houtryve if (SC.ItinClassDef == ItinDef) { 1131fa3d789dSPierre van Houtryve ProcModel.ItinDefList[SC.Index] = ItinData; 1132fa3d789dSPierre van Houtryve FoundClass = true; 1133fa3d789dSPierre van Houtryve } 1134fa3d789dSPierre van Houtryve } 1135fa3d789dSPierre van Houtryve if (!FoundClass) { 1136fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << ProcModel.ItinsDef->getName() 1137fa3d789dSPierre van Houtryve << " missing class for itinerary " 1138fa3d789dSPierre van Houtryve << ItinDef->getName() << '\n'); 1139fa3d789dSPierre van Houtryve } 1140fa3d789dSPierre van Houtryve } 1141fa3d789dSPierre van Houtryve // Check for missing itinerary entries. 1142fa3d789dSPierre van Houtryve assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); 1143fa3d789dSPierre van Houtryve LLVM_DEBUG( 1144fa3d789dSPierre van Houtryve for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { 1145fa3d789dSPierre van Houtryve if (!ProcModel.ItinDefList[i]) 1146fa3d789dSPierre van Houtryve dbgs() << ProcModel.ItinsDef->getName() 1147fa3d789dSPierre van Houtryve << " missing itinerary for class " << SchedClasses[i].Name 1148fa3d789dSPierre van Houtryve << '\n'; 1149fa3d789dSPierre van Houtryve }); 1150fa3d789dSPierre van Houtryve } 1151fa3d789dSPierre van Houtryve } 1152fa3d789dSPierre van Houtryve 1153fa3d789dSPierre van Houtryve // Gather the read/write types for each itinerary class. 1154fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectProcItinRW() { 11553ae71d15SRahul Joshi for (const Record *RWDef : Records.getAllDerivedDefinitions("ItinRW")) { 1156fa3d789dSPierre van Houtryve if (!RWDef->getValueInit("SchedModel")->isComplete()) 1157fa3d789dSPierre van Houtryve PrintFatalError(RWDef->getLoc(), "SchedModel is undefined"); 11583ae71d15SRahul Joshi const Record *ModelDef = RWDef->getValueAsDef("SchedModel"); 1159fa3d789dSPierre van Houtryve ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef); 1160fa3d789dSPierre van Houtryve if (I == ProcModelMap.end()) { 1161fa3d789dSPierre van Houtryve PrintFatalError(RWDef->getLoc(), 1162fa3d789dSPierre van Houtryve "Undefined SchedMachineModel " + ModelDef->getName()); 1163fa3d789dSPierre van Houtryve } 1164fa3d789dSPierre van Houtryve ProcModels[I->second].ItinRWDefs.push_back(RWDef); 1165fa3d789dSPierre van Houtryve } 1166fa3d789dSPierre van Houtryve } 1167fa3d789dSPierre van Houtryve 1168fa3d789dSPierre van Houtryve // Gather the unsupported features for processor models. 1169fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectProcUnsupportedFeatures() { 1170fa3d789dSPierre van Houtryve for (CodeGenProcModel &ProcModel : ProcModels) 1171fa3d789dSPierre van Houtryve append_range( 1172fa3d789dSPierre van Houtryve ProcModel.UnsupportedFeaturesDefs, 1173fa3d789dSPierre van Houtryve ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")); 1174fa3d789dSPierre van Houtryve } 1175fa3d789dSPierre van Houtryve 1176fa3d789dSPierre van Houtryve /// Infer new classes from existing classes. In the process, this may create new 1177fa3d789dSPierre van Houtryve /// SchedWrites from sequences of existing SchedWrites. 1178fa3d789dSPierre van Houtryve void CodeGenSchedModels::inferSchedClasses() { 1179fa3d789dSPierre van Houtryve LLVM_DEBUG( 1180fa3d789dSPierre van Houtryve dbgs() << "\n+++ INFERRING SCHED CLASSES (inferSchedClasses) +++\n"); 1181fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n"); 1182fa3d789dSPierre van Houtryve 1183fa3d789dSPierre van Houtryve // Visit all existing classes and newly created classes. 1184fa3d789dSPierre van Houtryve for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { 1185fa3d789dSPierre van Houtryve assert(SchedClasses[Idx].Index == Idx && "bad SCIdx"); 1186fa3d789dSPierre van Houtryve 1187fa3d789dSPierre van Houtryve if (SchedClasses[Idx].ItinClassDef) 1188fa3d789dSPierre van Houtryve inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx); 1189fa3d789dSPierre van Houtryve if (!SchedClasses[Idx].InstRWs.empty()) 1190fa3d789dSPierre van Houtryve inferFromInstRWs(Idx); 1191fa3d789dSPierre van Houtryve if (!SchedClasses[Idx].Writes.empty()) { 1192fa3d789dSPierre van Houtryve inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, Idx, 1193fa3d789dSPierre van Houtryve SchedClasses[Idx].ProcIndices); 1194fa3d789dSPierre van Houtryve } 1195fa3d789dSPierre van Houtryve assert(SchedClasses.size() < (NumInstrSchedClasses * 6) && 1196fa3d789dSPierre van Houtryve "too many SchedVariants"); 1197fa3d789dSPierre van Houtryve } 1198fa3d789dSPierre van Houtryve } 1199fa3d789dSPierre van Houtryve 1200fa3d789dSPierre van Houtryve /// Infer classes from per-processor itinerary resources. 1201c29dfb33SRahul Joshi void CodeGenSchedModels::inferFromItinClass(const Record *ItinClassDef, 1202fa3d789dSPierre van Houtryve unsigned FromClassIdx) { 1203fa3d789dSPierre van Houtryve for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { 1204fa3d789dSPierre van Houtryve const CodeGenProcModel &PM = ProcModels[PIdx]; 1205fa3d789dSPierre van Houtryve // For all ItinRW entries. 1206fa3d789dSPierre van Houtryve bool HasMatch = false; 1207fa3d789dSPierre van Houtryve for (const Record *Rec : PM.ItinRWDefs) { 1208a140931bSRahul Joshi ConstRecVec Matched = Rec->getValueAsListOfDefs("MatchedItinClasses"); 1209fa3d789dSPierre van Houtryve if (!llvm::is_contained(Matched, ItinClassDef)) 1210fa3d789dSPierre van Houtryve continue; 1211fa3d789dSPierre van Houtryve if (HasMatch) 1212fa3d789dSPierre van Houtryve PrintFatalError(Rec->getLoc(), 1213fa3d789dSPierre van Houtryve "Duplicate itinerary class " + ItinClassDef->getName() + 1214fa3d789dSPierre van Houtryve " in ItinResources for " + PM.ModelName); 1215fa3d789dSPierre van Houtryve HasMatch = true; 1216fa3d789dSPierre van Houtryve IdxVec Writes, Reads; 1217a140931bSRahul Joshi findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); 1218fa3d789dSPierre van Houtryve inferFromRW(Writes, Reads, FromClassIdx, PIdx); 1219fa3d789dSPierre van Houtryve } 1220fa3d789dSPierre van Houtryve } 1221fa3d789dSPierre van Houtryve } 1222fa3d789dSPierre van Houtryve 1223fa3d789dSPierre van Houtryve /// Infer classes from per-processor InstReadWrite definitions. 1224fa3d789dSPierre van Houtryve void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) { 1225fa3d789dSPierre van Houtryve for (unsigned I = 0, E = SchedClasses[SCIdx].InstRWs.size(); I != E; ++I) { 1226fa3d789dSPierre van Houtryve assert(SchedClasses[SCIdx].InstRWs.size() == E && "InstrRWs was mutated!"); 12273ae71d15SRahul Joshi const Record *Rec = SchedClasses[SCIdx].InstRWs[I]; 122816510149SRahul Joshi const std::vector<const Record *> *InstDefs = Sets.expand(Rec); 122916510149SRahul Joshi ConstRecIter II = InstDefs->begin(), IE = InstDefs->end(); 1230fa3d789dSPierre van Houtryve for (; II != IE; ++II) { 1231fa3d789dSPierre van Houtryve if (InstrClassMap[*II] == SCIdx) 1232fa3d789dSPierre van Houtryve break; 1233fa3d789dSPierre van Houtryve } 1234fa3d789dSPierre van Houtryve // If this class no longer has any instructions mapped to it, it has become 1235fa3d789dSPierre van Houtryve // irrelevant. 1236fa3d789dSPierre van Houtryve if (II == IE) 1237fa3d789dSPierre van Houtryve continue; 1238fa3d789dSPierre van Houtryve IdxVec Writes, Reads; 1239a140931bSRahul Joshi findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); 1240fa3d789dSPierre van Houtryve unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index; 1241fa3d789dSPierre van Houtryve inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses. 1242fa3d789dSPierre van Houtryve SchedClasses[SCIdx].InstRWProcIndices.insert(PIdx); 1243fa3d789dSPierre van Houtryve } 1244fa3d789dSPierre van Houtryve } 1245fa3d789dSPierre van Houtryve 1246fa3d789dSPierre van Houtryve namespace { 1247fa3d789dSPierre van Houtryve 1248fa3d789dSPierre van Houtryve // Helper for substituteVariantOperand. 1249fa3d789dSPierre van Houtryve struct TransVariant { 12503ae71d15SRahul Joshi const Record *VarOrSeqDef; // Variant or sequence. 1251fa3d789dSPierre van Houtryve unsigned RWIdx; // Index of this variant or sequence's matched type. 1252fa3d789dSPierre van Houtryve unsigned ProcIdx; // Processor model index or zero for any. 1253fa3d789dSPierre van Houtryve unsigned TransVecIdx; // Index into PredTransitions::TransVec. 1254fa3d789dSPierre van Houtryve 12553ae71d15SRahul Joshi TransVariant(const Record *def, unsigned rwi, unsigned pi, unsigned ti) 1256fa3d789dSPierre van Houtryve : VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {} 1257fa3d789dSPierre van Houtryve }; 1258fa3d789dSPierre van Houtryve 1259fa3d789dSPierre van Houtryve // Associate a predicate with the SchedReadWrite that it guards. 1260fa3d789dSPierre van Houtryve // RWIdx is the index of the read/write variant. 1261fa3d789dSPierre van Houtryve struct PredCheck { 1262fa3d789dSPierre van Houtryve bool IsRead; 1263fa3d789dSPierre van Houtryve unsigned RWIdx; 12643ae71d15SRahul Joshi const Record *Predicate; 1265fa3d789dSPierre van Houtryve 1266d256b9e8SRahul Joshi PredCheck(bool r, unsigned w, const Record *p) 1267fa3d789dSPierre van Houtryve : IsRead(r), RWIdx(w), Predicate(p) {} 1268fa3d789dSPierre van Houtryve }; 1269fa3d789dSPierre van Houtryve 1270fa3d789dSPierre van Houtryve // A Predicate transition is a list of RW sequences guarded by a PredTerm. 1271fa3d789dSPierre van Houtryve struct PredTransition { 1272fa3d789dSPierre van Houtryve // A predicate term is a conjunction of PredChecks. 1273fa3d789dSPierre van Houtryve SmallVector<PredCheck, 4> PredTerm; 1274fa3d789dSPierre van Houtryve SmallVector<SmallVector<unsigned, 4>, 16> WriteSequences; 1275fa3d789dSPierre van Houtryve SmallVector<SmallVector<unsigned, 4>, 16> ReadSequences; 1276fa3d789dSPierre van Houtryve unsigned ProcIndex = 0; 1277fa3d789dSPierre van Houtryve 1278fa3d789dSPierre van Houtryve PredTransition() = default; 1279fa3d789dSPierre van Houtryve PredTransition(ArrayRef<PredCheck> PT, unsigned ProcId) { 1280fa3d789dSPierre van Houtryve PredTerm.assign(PT.begin(), PT.end()); 1281fa3d789dSPierre van Houtryve ProcIndex = ProcId; 1282fa3d789dSPierre van Houtryve } 1283fa3d789dSPierre van Houtryve }; 1284fa3d789dSPierre van Houtryve 1285fa3d789dSPierre van Houtryve // Encapsulate a set of partially constructed transitions. 1286fa3d789dSPierre van Houtryve // The results are built by repeated calls to substituteVariants. 1287fa3d789dSPierre van Houtryve class PredTransitions { 1288fa3d789dSPierre van Houtryve CodeGenSchedModels &SchedModels; 1289fa3d789dSPierre van Houtryve 1290fa3d789dSPierre van Houtryve public: 1291fa3d789dSPierre van Houtryve std::vector<PredTransition> TransVec; 1292fa3d789dSPierre van Houtryve 1293fa3d789dSPierre van Houtryve PredTransitions(CodeGenSchedModels &sm) : SchedModels(sm) {} 1294fa3d789dSPierre van Houtryve 1295fa3d789dSPierre van Houtryve bool substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq, 1296fa3d789dSPierre van Houtryve bool IsRead, unsigned StartIdx); 1297fa3d789dSPierre van Houtryve 1298fa3d789dSPierre van Houtryve bool substituteVariants(const PredTransition &Trans); 1299fa3d789dSPierre van Houtryve 1300fa3d789dSPierre van Houtryve #ifndef NDEBUG 1301fa3d789dSPierre van Houtryve void dump() const; 1302fa3d789dSPierre van Houtryve #endif 1303fa3d789dSPierre van Houtryve 1304fa3d789dSPierre van Houtryve private: 1305d256b9e8SRahul Joshi bool mutuallyExclusive(const Record *PredDef, ArrayRef<const Record *> Preds, 1306fa3d789dSPierre van Houtryve ArrayRef<PredCheck> Term); 1307fa3d789dSPierre van Houtryve void getIntersectingVariants(const CodeGenSchedRW &SchedRW, unsigned TransIdx, 1308fa3d789dSPierre van Houtryve std::vector<TransVariant> &IntersectingVariants); 1309fa3d789dSPierre van Houtryve void pushVariant(const TransVariant &VInfo, bool IsRead); 1310fa3d789dSPierre van Houtryve }; 1311fa3d789dSPierre van Houtryve 1312fa3d789dSPierre van Houtryve } // end anonymous namespace 1313fa3d789dSPierre van Houtryve 1314fa3d789dSPierre van Houtryve // Return true if this predicate is mutually exclusive with a PredTerm. This 1315fa3d789dSPierre van Houtryve // degenerates into checking if the predicate is mutually exclusive with any 1316fa3d789dSPierre van Houtryve // predicate in the Term's conjunction. 1317fa3d789dSPierre van Houtryve // 1318fa3d789dSPierre van Houtryve // All predicates associated with a given SchedRW are considered mutually 1319fa3d789dSPierre van Houtryve // exclusive. This should work even if the conditions expressed by the 1320fa3d789dSPierre van Houtryve // predicates are not exclusive because the predicates for a given SchedWrite 1321fa3d789dSPierre van Houtryve // are always checked in the order they are defined in the .td file. Later 1322fa3d789dSPierre van Houtryve // conditions implicitly negate any prior condition. 1323d256b9e8SRahul Joshi bool PredTransitions::mutuallyExclusive(const Record *PredDef, 1324d256b9e8SRahul Joshi ArrayRef<const Record *> Preds, 1325fa3d789dSPierre van Houtryve ArrayRef<PredCheck> Term) { 1326fa3d789dSPierre van Houtryve for (const PredCheck &PC : Term) { 1327fa3d789dSPierre van Houtryve if (PC.Predicate == PredDef) 1328fa3d789dSPierre van Houtryve return false; 1329fa3d789dSPierre van Houtryve 1330fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(PC.RWIdx, PC.IsRead); 1331fa3d789dSPierre van Houtryve assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant"); 1332a140931bSRahul Joshi ConstRecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); 1333fa3d789dSPierre van Houtryve if (any_of(Variants, [PredDef](const Record *R) { 1334fa3d789dSPierre van Houtryve return R->getValueAsDef("Predicate") == PredDef; 1335fa3d789dSPierre van Houtryve })) { 1336fa3d789dSPierre van Houtryve // To check if PredDef is mutually exclusive with PC we also need to 1337fa3d789dSPierre van Houtryve // check that PC.Predicate is exclusive with all predicates from variant 1338fa3d789dSPierre van Houtryve // we're expanding. Consider following RW sequence with two variants 1339fa3d789dSPierre van Houtryve // (1 & 2), where A, B and C are predicates from corresponding SchedVars: 1340fa3d789dSPierre van Houtryve // 1341fa3d789dSPierre van Houtryve // 1:A/B - 2:C/B 1342fa3d789dSPierre van Houtryve // 1343fa3d789dSPierre van Houtryve // Here C is not mutually exclusive with variant (1), because A doesn't 1344fa3d789dSPierre van Houtryve // exist in variant (2). This means we have possible transitions from A 1345fa3d789dSPierre van Houtryve // to C and from A to B, and fully expanded sequence would look like: 1346fa3d789dSPierre van Houtryve // 1347fa3d789dSPierre van Houtryve // if (A & C) return ...; 1348fa3d789dSPierre van Houtryve // if (A & B) return ...; 1349fa3d789dSPierre van Houtryve // if (B) return ...; 1350fa3d789dSPierre van Houtryve // 1351fa3d789dSPierre van Houtryve // Now let's consider another sequence: 1352fa3d789dSPierre van Houtryve // 1353fa3d789dSPierre van Houtryve // 1:A/B - 2:A/B 1354fa3d789dSPierre van Houtryve // 1355fa3d789dSPierre van Houtryve // Here A in variant (2) is mutually exclusive with variant (1), because 1356fa3d789dSPierre van Houtryve // A also exists in (2). This means A->B transition is impossible and 1357fa3d789dSPierre van Houtryve // expanded sequence would look like: 1358fa3d789dSPierre van Houtryve // 1359fa3d789dSPierre van Houtryve // if (A) return ...; 1360fa3d789dSPierre van Houtryve // if (B) return ...; 1361fa3d789dSPierre van Houtryve if (!llvm::is_contained(Preds, PC.Predicate)) 1362fa3d789dSPierre van Houtryve continue; 1363fa3d789dSPierre van Houtryve return true; 1364fa3d789dSPierre van Houtryve } 1365fa3d789dSPierre van Houtryve } 1366fa3d789dSPierre van Houtryve return false; 1367fa3d789dSPierre van Houtryve } 1368fa3d789dSPierre van Houtryve 1369d256b9e8SRahul Joshi static std::vector<const Record *> 1370d256b9e8SRahul Joshi getAllPredicates(ArrayRef<TransVariant> Variants, unsigned ProcId) { 1371d256b9e8SRahul Joshi std::vector<const Record *> Preds; 1372fa3d789dSPierre van Houtryve for (auto &Variant : Variants) { 1373fa3d789dSPierre van Houtryve if (!Variant.VarOrSeqDef->isSubClassOf("SchedVar")) 1374fa3d789dSPierre van Houtryve continue; 1375fa3d789dSPierre van Houtryve Preds.push_back(Variant.VarOrSeqDef->getValueAsDef("Predicate")); 1376fa3d789dSPierre van Houtryve } 1377fa3d789dSPierre van Houtryve return Preds; 1378fa3d789dSPierre van Houtryve } 1379fa3d789dSPierre van Houtryve 1380fa3d789dSPierre van Houtryve // Populate IntersectingVariants with any variants or aliased sequences of the 1381fa3d789dSPierre van Houtryve // given SchedRW whose processor indices and predicates are not mutually 1382fa3d789dSPierre van Houtryve // exclusive with the given transition. 1383fa3d789dSPierre van Houtryve void PredTransitions::getIntersectingVariants( 1384fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedRW, unsigned TransIdx, 1385fa3d789dSPierre van Houtryve std::vector<TransVariant> &IntersectingVariants) { 1386fa3d789dSPierre van Houtryve 1387fa3d789dSPierre van Houtryve bool GenericRW = false; 1388fa3d789dSPierre van Houtryve 1389fa3d789dSPierre van Houtryve std::vector<TransVariant> Variants; 1390fa3d789dSPierre van Houtryve if (SchedRW.HasVariants) { 1391fa3d789dSPierre van Houtryve unsigned VarProcIdx = 0; 1392fa3d789dSPierre van Houtryve if (SchedRW.TheDef->getValueInit("SchedModel")->isComplete()) { 1393d256b9e8SRahul Joshi const Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel"); 1394fa3d789dSPierre van Houtryve VarProcIdx = SchedModels.getProcModel(ModelDef).Index; 1395fa3d789dSPierre van Houtryve } 1396fa3d789dSPierre van Houtryve if (VarProcIdx == 0 || VarProcIdx == TransVec[TransIdx].ProcIndex) { 1397fa3d789dSPierre van Houtryve // Push each variant. Assign TransVecIdx later. 1398c29dfb33SRahul Joshi for (const Record *VarDef : 1399c29dfb33SRahul Joshi SchedRW.TheDef->getValueAsListOfDefs("Variants")) 1400fa3d789dSPierre van Houtryve Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0); 1401fa3d789dSPierre van Houtryve if (VarProcIdx == 0) 1402fa3d789dSPierre van Houtryve GenericRW = true; 1403fa3d789dSPierre van Houtryve } 1404fa3d789dSPierre van Houtryve } 14053ae71d15SRahul Joshi for (ConstRecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); 1406fa3d789dSPierre van Houtryve AI != AE; ++AI) { 1407fa3d789dSPierre van Houtryve // If either the SchedAlias itself or the SchedReadWrite that it aliases 1408fa3d789dSPierre van Houtryve // to is defined within a processor model, constrain all variants to 1409fa3d789dSPierre van Houtryve // that processor. 1410fa3d789dSPierre van Houtryve unsigned AliasProcIdx = 0; 1411fa3d789dSPierre van Houtryve if ((*AI)->getValueInit("SchedModel")->isComplete()) { 1412d256b9e8SRahul Joshi const Record *ModelDef = (*AI)->getValueAsDef("SchedModel"); 1413fa3d789dSPierre van Houtryve AliasProcIdx = SchedModels.getProcModel(ModelDef).Index; 1414fa3d789dSPierre van Houtryve } 1415fa3d789dSPierre van Houtryve if (AliasProcIdx && AliasProcIdx != TransVec[TransIdx].ProcIndex) 1416fa3d789dSPierre van Houtryve continue; 1417fa3d789dSPierre van Houtryve if (!Variants.empty()) { 1418bc386a82SCraig Topper const CodeGenProcModel &PM = SchedModels.procModels()[AliasProcIdx]; 1419fa3d789dSPierre van Houtryve PrintFatalError((*AI)->getLoc(), 1420fa3d789dSPierre van Houtryve "Multiple variants defined for processor " + 1421fa3d789dSPierre van Houtryve PM.ModelName + 1422fa3d789dSPierre van Houtryve " Ensure only one SchedAlias exists per RW."); 1423fa3d789dSPierre van Houtryve } 1424fa3d789dSPierre van Houtryve 1425fa3d789dSPierre van Houtryve const CodeGenSchedRW &AliasRW = 1426fa3d789dSPierre van Houtryve SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); 1427fa3d789dSPierre van Houtryve 1428fa3d789dSPierre van Houtryve if (AliasRW.HasVariants) { 1429c29dfb33SRahul Joshi for (const Record *VD : AliasRW.TheDef->getValueAsListOfDefs("Variants")) 1430fa3d789dSPierre van Houtryve Variants.emplace_back(VD, AliasRW.Index, AliasProcIdx, 0); 1431fa3d789dSPierre van Houtryve } 1432fa3d789dSPierre van Houtryve if (AliasRW.IsSequence) 1433fa3d789dSPierre van Houtryve Variants.emplace_back(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0); 1434fa3d789dSPierre van Houtryve if (AliasProcIdx == 0) 1435fa3d789dSPierre van Houtryve GenericRW = true; 1436fa3d789dSPierre van Houtryve } 1437d256b9e8SRahul Joshi std::vector<const Record *> AllPreds = 1438fa3d789dSPierre van Houtryve getAllPredicates(Variants, TransVec[TransIdx].ProcIndex); 1439fa3d789dSPierre van Houtryve for (TransVariant &Variant : Variants) { 1440fa3d789dSPierre van Houtryve // Don't expand variants if the processor models don't intersect. 1441fa3d789dSPierre van Houtryve // A zero processor index means any processor. 1442fa3d789dSPierre van Houtryve if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) { 1443d256b9e8SRahul Joshi const Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate"); 1444fa3d789dSPierre van Houtryve if (mutuallyExclusive(PredDef, AllPreds, TransVec[TransIdx].PredTerm)) 1445fa3d789dSPierre van Houtryve continue; 1446fa3d789dSPierre van Houtryve } 1447fa3d789dSPierre van Houtryve 1448fa3d789dSPierre van Houtryve if (IntersectingVariants.empty()) { 1449fa3d789dSPierre van Houtryve // The first variant builds on the existing transition. 1450fa3d789dSPierre van Houtryve Variant.TransVecIdx = TransIdx; 1451fa3d789dSPierre van Houtryve IntersectingVariants.push_back(Variant); 1452fa3d789dSPierre van Houtryve } else { 1453fa3d789dSPierre van Houtryve // Push another copy of the current transition for more variants. 1454fa3d789dSPierre van Houtryve Variant.TransVecIdx = TransVec.size(); 1455fa3d789dSPierre van Houtryve IntersectingVariants.push_back(Variant); 1456fa3d789dSPierre van Houtryve TransVec.push_back(TransVec[TransIdx]); 1457fa3d789dSPierre van Houtryve } 1458fa3d789dSPierre van Houtryve } 1459fa3d789dSPierre van Houtryve if (GenericRW && IntersectingVariants.empty()) { 1460fa3d789dSPierre van Houtryve PrintFatalError(SchedRW.TheDef->getLoc(), 1461fa3d789dSPierre van Houtryve "No variant of this type has " 1462fa3d789dSPierre van Houtryve "a matching predicate on any processor"); 1463fa3d789dSPierre van Houtryve } 1464fa3d789dSPierre van Houtryve } 1465fa3d789dSPierre van Houtryve 1466fa3d789dSPierre van Houtryve // Push the Reads/Writes selected by this variant onto the PredTransition 1467fa3d789dSPierre van Houtryve // specified by VInfo. 1468fa3d789dSPierre van Houtryve void PredTransitions::pushVariant(const TransVariant &VInfo, bool IsRead) { 1469fa3d789dSPierre van Houtryve PredTransition &Trans = TransVec[VInfo.TransVecIdx]; 1470fa3d789dSPierre van Houtryve 1471fa3d789dSPierre van Houtryve // If this operand transition is reached through a processor-specific alias, 1472fa3d789dSPierre van Houtryve // then the whole transition is specific to this processor. 1473fa3d789dSPierre van Houtryve IdxVec SelectedRWs; 1474fa3d789dSPierre van Houtryve if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) { 1475d256b9e8SRahul Joshi const Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate"); 1476fa3d789dSPierre van Houtryve Trans.PredTerm.emplace_back(IsRead, VInfo.RWIdx, PredDef); 1477c29dfb33SRahul Joshi ConstRecVec SelectedDefs = 1478a140931bSRahul Joshi VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected"); 1479fa3d789dSPierre van Houtryve SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead); 1480fa3d789dSPierre van Houtryve } else { 1481fa3d789dSPierre van Houtryve assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") && 1482fa3d789dSPierre van Houtryve "variant must be a SchedVariant or aliased WriteSequence"); 1483fa3d789dSPierre van Houtryve SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead)); 1484fa3d789dSPierre van Houtryve } 1485fa3d789dSPierre van Houtryve 1486fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead); 1487fa3d789dSPierre van Houtryve 1488fa3d789dSPierre van Houtryve SmallVectorImpl<SmallVector<unsigned, 4>> &RWSequences = 1489fa3d789dSPierre van Houtryve IsRead ? Trans.ReadSequences : Trans.WriteSequences; 1490fa3d789dSPierre van Houtryve if (SchedRW.IsVariadic) { 1491fa3d789dSPierre van Houtryve unsigned OperIdx = RWSequences.size() - 1; 1492fa3d789dSPierre van Houtryve // Make N-1 copies of this transition's last sequence. 1493fa3d789dSPierre van Houtryve RWSequences.reserve(RWSequences.size() + SelectedRWs.size() - 1); 1494fa3d789dSPierre van Houtryve RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1, 1495fa3d789dSPierre van Houtryve RWSequences[OperIdx]); 1496fa3d789dSPierre van Houtryve // Push each of the N elements of the SelectedRWs onto a copy of the last 1497fa3d789dSPierre van Houtryve // sequence (split the current operand into N operands). 1498fa3d789dSPierre van Houtryve // Note that write sequences should be expanded within this loop--the entire 1499fa3d789dSPierre van Houtryve // sequence belongs to a single operand. 1500fa3d789dSPierre van Houtryve for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end(); RWI != RWE; 1501fa3d789dSPierre van Houtryve ++RWI, ++OperIdx) { 1502fa3d789dSPierre van Houtryve IdxVec ExpandedRWs; 1503fa3d789dSPierre van Houtryve if (IsRead) 1504fa3d789dSPierre van Houtryve ExpandedRWs.push_back(*RWI); 1505fa3d789dSPierre van Houtryve else 1506fa3d789dSPierre van Houtryve SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); 1507fa3d789dSPierre van Houtryve llvm::append_range(RWSequences[OperIdx], ExpandedRWs); 1508fa3d789dSPierre van Houtryve } 1509fa3d789dSPierre van Houtryve assert(OperIdx == RWSequences.size() && "missed a sequence"); 1510fa3d789dSPierre van Houtryve } else { 1511fa3d789dSPierre van Houtryve // Push this transition's expanded sequence onto this transition's last 1512fa3d789dSPierre van Houtryve // sequence (add to the current operand's sequence). 1513fa3d789dSPierre van Houtryve SmallVectorImpl<unsigned> &Seq = RWSequences.back(); 1514fa3d789dSPierre van Houtryve IdxVec ExpandedRWs; 1515fa3d789dSPierre van Houtryve for (unsigned int SelectedRW : SelectedRWs) { 1516fa3d789dSPierre van Houtryve if (IsRead) 1517fa3d789dSPierre van Houtryve ExpandedRWs.push_back(SelectedRW); 1518fa3d789dSPierre van Houtryve else 1519fa3d789dSPierre van Houtryve SchedModels.expandRWSequence(SelectedRW, ExpandedRWs, IsRead); 1520fa3d789dSPierre van Houtryve } 1521fa3d789dSPierre van Houtryve llvm::append_range(Seq, ExpandedRWs); 1522fa3d789dSPierre van Houtryve } 1523fa3d789dSPierre van Houtryve } 1524fa3d789dSPierre van Houtryve 1525fa3d789dSPierre van Houtryve // RWSeq is a sequence of all Reads or all Writes for the next read or write 1526fa3d789dSPierre van Houtryve // operand. StartIdx is an index into TransVec where partial results 1527fa3d789dSPierre van Houtryve // starts. RWSeq must be applied to all transitions between StartIdx and the end 1528fa3d789dSPierre van Houtryve // of TransVec. 1529fa3d789dSPierre van Houtryve bool PredTransitions::substituteVariantOperand( 1530fa3d789dSPierre van Houtryve const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) { 1531fa3d789dSPierre van Houtryve bool Subst = false; 1532fa3d789dSPierre van Houtryve // Visit each original RW within the current sequence. 1533fa3d789dSPierre van Houtryve for (unsigned int RWI : RWSeq) { 1534fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(RWI, IsRead); 1535fa3d789dSPierre van Houtryve // Push this RW on all partial PredTransitions or distribute variants. 1536fa3d789dSPierre van Houtryve // New PredTransitions may be pushed within this loop which should not be 1537fa3d789dSPierre van Houtryve // revisited (TransEnd must be loop invariant). 1538fa3d789dSPierre van Houtryve for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size(); 1539fa3d789dSPierre van Houtryve TransIdx != TransEnd; ++TransIdx) { 1540fa3d789dSPierre van Houtryve // Distribute this partial PredTransition across intersecting variants. 1541fa3d789dSPierre van Houtryve // This will push a copies of TransVec[TransIdx] on the back of TransVec. 1542fa3d789dSPierre van Houtryve std::vector<TransVariant> IntersectingVariants; 1543fa3d789dSPierre van Houtryve getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants); 1544fa3d789dSPierre van Houtryve // Now expand each variant on top of its copy of the transition. 1545fa3d789dSPierre van Houtryve for (const TransVariant &IV : IntersectingVariants) 1546fa3d789dSPierre van Houtryve pushVariant(IV, IsRead); 1547fa3d789dSPierre van Houtryve if (IntersectingVariants.empty()) { 1548fa3d789dSPierre van Houtryve if (IsRead) 1549fa3d789dSPierre van Houtryve TransVec[TransIdx].ReadSequences.back().push_back(RWI); 1550fa3d789dSPierre van Houtryve else 1551fa3d789dSPierre van Houtryve TransVec[TransIdx].WriteSequences.back().push_back(RWI); 1552fa3d789dSPierre van Houtryve continue; 1553fa3d789dSPierre van Houtryve } else { 1554fa3d789dSPierre van Houtryve Subst = true; 1555fa3d789dSPierre van Houtryve } 1556fa3d789dSPierre van Houtryve } 1557fa3d789dSPierre van Houtryve } 1558fa3d789dSPierre van Houtryve return Subst; 1559fa3d789dSPierre van Houtryve } 1560fa3d789dSPierre van Houtryve 1561fa3d789dSPierre van Houtryve // For each variant of a Read/Write in Trans, substitute the sequence of 1562fa3d789dSPierre van Houtryve // Read/Writes guarded by the variant. This is exponential in the number of 1563fa3d789dSPierre van Houtryve // variant Read/Writes, but in practice detection of mutually exclusive 1564fa3d789dSPierre van Houtryve // predicates should result in linear growth in the total number variants. 1565fa3d789dSPierre van Houtryve // 1566fa3d789dSPierre van Houtryve // This is one step in a breadth-first search of nested variants. 1567fa3d789dSPierre van Houtryve bool PredTransitions::substituteVariants(const PredTransition &Trans) { 1568fa3d789dSPierre van Houtryve // Build up a set of partial results starting at the back of 1569fa3d789dSPierre van Houtryve // PredTransitions. Remember the first new transition. 1570fa3d789dSPierre van Houtryve unsigned StartIdx = TransVec.size(); 1571fa3d789dSPierre van Houtryve bool Subst = false; 1572fa3d789dSPierre van Houtryve assert(Trans.ProcIndex != 0); 1573fa3d789dSPierre van Houtryve TransVec.emplace_back(Trans.PredTerm, Trans.ProcIndex); 1574fa3d789dSPierre van Houtryve 1575fa3d789dSPierre van Houtryve // Visit each original write sequence. 1576fa3d789dSPierre van Houtryve for (const auto &WriteSequence : Trans.WriteSequences) { 1577fa3d789dSPierre van Houtryve // Push a new (empty) write sequence onto all partial Transitions. 15786628b593SCraig Topper for (auto &PT : drop_begin(TransVec, StartIdx)) 15796628b593SCraig Topper PT.WriteSequences.emplace_back(); 1580fa3d789dSPierre van Houtryve Subst |= 1581fa3d789dSPierre van Houtryve substituteVariantOperand(WriteSequence, /*IsRead=*/false, StartIdx); 1582fa3d789dSPierre van Houtryve } 1583fa3d789dSPierre van Houtryve // Visit each original read sequence. 1584fa3d789dSPierre van Houtryve for (const auto &ReadSequence : Trans.ReadSequences) { 1585fa3d789dSPierre van Houtryve // Push a new (empty) read sequence onto all partial Transitions. 15866628b593SCraig Topper for (auto &PT : drop_begin(TransVec, StartIdx)) 15876628b593SCraig Topper PT.ReadSequences.emplace_back(); 1588fa3d789dSPierre van Houtryve Subst |= substituteVariantOperand(ReadSequence, /*IsRead=*/true, StartIdx); 1589fa3d789dSPierre van Houtryve } 1590fa3d789dSPierre van Houtryve return Subst; 1591fa3d789dSPierre van Houtryve } 1592fa3d789dSPierre van Houtryve 1593fa3d789dSPierre van Houtryve static void addSequences(CodeGenSchedModels &SchedModels, 1594fa3d789dSPierre van Houtryve const SmallVectorImpl<SmallVector<unsigned, 4>> &Seqs, 1595fa3d789dSPierre van Houtryve IdxVec &Result, bool IsRead) { 1596fa3d789dSPierre van Houtryve for (const auto &S : Seqs) 1597fa3d789dSPierre van Houtryve if (!S.empty()) 1598fa3d789dSPierre van Houtryve Result.push_back(SchedModels.findOrInsertRW(S, IsRead)); 1599fa3d789dSPierre van Houtryve } 1600fa3d789dSPierre van Houtryve 1601fa3d789dSPierre van Houtryve #ifndef NDEBUG 16023ae71d15SRahul Joshi static void dumpRecVec(const ConstRecVec &RV) { 1603fa3d789dSPierre van Houtryve for (const Record *R : RV) 1604fa3d789dSPierre van Houtryve dbgs() << R->getName() << ", "; 1605fa3d789dSPierre van Houtryve } 1606fa3d789dSPierre van Houtryve #endif 1607fa3d789dSPierre van Houtryve 1608fa3d789dSPierre van Houtryve static void dumpTransition(const CodeGenSchedModels &SchedModels, 1609fa3d789dSPierre van Houtryve const CodeGenSchedClass &FromSC, 1610fa3d789dSPierre van Houtryve const CodeGenSchedTransition &SCTrans, 16113ae71d15SRahul Joshi const ConstRecVec &Preds) { 1612fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "Adding transition from " << FromSC.Name << "(" 1613fa3d789dSPierre van Houtryve << FromSC.Index << ") to " 1614fa3d789dSPierre van Houtryve << SchedModels.getSchedClass(SCTrans.ToClassIdx).Name << "(" 1615fa3d789dSPierre van Houtryve << SCTrans.ToClassIdx << ") on pred term: ("; 1616fa3d789dSPierre van Houtryve dumpRecVec(Preds); 1617fa3d789dSPierre van Houtryve dbgs() << ") on processor (" << SCTrans.ProcIndex << ")\n"); 1618fa3d789dSPierre van Houtryve } 1619fa3d789dSPierre van Houtryve // Create a new SchedClass for each variant found by inferFromRW. Pass 1620fa3d789dSPierre van Houtryve static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, 1621fa3d789dSPierre van Houtryve unsigned FromClassIdx, 1622fa3d789dSPierre van Houtryve CodeGenSchedModels &SchedModels) { 1623fa3d789dSPierre van Houtryve // For each PredTransition, create a new CodeGenSchedTransition, which usually 1624fa3d789dSPierre van Houtryve // requires creating a new SchedClass. 1625fa3d789dSPierre van Houtryve for (const auto &LastTransition : LastTransitions) { 1626fa3d789dSPierre van Houtryve // Variant expansion (substituteVariants) may create unconditional 1627fa3d789dSPierre van Houtryve // transitions. We don't need to build sched classes for them. 1628fa3d789dSPierre van Houtryve if (LastTransition.PredTerm.empty()) 1629fa3d789dSPierre van Houtryve continue; 1630fa3d789dSPierre van Houtryve IdxVec OperWritesVariant, OperReadsVariant; 1631fa3d789dSPierre van Houtryve addSequences(SchedModels, LastTransition.WriteSequences, OperWritesVariant, 1632fa3d789dSPierre van Houtryve false); 1633fa3d789dSPierre van Houtryve addSequences(SchedModels, LastTransition.ReadSequences, OperReadsVariant, 1634fa3d789dSPierre van Houtryve true); 1635fa3d789dSPierre van Houtryve CodeGenSchedTransition SCTrans; 1636fa3d789dSPierre van Houtryve 1637fa3d789dSPierre van Houtryve // Transition should not contain processor indices already assigned to 1638fa3d789dSPierre van Houtryve // InstRWs in this scheduling class. 1639fa3d789dSPierre van Houtryve const CodeGenSchedClass &FromSC = SchedModels.getSchedClass(FromClassIdx); 1640fa3d789dSPierre van Houtryve if (FromSC.InstRWProcIndices.count(LastTransition.ProcIndex)) 1641fa3d789dSPierre van Houtryve continue; 1642fa3d789dSPierre van Houtryve SCTrans.ProcIndex = LastTransition.ProcIndex; 1643fa3d789dSPierre van Houtryve SCTrans.ToClassIdx = 1644fa3d789dSPierre van Houtryve SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant, 1645fa3d789dSPierre van Houtryve OperReadsVariant, LastTransition.ProcIndex); 1646fa3d789dSPierre van Houtryve 1647fa3d789dSPierre van Houtryve // The final PredTerm is unique set of predicates guarding the transition. 16483ae71d15SRahul Joshi ConstRecVec Preds; 1649fa3d789dSPierre van Houtryve transform(LastTransition.PredTerm, std::back_inserter(Preds), 1650fa3d789dSPierre van Houtryve [](const PredCheck &P) { return P.Predicate; }); 1651d9293519SKazu Hirata Preds.erase(llvm::unique(Preds), Preds.end()); 1652fa3d789dSPierre van Houtryve dumpTransition(SchedModels, FromSC, SCTrans, Preds); 1653fa3d789dSPierre van Houtryve SCTrans.PredTerm = std::move(Preds); 1654fa3d789dSPierre van Houtryve SchedModels.getSchedClass(FromClassIdx) 1655fa3d789dSPierre van Houtryve .Transitions.push_back(std::move(SCTrans)); 1656fa3d789dSPierre van Houtryve } 1657fa3d789dSPierre van Houtryve } 1658fa3d789dSPierre van Houtryve 1659fa3d789dSPierre van Houtryve std::vector<unsigned> CodeGenSchedModels::getAllProcIndices() const { 1660fa3d789dSPierre van Houtryve std::vector<unsigned> ProcIdVec; 1661fa3d789dSPierre van Houtryve for (const auto &PM : ProcModelMap) 1662fa3d789dSPierre van Houtryve if (PM.second != 0) 1663fa3d789dSPierre van Houtryve ProcIdVec.push_back(PM.second); 1664fa3d789dSPierre van Houtryve // The order of the keys (Record pointers) of ProcModelMap are not stable. 1665fa3d789dSPierre van Houtryve // Sort to stabalize the values. 1666fa3d789dSPierre van Houtryve llvm::sort(ProcIdVec); 1667fa3d789dSPierre van Houtryve return ProcIdVec; 1668fa3d789dSPierre van Houtryve } 1669fa3d789dSPierre van Houtryve 1670fa3d789dSPierre van Houtryve static std::vector<PredTransition> 1671fa3d789dSPierre van Houtryve makePerProcessorTransitions(const PredTransition &Trans, 1672fa3d789dSPierre van Houtryve ArrayRef<unsigned> ProcIndices) { 1673fa3d789dSPierre van Houtryve std::vector<PredTransition> PerCpuTransVec; 1674fa3d789dSPierre van Houtryve for (unsigned ProcId : ProcIndices) { 1675fa3d789dSPierre van Houtryve assert(ProcId != 0); 1676fa3d789dSPierre van Houtryve PerCpuTransVec.push_back(Trans); 1677fa3d789dSPierre van Houtryve PerCpuTransVec.back().ProcIndex = ProcId; 1678fa3d789dSPierre van Houtryve } 1679fa3d789dSPierre van Houtryve return PerCpuTransVec; 1680fa3d789dSPierre van Houtryve } 1681fa3d789dSPierre van Houtryve 1682fa3d789dSPierre van Houtryve // Create new SchedClasses for the given ReadWrite list. If any of the 1683fa3d789dSPierre van Houtryve // ReadWrites refers to a SchedVariant, create a new SchedClass for each variant 1684fa3d789dSPierre van Houtryve // of the ReadWrite list, following Aliases if necessary. 1685fa3d789dSPierre van Houtryve void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites, 1686fa3d789dSPierre van Houtryve ArrayRef<unsigned> OperReads, 1687fa3d789dSPierre van Houtryve unsigned FromClassIdx, 1688fa3d789dSPierre van Houtryve ArrayRef<unsigned> ProcIndices) { 1689fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); 1690fa3d789dSPierre van Houtryve dbgs() << ") "); 1691fa3d789dSPierre van Houtryve // Create a seed transition with an empty PredTerm and the expanded sequences 1692fa3d789dSPierre van Houtryve // of SchedWrites for the current SchedClass. 169323746c2fSCraig Topper std::vector<PredTransition> LastTransitions(1); 1694fa3d789dSPierre van Houtryve 1695fa3d789dSPierre van Houtryve for (unsigned WriteIdx : OperWrites) { 1696fa3d789dSPierre van Houtryve IdxVec WriteSeq; 1697fa3d789dSPierre van Houtryve expandRWSequence(WriteIdx, WriteSeq, /*IsRead=*/false); 1698d79e3af8SJie Fu [[maybe_unused]] SmallVectorImpl<unsigned> &Seq = 169923746c2fSCraig Topper LastTransitions[0].WriteSequences.emplace_back(WriteSeq.begin(), 170023746c2fSCraig Topper WriteSeq.end()); 1701fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); 1702fa3d789dSPierre van Houtryve } 1703fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << " Reads: "); 1704fa3d789dSPierre van Houtryve for (unsigned ReadIdx : OperReads) { 1705fa3d789dSPierre van Houtryve IdxVec ReadSeq; 1706fa3d789dSPierre van Houtryve expandRWSequence(ReadIdx, ReadSeq, /*IsRead=*/true); 1707d79e3af8SJie Fu [[maybe_unused]] SmallVectorImpl<unsigned> &Seq = 170823746c2fSCraig Topper LastTransitions[0].ReadSequences.emplace_back(ReadSeq.begin(), 170923746c2fSCraig Topper ReadSeq.end()); 1710fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); 1711fa3d789dSPierre van Houtryve } 1712fa3d789dSPierre van Houtryve LLVM_DEBUG(dbgs() << '\n'); 1713fa3d789dSPierre van Houtryve 1714fa3d789dSPierre van Houtryve LastTransitions = makePerProcessorTransitions( 1715fa3d789dSPierre van Houtryve LastTransitions[0], llvm::is_contained(ProcIndices, 0) 1716fa3d789dSPierre van Houtryve ? ArrayRef<unsigned>(getAllProcIndices()) 1717fa3d789dSPierre van Houtryve : ProcIndices); 1718fa3d789dSPierre van Houtryve // Collect all PredTransitions for individual operands. 1719fa3d789dSPierre van Houtryve // Iterate until no variant writes remain. 1720fa3d789dSPierre van Houtryve bool SubstitutedAny; 1721fa3d789dSPierre van Houtryve do { 1722fa3d789dSPierre van Houtryve SubstitutedAny = false; 1723fa3d789dSPierre van Houtryve PredTransitions Transitions(*this); 1724fa3d789dSPierre van Houtryve for (const PredTransition &Trans : LastTransitions) 1725fa3d789dSPierre van Houtryve SubstitutedAny |= Transitions.substituteVariants(Trans); 1726fa3d789dSPierre van Houtryve LLVM_DEBUG(Transitions.dump()); 1727fa3d789dSPierre van Houtryve LastTransitions = std::move(Transitions.TransVec); 1728fa3d789dSPierre van Houtryve } while (SubstitutedAny); 1729fa3d789dSPierre van Houtryve 1730fa3d789dSPierre van Houtryve // WARNING: We are about to mutate the SchedClasses vector. Do not refer to 1731fa3d789dSPierre van Houtryve // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions. 1732fa3d789dSPierre van Houtryve inferFromTransitions(LastTransitions, FromClassIdx, *this); 1733fa3d789dSPierre van Houtryve } 1734fa3d789dSPierre van Houtryve 1735fa3d789dSPierre van Houtryve // Check if any processor resource group contains all resource records in 1736fa3d789dSPierre van Houtryve // SubUnits. 1737c3aa86c9SCraig Topper bool CodeGenSchedModels::hasSuperGroup(const ConstRecVec &SubUnits, 1738c3aa86c9SCraig Topper const CodeGenProcModel &PM) { 17393ae71d15SRahul Joshi for (const Record *ProcResourceDef : PM.ProcResourceDefs) { 1740fa3d789dSPierre van Houtryve if (!ProcResourceDef->isSubClassOf("ProcResGroup")) 1741fa3d789dSPierre van Houtryve continue; 1742a140931bSRahul Joshi ConstRecVec SuperUnits = ProcResourceDef->getValueAsListOfDefs("Resources"); 1743c29dfb33SRahul Joshi auto RI = SubUnits.begin(), RE = SubUnits.end(); 1744fa3d789dSPierre van Houtryve for (; RI != RE; ++RI) { 1745fa3d789dSPierre van Houtryve if (!is_contained(SuperUnits, *RI)) { 1746fa3d789dSPierre van Houtryve break; 1747fa3d789dSPierre van Houtryve } 1748fa3d789dSPierre van Houtryve } 1749fa3d789dSPierre van Houtryve if (RI == RE) 1750fa3d789dSPierre van Houtryve return true; 1751fa3d789dSPierre van Houtryve } 1752fa3d789dSPierre van Houtryve return false; 1753fa3d789dSPierre van Houtryve } 1754fa3d789dSPierre van Houtryve 1755fa3d789dSPierre van Houtryve // Verify that overlapping groups have a common supergroup. 1756c3aa86c9SCraig Topper void CodeGenSchedModels::verifyProcResourceGroups(const CodeGenProcModel &PM) { 1757fa3d789dSPierre van Houtryve for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) { 1758fa3d789dSPierre van Houtryve if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup")) 1759fa3d789dSPierre van Houtryve continue; 1760c29dfb33SRahul Joshi ConstRecVec CheckUnits = 1761a140931bSRahul Joshi PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources"); 1762fa3d789dSPierre van Houtryve for (unsigned j = i + 1; j < e; ++j) { 1763fa3d789dSPierre van Houtryve if (!PM.ProcResourceDefs[j]->isSubClassOf("ProcResGroup")) 1764fa3d789dSPierre van Houtryve continue; 1765c29dfb33SRahul Joshi ConstRecVec OtherUnits = 1766a140931bSRahul Joshi PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources"); 1767fa3d789dSPierre van Houtryve if (std::find_first_of(CheckUnits.begin(), CheckUnits.end(), 1768fa3d789dSPierre van Houtryve OtherUnits.begin(), 1769fa3d789dSPierre van Houtryve OtherUnits.end()) != CheckUnits.end()) { 1770fa3d789dSPierre van Houtryve // CheckUnits and OtherUnits overlap 1771fa3d789dSPierre van Houtryve llvm::append_range(OtherUnits, CheckUnits); 1772fa3d789dSPierre van Houtryve if (!hasSuperGroup(OtherUnits, PM)) { 1773fa3d789dSPierre van Houtryve PrintFatalError((PM.ProcResourceDefs[i])->getLoc(), 1774fa3d789dSPierre van Houtryve "proc resource group overlaps with " + 1775fa3d789dSPierre van Houtryve PM.ProcResourceDefs[j]->getName() + 1776fa3d789dSPierre van Houtryve " but no supergroup contains both."); 1777fa3d789dSPierre van Houtryve } 1778fa3d789dSPierre van Houtryve } 1779fa3d789dSPierre van Houtryve } 1780fa3d789dSPierre van Houtryve } 1781fa3d789dSPierre van Houtryve } 1782fa3d789dSPierre van Houtryve 1783fa3d789dSPierre van Houtryve // Collect all the RegisterFile definitions available in this target. 1784fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectRegisterFiles() { 1785fa3d789dSPierre van Houtryve // RegisterFiles is the vector of CodeGenRegisterFile. 17863ae71d15SRahul Joshi for (const Record *RF : Records.getAllDerivedDefinitions("RegisterFile")) { 1787fa3d789dSPierre van Houtryve // For each register file definition, construct a CodeGenRegisterFile object 1788fa3d789dSPierre van Houtryve // and add it to the appropriate scheduling model. 1789fa3d789dSPierre van Houtryve CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel")); 1790fa3d789dSPierre van Houtryve PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(), RF)); 1791fa3d789dSPierre van Houtryve CodeGenRegisterFile &CGRF = PM.RegisterFiles.back(); 1792fa3d789dSPierre van Houtryve CGRF.MaxMovesEliminatedPerCycle = 1793fa3d789dSPierre van Houtryve RF->getValueAsInt("MaxMovesEliminatedPerCycle"); 1794fa3d789dSPierre van Houtryve CGRF.AllowZeroMoveEliminationOnly = 1795fa3d789dSPierre van Houtryve RF->getValueAsBit("AllowZeroMoveEliminationOnly"); 1796fa3d789dSPierre van Houtryve 1797fa3d789dSPierre van Houtryve // Now set the number of physical registers as well as the cost of registers 1798fa3d789dSPierre van Houtryve // in each register class. 1799fa3d789dSPierre van Houtryve CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs"); 1800fa3d789dSPierre van Houtryve if (!CGRF.NumPhysRegs) { 1801fa3d789dSPierre van Houtryve PrintFatalError(RF->getLoc(), 1802fa3d789dSPierre van Houtryve "Invalid RegisterFile with zero physical registers"); 1803fa3d789dSPierre van Houtryve } 1804fa3d789dSPierre van Houtryve 1805a140931bSRahul Joshi ConstRecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses"); 1806fa3d789dSPierre van Houtryve std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts"); 180762e2c7fbSRahul Joshi const ListInit *MoveElimInfo = 180862e2c7fbSRahul Joshi RF->getValueAsListInit("AllowMoveElimination"); 1809fa3d789dSPierre van Houtryve for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) { 1810fa3d789dSPierre van Houtryve int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1; 1811fa3d789dSPierre van Houtryve 1812fa3d789dSPierre van Houtryve bool AllowMoveElim = false; 1813fa3d789dSPierre van Houtryve if (MoveElimInfo->size() > I) { 181462e2c7fbSRahul Joshi const BitInit *Val = cast<BitInit>(MoveElimInfo->getElement(I)); 1815fa3d789dSPierre van Houtryve AllowMoveElim = Val->getValue(); 1816fa3d789dSPierre van Houtryve } 1817fa3d789dSPierre van Houtryve 1818fa3d789dSPierre van Houtryve CGRF.Costs.emplace_back(RegisterClasses[I], Cost, AllowMoveElim); 1819fa3d789dSPierre van Houtryve } 1820fa3d789dSPierre van Houtryve } 1821fa3d789dSPierre van Houtryve } 1822fa3d789dSPierre van Houtryve 1823fa3d789dSPierre van Houtryve // Collect and sort WriteRes, ReadAdvance, and ProcResources. 1824fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectProcResources() { 1825fa3d789dSPierre van Houtryve ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits"); 1826fa3d789dSPierre van Houtryve ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); 1827fa3d789dSPierre van Houtryve 1828fa3d789dSPierre van Houtryve // Add any subtarget-specific SchedReadWrites that are directly associated 1829fa3d789dSPierre van Houtryve // with processor resources. Refer to the parent SchedClass's ProcIndices to 1830fa3d789dSPierre van Houtryve // determine which processors they apply to. 1831bc386a82SCraig Topper for (const CodeGenSchedClass &SC : schedClasses()) { 1832fa3d789dSPierre van Houtryve if (SC.ItinClassDef) { 1833fa3d789dSPierre van Houtryve collectItinProcResources(SC.ItinClassDef); 1834fa3d789dSPierre van Houtryve continue; 1835fa3d789dSPierre van Houtryve } 1836fa3d789dSPierre van Houtryve 1837fa3d789dSPierre van Houtryve // This class may have a default ReadWrite list which can be overriden by 1838fa3d789dSPierre van Houtryve // InstRW definitions. 18393ae71d15SRahul Joshi for (const Record *RW : SC.InstRWs) { 1840d256b9e8SRahul Joshi const Record *RWModelDef = RW->getValueAsDef("SchedModel"); 1841fa3d789dSPierre van Houtryve unsigned PIdx = getProcModel(RWModelDef).Index; 1842fa3d789dSPierre van Houtryve IdxVec Writes, Reads; 1843a140931bSRahul Joshi findRWs(RW->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); 1844fa3d789dSPierre van Houtryve collectRWResources(Writes, Reads, PIdx); 1845fa3d789dSPierre van Houtryve } 1846fa3d789dSPierre van Houtryve 1847fa3d789dSPierre van Houtryve collectRWResources(SC.Writes, SC.Reads, SC.ProcIndices); 1848fa3d789dSPierre van Houtryve } 1849fa3d789dSPierre van Houtryve // Add resources separately defined by each subtarget. 18503ae71d15SRahul Joshi for (const Record *WR : Records.getAllDerivedDefinitions("WriteRes")) { 18513ae71d15SRahul Joshi const Record *ModelDef = WR->getValueAsDef("SchedModel"); 1852082b1480SCraig Topper addWriteRes(WR, getProcModel(ModelDef)); 1853fa3d789dSPierre van Houtryve } 18543ae71d15SRahul Joshi for (const Record *SWR : Records.getAllDerivedDefinitions("SchedWriteRes")) { 18553ae71d15SRahul Joshi const Record *ModelDef = SWR->getValueAsDef("SchedModel"); 1856082b1480SCraig Topper addWriteRes(SWR, getProcModel(ModelDef)); 1857fa3d789dSPierre van Houtryve } 18583ae71d15SRahul Joshi for (const Record *RA : Records.getAllDerivedDefinitions("ReadAdvance")) { 18593ae71d15SRahul Joshi const Record *ModelDef = RA->getValueAsDef("SchedModel"); 1860082b1480SCraig Topper addReadAdvance(RA, getProcModel(ModelDef)); 1861fa3d789dSPierre van Houtryve } 18623ae71d15SRahul Joshi for (const Record *SRA : 18633ae71d15SRahul Joshi Records.getAllDerivedDefinitions("SchedReadAdvance")) { 1864fa3d789dSPierre van Houtryve if (SRA->getValueInit("SchedModel")->isComplete()) { 18653ae71d15SRahul Joshi const Record *ModelDef = SRA->getValueAsDef("SchedModel"); 1866082b1480SCraig Topper addReadAdvance(SRA, getProcModel(ModelDef)); 1867fa3d789dSPierre van Houtryve } 1868fa3d789dSPierre van Houtryve } 1869fa3d789dSPierre van Houtryve // Add ProcResGroups that are defined within this processor model, which may 1870fa3d789dSPierre van Houtryve // not be directly referenced but may directly specify a buffer size. 18713ae71d15SRahul Joshi for (const Record *PRG : Records.getAllDerivedDefinitions("ProcResGroup")) { 1872fa3d789dSPierre van Houtryve if (!PRG->getValueInit("SchedModel")->isComplete()) 1873fa3d789dSPierre van Houtryve continue; 1874fa3d789dSPierre van Houtryve CodeGenProcModel &PM = getProcModel(PRG->getValueAsDef("SchedModel")); 1875fa3d789dSPierre van Houtryve if (!is_contained(PM.ProcResourceDefs, PRG)) 1876fa3d789dSPierre van Houtryve PM.ProcResourceDefs.push_back(PRG); 1877fa3d789dSPierre van Houtryve } 1878fa3d789dSPierre van Houtryve // Add ProcResourceUnits unconditionally. 18793ae71d15SRahul Joshi for (const Record *PRU : 18803ae71d15SRahul Joshi Records.getAllDerivedDefinitions("ProcResourceUnits")) { 1881fa3d789dSPierre van Houtryve if (!PRU->getValueInit("SchedModel")->isComplete()) 1882fa3d789dSPierre van Houtryve continue; 1883fa3d789dSPierre van Houtryve CodeGenProcModel &PM = getProcModel(PRU->getValueAsDef("SchedModel")); 1884fa3d789dSPierre van Houtryve if (!is_contained(PM.ProcResourceDefs, PRU)) 1885fa3d789dSPierre van Houtryve PM.ProcResourceDefs.push_back(PRU); 1886fa3d789dSPierre van Houtryve } 1887fa3d789dSPierre van Houtryve // Finalize each ProcModel by sorting the record arrays. 1888fa3d789dSPierre van Houtryve for (CodeGenProcModel &PM : ProcModels) { 1889fa3d789dSPierre van Houtryve llvm::sort(PM.WriteResDefs, LessRecord()); 1890fa3d789dSPierre van Houtryve llvm::sort(PM.ReadAdvanceDefs, LessRecord()); 1891fa3d789dSPierre van Houtryve llvm::sort(PM.ProcResourceDefs, LessRecord()); 1892fa3d789dSPierre van Houtryve LLVM_DEBUG( 1893fa3d789dSPierre van Houtryve PM.dump(); dbgs() << "WriteResDefs: "; for (auto WriteResDef 1894fa3d789dSPierre van Houtryve : PM.WriteResDefs) { 1895fa3d789dSPierre van Houtryve if (WriteResDef->isSubClassOf("WriteRes")) 1896fa3d789dSPierre van Houtryve dbgs() << WriteResDef->getValueAsDef("WriteType")->getName() << " "; 1897fa3d789dSPierre van Houtryve else 1898fa3d789dSPierre van Houtryve dbgs() << WriteResDef->getName() << " "; 1899fa3d789dSPierre van Houtryve } dbgs() << "\nReadAdvanceDefs: "; 19003ae71d15SRahul Joshi for (const Record *ReadAdvanceDef 1901fa3d789dSPierre van Houtryve : PM.ReadAdvanceDefs) { 1902fa3d789dSPierre van Houtryve if (ReadAdvanceDef->isSubClassOf("ReadAdvance")) 1903fa3d789dSPierre van Houtryve dbgs() << ReadAdvanceDef->getValueAsDef("ReadType")->getName() 1904fa3d789dSPierre van Houtryve << " "; 1905fa3d789dSPierre van Houtryve else 1906fa3d789dSPierre van Houtryve dbgs() << ReadAdvanceDef->getName() << " "; 1907fa3d789dSPierre van Houtryve } dbgs() 1908fa3d789dSPierre van Houtryve << "\nProcResourceDefs: "; 19093ae71d15SRahul Joshi for (const Record *ProcResourceDef 1910fa3d789dSPierre van Houtryve : PM.ProcResourceDefs) { 1911fa3d789dSPierre van Houtryve dbgs() << ProcResourceDef->getName() << " "; 1912fa3d789dSPierre van Houtryve } dbgs() 1913fa3d789dSPierre van Houtryve << '\n'); 1914fa3d789dSPierre van Houtryve verifyProcResourceGroups(PM); 1915fa3d789dSPierre van Houtryve } 1916fa3d789dSPierre van Houtryve 1917fa3d789dSPierre van Houtryve ProcResourceDefs.clear(); 1918fa3d789dSPierre van Houtryve ProcResGroups.clear(); 1919fa3d789dSPierre van Houtryve } 1920fa3d789dSPierre van Houtryve 1921fa3d789dSPierre van Houtryve void CodeGenSchedModels::checkCompleteness() { 1922fa3d789dSPierre van Houtryve bool Complete = true; 1923fa3d789dSPierre van Houtryve for (const CodeGenProcModel &ProcModel : procModels()) { 1924fa3d789dSPierre van Houtryve const bool HasItineraries = ProcModel.hasItineraries(); 1925fa3d789dSPierre van Houtryve if (!ProcModel.ModelDef->getValueAsBit("CompleteModel")) 1926fa3d789dSPierre van Houtryve continue; 1927fa3d789dSPierre van Houtryve for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { 1928fa3d789dSPierre van Houtryve if (Inst->hasNoSchedulingInfo) 1929fa3d789dSPierre van Houtryve continue; 1930fa3d789dSPierre van Houtryve if (ProcModel.isUnsupported(*Inst)) 1931fa3d789dSPierre van Houtryve continue; 1932fa3d789dSPierre van Houtryve unsigned SCIdx = getSchedClassIdx(*Inst); 1933fa3d789dSPierre van Houtryve if (!SCIdx) { 1934fa3d789dSPierre van Houtryve if (Inst->TheDef->isValueUnset("SchedRW")) { 1935fa3d789dSPierre van Houtryve PrintError(Inst->TheDef->getLoc(), 1936fa3d789dSPierre van Houtryve "No schedule information for instruction '" + 1937fa3d789dSPierre van Houtryve Inst->TheDef->getName() + "' in SchedMachineModel '" + 1938fa3d789dSPierre van Houtryve ProcModel.ModelDef->getName() + "'"); 1939fa3d789dSPierre van Houtryve Complete = false; 1940fa3d789dSPierre van Houtryve } 1941fa3d789dSPierre van Houtryve continue; 1942fa3d789dSPierre van Houtryve } 1943fa3d789dSPierre van Houtryve 1944fa3d789dSPierre van Houtryve const CodeGenSchedClass &SC = getSchedClass(SCIdx); 1945fa3d789dSPierre van Houtryve if (!SC.Writes.empty()) 1946fa3d789dSPierre van Houtryve continue; 1947fa3d789dSPierre van Houtryve if (HasItineraries && SC.ItinClassDef != nullptr && 1948fa3d789dSPierre van Houtryve SC.ItinClassDef->getName() != "NoItinerary") 1949fa3d789dSPierre van Houtryve continue; 1950fa3d789dSPierre van Houtryve 19513ae71d15SRahul Joshi const ConstRecVec &InstRWs = SC.InstRWs; 1952fa3d789dSPierre van Houtryve auto I = find_if(InstRWs, [&ProcModel](const Record *R) { 1953fa3d789dSPierre van Houtryve return R->getValueAsDef("SchedModel") == ProcModel.ModelDef; 1954fa3d789dSPierre van Houtryve }); 1955fa3d789dSPierre van Houtryve if (I == InstRWs.end()) { 1956fa3d789dSPierre van Houtryve PrintError(Inst->TheDef->getLoc(), "'" + ProcModel.ModelName + 1957fa3d789dSPierre van Houtryve "' lacks information for '" + 1958fa3d789dSPierre van Houtryve Inst->TheDef->getName() + "'"); 1959fa3d789dSPierre van Houtryve Complete = false; 1960fa3d789dSPierre van Houtryve } 1961fa3d789dSPierre van Houtryve } 1962fa3d789dSPierre van Houtryve } 1963fa3d789dSPierre van Houtryve if (!Complete) { 1964fa3d789dSPierre van Houtryve errs() 1965fa3d789dSPierre van Houtryve << "\n\nIncomplete schedule models found.\n" 1966fa3d789dSPierre van Houtryve << "- Consider setting 'CompleteModel = 0' while developing new " 1967fa3d789dSPierre van Houtryve "models.\n" 1968fa3d789dSPierre van Houtryve << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = " 1969fa3d789dSPierre van Houtryve "1'.\n" 1970fa3d789dSPierre van Houtryve << "- Instructions should usually have Sched<[...]> as a superclass, " 1971fa3d789dSPierre van Houtryve "you may temporarily use an empty list.\n" 1972fa3d789dSPierre van Houtryve << "- Instructions related to unsupported features can be excluded " 1973fa3d789dSPierre van Houtryve "with " 1974fa3d789dSPierre van Houtryve "list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the " 1975fa3d789dSPierre van Houtryve "processor model.\n\n"; 1976fa3d789dSPierre van Houtryve PrintFatalError("Incomplete schedule model"); 1977fa3d789dSPierre van Houtryve } 1978fa3d789dSPierre van Houtryve } 1979fa3d789dSPierre van Houtryve 1980fa3d789dSPierre van Houtryve // Collect itinerary class resources for each processor. 1981c29dfb33SRahul Joshi void CodeGenSchedModels::collectItinProcResources(const Record *ItinClassDef) { 1982fa3d789dSPierre van Houtryve for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { 1983fa3d789dSPierre van Houtryve const CodeGenProcModel &PM = ProcModels[PIdx]; 1984fa3d789dSPierre van Houtryve // For all ItinRW entries. 1985fa3d789dSPierre van Houtryve bool HasMatch = false; 19863ae71d15SRahul Joshi for (const Record *R : PM.ItinRWDefs) { 1987a140931bSRahul Joshi ConstRecVec Matched = R->getValueAsListOfDefs("MatchedItinClasses"); 1988fa3d789dSPierre van Houtryve if (!llvm::is_contained(Matched, ItinClassDef)) 1989fa3d789dSPierre van Houtryve continue; 1990fa3d789dSPierre van Houtryve if (HasMatch) 19913ae71d15SRahul Joshi PrintFatalError(R->getLoc(), 1992fa3d789dSPierre van Houtryve "Duplicate itinerary class " + ItinClassDef->getName() + 1993fa3d789dSPierre van Houtryve " in ItinResources for " + PM.ModelName); 1994fa3d789dSPierre van Houtryve HasMatch = true; 1995fa3d789dSPierre van Houtryve IdxVec Writes, Reads; 1996a140931bSRahul Joshi findRWs(R->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); 1997fa3d789dSPierre van Houtryve collectRWResources(Writes, Reads, PIdx); 1998fa3d789dSPierre van Houtryve } 1999fa3d789dSPierre van Houtryve } 2000fa3d789dSPierre van Houtryve } 2001fa3d789dSPierre van Houtryve 2002fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectRWResources(unsigned RWIdx, bool IsRead, 2003fa3d789dSPierre van Houtryve ArrayRef<unsigned> ProcIndices) { 2004fa3d789dSPierre van Houtryve const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead); 2005fa3d789dSPierre van Houtryve if (SchedRW.TheDef) { 2006fa3d789dSPierre van Houtryve if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) { 2007fa3d789dSPierre van Houtryve for (unsigned Idx : ProcIndices) 2008082b1480SCraig Topper addWriteRes(SchedRW.TheDef, ProcModels[Idx]); 2009fa3d789dSPierre van Houtryve } else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) { 2010fa3d789dSPierre van Houtryve for (unsigned Idx : ProcIndices) 2011082b1480SCraig Topper addReadAdvance(SchedRW.TheDef, ProcModels[Idx]); 2012fa3d789dSPierre van Houtryve } 2013fa3d789dSPierre van Houtryve } 2014fa3d789dSPierre van Houtryve for (auto *Alias : SchedRW.Aliases) { 2015fa3d789dSPierre van Houtryve IdxVec AliasProcIndices; 2016fa3d789dSPierre van Houtryve if (Alias->getValueInit("SchedModel")->isComplete()) { 2017fa3d789dSPierre van Houtryve AliasProcIndices.push_back( 2018fa3d789dSPierre van Houtryve getProcModel(Alias->getValueAsDef("SchedModel")).Index); 2019fa3d789dSPierre van Houtryve } else 2020fa3d789dSPierre van Houtryve AliasProcIndices = ProcIndices; 2021fa3d789dSPierre van Houtryve const CodeGenSchedRW &AliasRW = getSchedRW(Alias->getValueAsDef("AliasRW")); 2022fa3d789dSPierre van Houtryve assert(AliasRW.IsRead == IsRead && "cannot alias reads to writes"); 2023fa3d789dSPierre van Houtryve 2024fa3d789dSPierre van Houtryve IdxVec ExpandedRWs; 2025fa3d789dSPierre van Houtryve expandRWSequence(AliasRW.Index, ExpandedRWs, IsRead); 2026fa3d789dSPierre van Houtryve for (unsigned int ExpandedRW : ExpandedRWs) { 2027fa3d789dSPierre van Houtryve collectRWResources(ExpandedRW, IsRead, AliasProcIndices); 2028fa3d789dSPierre van Houtryve } 2029fa3d789dSPierre van Houtryve } 2030fa3d789dSPierre van Houtryve } 2031fa3d789dSPierre van Houtryve 2032fa3d789dSPierre van Houtryve // Collect resources for a set of read/write types and processor indices. 2033fa3d789dSPierre van Houtryve void CodeGenSchedModels::collectRWResources(ArrayRef<unsigned> Writes, 2034fa3d789dSPierre van Houtryve ArrayRef<unsigned> Reads, 2035fa3d789dSPierre van Houtryve ArrayRef<unsigned> ProcIndices) { 2036fa3d789dSPierre van Houtryve for (unsigned Idx : Writes) 2037fa3d789dSPierre van Houtryve collectRWResources(Idx, /*IsRead=*/false, ProcIndices); 2038fa3d789dSPierre van Houtryve 2039fa3d789dSPierre van Houtryve for (unsigned Idx : Reads) 2040fa3d789dSPierre van Houtryve collectRWResources(Idx, /*IsRead=*/true, ProcIndices); 2041fa3d789dSPierre van Houtryve } 2042fa3d789dSPierre van Houtryve 2043fa3d789dSPierre van Houtryve // Find the processor's resource units for this kind of resource. 20443ae71d15SRahul Joshi const Record *CodeGenSchedModels::findProcResUnits(const Record *ProcResKind, 2045fa3d789dSPierre van Houtryve const CodeGenProcModel &PM, 2046fa3d789dSPierre van Houtryve ArrayRef<SMLoc> Loc) const { 2047fa3d789dSPierre van Houtryve if (ProcResKind->isSubClassOf("ProcResourceUnits")) 2048fa3d789dSPierre van Houtryve return ProcResKind; 2049fa3d789dSPierre van Houtryve 20503ae71d15SRahul Joshi const Record *ProcUnitDef = nullptr; 2051fa3d789dSPierre van Houtryve assert(!ProcResourceDefs.empty()); 2052fa3d789dSPierre van Houtryve assert(!ProcResGroups.empty()); 2053fa3d789dSPierre van Houtryve 20543ae71d15SRahul Joshi for (const Record *ProcResDef : ProcResourceDefs) { 2055fa3d789dSPierre van Houtryve if (ProcResDef->getValueAsDef("Kind") == ProcResKind && 2056fa3d789dSPierre van Houtryve ProcResDef->getValueAsDef("SchedModel") == PM.ModelDef) { 2057fa3d789dSPierre van Houtryve if (ProcUnitDef) { 2058fa3d789dSPierre van Houtryve PrintFatalError(Loc, 2059fa3d789dSPierre van Houtryve "Multiple ProcessorResourceUnits associated with " + 2060fa3d789dSPierre van Houtryve ProcResKind->getName()); 2061fa3d789dSPierre van Houtryve } 2062fa3d789dSPierre van Houtryve ProcUnitDef = ProcResDef; 2063fa3d789dSPierre van Houtryve } 2064fa3d789dSPierre van Houtryve } 20653ae71d15SRahul Joshi for (const Record *ProcResGroup : ProcResGroups) { 2066fa3d789dSPierre van Houtryve if (ProcResGroup == ProcResKind && 2067fa3d789dSPierre van Houtryve ProcResGroup->getValueAsDef("SchedModel") == PM.ModelDef) { 2068fa3d789dSPierre van Houtryve if (ProcUnitDef) { 2069fa3d789dSPierre van Houtryve PrintFatalError(Loc, 2070fa3d789dSPierre van Houtryve "Multiple ProcessorResourceUnits associated with " + 2071fa3d789dSPierre van Houtryve ProcResKind->getName()); 2072fa3d789dSPierre van Houtryve } 2073fa3d789dSPierre van Houtryve ProcUnitDef = ProcResGroup; 2074fa3d789dSPierre van Houtryve } 2075fa3d789dSPierre van Houtryve } 2076fa3d789dSPierre van Houtryve if (!ProcUnitDef) { 2077fa3d789dSPierre van Houtryve PrintFatalError(Loc, "No ProcessorResources associated with " + 2078fa3d789dSPierre van Houtryve ProcResKind->getName()); 2079fa3d789dSPierre van Houtryve } 2080fa3d789dSPierre van Houtryve return ProcUnitDef; 2081fa3d789dSPierre van Houtryve } 2082fa3d789dSPierre van Houtryve 2083fa3d789dSPierre van Houtryve // Iteratively add a resource and its super resources. 20843ae71d15SRahul Joshi void CodeGenSchedModels::addProcResource(const Record *ProcResKind, 2085fa3d789dSPierre van Houtryve CodeGenProcModel &PM, 2086fa3d789dSPierre van Houtryve ArrayRef<SMLoc> Loc) { 2087fa3d789dSPierre van Houtryve while (true) { 20883ae71d15SRahul Joshi const Record *ProcResUnits = findProcResUnits(ProcResKind, PM, Loc); 2089fa3d789dSPierre van Houtryve 2090fa3d789dSPierre van Houtryve // See if this ProcResource is already associated with this processor. 2091fa3d789dSPierre van Houtryve if (is_contained(PM.ProcResourceDefs, ProcResUnits)) 2092fa3d789dSPierre van Houtryve return; 2093fa3d789dSPierre van Houtryve 2094fa3d789dSPierre van Houtryve PM.ProcResourceDefs.push_back(ProcResUnits); 2095fa3d789dSPierre van Houtryve if (ProcResUnits->isSubClassOf("ProcResGroup")) 2096fa3d789dSPierre van Houtryve return; 2097fa3d789dSPierre van Houtryve 2098fa3d789dSPierre van Houtryve if (!ProcResUnits->getValueInit("Super")->isComplete()) 2099fa3d789dSPierre van Houtryve return; 2100fa3d789dSPierre van Houtryve 2101fa3d789dSPierre van Houtryve ProcResKind = ProcResUnits->getValueAsDef("Super"); 2102fa3d789dSPierre van Houtryve } 2103fa3d789dSPierre van Houtryve } 2104fa3d789dSPierre van Houtryve 2105fa3d789dSPierre van Houtryve // Add resources for a SchedWrite to this processor if they don't exist. 21063ae71d15SRahul Joshi void CodeGenSchedModels::addWriteRes(const Record *ProcWriteResDef, 2107082b1480SCraig Topper CodeGenProcModel &PM) { 2108082b1480SCraig Topper ConstRecVec &WRDefs = PM.WriteResDefs; 2109fa3d789dSPierre van Houtryve if (is_contained(WRDefs, ProcWriteResDef)) 2110fa3d789dSPierre van Houtryve return; 2111fa3d789dSPierre van Houtryve WRDefs.push_back(ProcWriteResDef); 2112fa3d789dSPierre van Houtryve 2113517334bdSCraig Topper if (ProcWriteResDef->isSubClassOf("WriteRes")) { 2114082b1480SCraig Topper auto &WRMap = PM.WriteResMap; 2115517334bdSCraig Topper const Record *WRDef = ProcWriteResDef->getValueAsDef("WriteType"); 2116517334bdSCraig Topper if (!WRMap.try_emplace(WRDef, ProcWriteResDef).second) 2117517334bdSCraig Topper PrintFatalError(ProcWriteResDef->getLoc(), 2118517334bdSCraig Topper "WriteType already used in another WriteRes"); 2119517334bdSCraig Topper } 2120517334bdSCraig Topper 2121fa3d789dSPierre van Houtryve // Visit ProcResourceKinds referenced by the newly discovered WriteRes. 2122c29dfb33SRahul Joshi for (const Record *ProcResDef : 2123c29dfb33SRahul Joshi ProcWriteResDef->getValueAsListOfDefs("ProcResources")) { 2124082b1480SCraig Topper addProcResource(ProcResDef, PM, ProcWriteResDef->getLoc()); 2125fa3d789dSPierre van Houtryve } 2126fa3d789dSPierre van Houtryve } 2127fa3d789dSPierre van Houtryve 2128fa3d789dSPierre van Houtryve // Add resources for a ReadAdvance to this processor if they don't exist. 21293ae71d15SRahul Joshi void CodeGenSchedModels::addReadAdvance(const Record *ProcReadAdvanceDef, 2130082b1480SCraig Topper CodeGenProcModel &PM) { 2131fa3d789dSPierre van Houtryve for (const Record *ValidWrite : 2132*e19261faSCraig Topper ProcReadAdvanceDef->getValueAsListOfDefs("ValidWrites")) { 2133fa3d789dSPierre van Houtryve if (getSchedRWIdx(ValidWrite, /*IsRead=*/false) == 0) 2134fa3d789dSPierre van Houtryve PrintFatalError( 2135fa3d789dSPierre van Houtryve ProcReadAdvanceDef->getLoc(), 2136fa3d789dSPierre van Houtryve "ReadAdvance referencing a ValidWrite that is not used by " 2137fa3d789dSPierre van Houtryve "any instruction (" + 2138fa3d789dSPierre van Houtryve ValidWrite->getName() + ")"); 2139*e19261faSCraig Topper PM.ReadOfWriteSet.insert(ValidWrite); 2140*e19261faSCraig Topper } 2141fa3d789dSPierre van Houtryve 2142082b1480SCraig Topper ConstRecVec &RADefs = PM.ReadAdvanceDefs; 2143fa3d789dSPierre van Houtryve if (is_contained(RADefs, ProcReadAdvanceDef)) 2144fa3d789dSPierre van Houtryve return; 2145fa3d789dSPierre van Houtryve RADefs.push_back(ProcReadAdvanceDef); 2146517334bdSCraig Topper 2147517334bdSCraig Topper if (ProcReadAdvanceDef->isSubClassOf("ReadAdvance")) { 2148082b1480SCraig Topper auto &RAMap = PM.ReadAdvanceMap; 2149517334bdSCraig Topper const Record *RADef = ProcReadAdvanceDef->getValueAsDef("ReadType"); 2150517334bdSCraig Topper if (!RAMap.try_emplace(RADef, ProcReadAdvanceDef).second) 2151517334bdSCraig Topper PrintFatalError(ProcReadAdvanceDef->getLoc(), 2152517334bdSCraig Topper "ReadType already used in another ReadAdvance"); 2153517334bdSCraig Topper } 2154fa3d789dSPierre van Houtryve } 2155fa3d789dSPierre van Houtryve 21563ae71d15SRahul Joshi unsigned CodeGenProcModel::getProcResourceIdx(const Record *PRDef) const { 21573ae71d15SRahul Joshi ConstRecIter PRPos = find(ProcResourceDefs, PRDef); 2158fa3d789dSPierre van Houtryve if (PRPos == ProcResourceDefs.end()) 2159fa3d789dSPierre van Houtryve PrintFatalError(PRDef->getLoc(), "ProcResource def is not included in " 2160fa3d789dSPierre van Houtryve "the ProcResources list for " + 2161fa3d789dSPierre van Houtryve ModelName); 2162fa3d789dSPierre van Houtryve // Idx=0 is reserved for invalid. 2163fa3d789dSPierre van Houtryve return 1 + (PRPos - ProcResourceDefs.begin()); 2164fa3d789dSPierre van Houtryve } 2165fa3d789dSPierre van Houtryve 2166fa3d789dSPierre van Houtryve bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const { 2167fa3d789dSPierre van Houtryve for (const Record *TheDef : UnsupportedFeaturesDefs) { 2168fa3d789dSPierre van Houtryve for (const Record *PredDef : 2169fa3d789dSPierre van Houtryve Inst.TheDef->getValueAsListOfDefs("Predicates")) { 2170fa3d789dSPierre van Houtryve if (TheDef->getName() == PredDef->getName()) 2171fa3d789dSPierre van Houtryve return true; 2172fa3d789dSPierre van Houtryve } 2173fa3d789dSPierre van Houtryve } 2174fa3d789dSPierre van Houtryve return false; 2175fa3d789dSPierre van Houtryve } 2176fa3d789dSPierre van Houtryve 21773ae71d15SRahul Joshi bool CodeGenProcModel::hasReadOfWrite(const Record *WriteDef) const { 2178*e19261faSCraig Topper return ReadOfWriteSet.count(WriteDef); 217967beebfcSMichael Maitland } 218067beebfcSMichael Maitland 2181fa3d789dSPierre van Houtryve #ifndef NDEBUG 2182fa3d789dSPierre van Houtryve void CodeGenProcModel::dump() const { 2183fa3d789dSPierre van Houtryve dbgs() << Index << ": " << ModelName << " " 2184fa3d789dSPierre van Houtryve << (ModelDef ? ModelDef->getName() : "inferred") << " " 2185fa3d789dSPierre van Houtryve << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n'; 2186fa3d789dSPierre van Houtryve } 2187fa3d789dSPierre van Houtryve 2188fa3d789dSPierre van Houtryve void CodeGenSchedRW::dump() const { 2189fa3d789dSPierre van Houtryve dbgs() << Name << (IsVariadic ? " (V) " : " "); 2190fa3d789dSPierre van Houtryve if (IsSequence) { 2191fa3d789dSPierre van Houtryve dbgs() << "("; 2192fa3d789dSPierre van Houtryve dumpIdxVec(Sequence); 2193fa3d789dSPierre van Houtryve dbgs() << ")"; 2194fa3d789dSPierre van Houtryve } 2195fa3d789dSPierre van Houtryve } 2196fa3d789dSPierre van Houtryve 2197fa3d789dSPierre van Houtryve void CodeGenSchedClass::dump(const CodeGenSchedModels *SchedModels) const { 2198fa3d789dSPierre van Houtryve dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n' << " Writes: "; 2199fa3d789dSPierre van Houtryve for (unsigned i = 0, N = Writes.size(); i < N; ++i) { 2200fa3d789dSPierre van Houtryve SchedModels->getSchedWrite(Writes[i]).dump(); 2201fa3d789dSPierre van Houtryve if (i < N - 1) { 2202fa3d789dSPierre van Houtryve dbgs() << '\n'; 2203fa3d789dSPierre van Houtryve dbgs().indent(10); 2204fa3d789dSPierre van Houtryve } 2205fa3d789dSPierre van Houtryve } 2206fa3d789dSPierre van Houtryve dbgs() << "\n Reads: "; 2207fa3d789dSPierre van Houtryve for (unsigned i = 0, N = Reads.size(); i < N; ++i) { 2208fa3d789dSPierre van Houtryve SchedModels->getSchedRead(Reads[i]).dump(); 2209fa3d789dSPierre van Houtryve if (i < N - 1) { 2210fa3d789dSPierre van Houtryve dbgs() << '\n'; 2211fa3d789dSPierre van Houtryve dbgs().indent(10); 2212fa3d789dSPierre van Houtryve } 2213fa3d789dSPierre van Houtryve } 2214fa3d789dSPierre van Houtryve dbgs() << "\n ProcIdx: "; 2215fa3d789dSPierre van Houtryve dumpIdxVec(ProcIndices); 2216fa3d789dSPierre van Houtryve if (!Transitions.empty()) { 2217fa3d789dSPierre van Houtryve dbgs() << "\n Transitions for Proc "; 2218fa3d789dSPierre van Houtryve for (const CodeGenSchedTransition &Transition : Transitions) { 2219fa3d789dSPierre van Houtryve dbgs() << Transition.ProcIndex << ", "; 2220fa3d789dSPierre van Houtryve } 2221fa3d789dSPierre van Houtryve } 2222fa3d789dSPierre van Houtryve dbgs() << '\n'; 2223fa3d789dSPierre van Houtryve } 2224fa3d789dSPierre van Houtryve 2225fa3d789dSPierre van Houtryve void PredTransitions::dump() const { 2226fa3d789dSPierre van Houtryve dbgs() << "Expanded Variants:\n"; 2227fa3d789dSPierre van Houtryve for (const auto &TI : TransVec) { 2228fa3d789dSPierre van Houtryve dbgs() << "{"; 2229fa3d789dSPierre van Houtryve ListSeparator LS; 2230fa3d789dSPierre van Houtryve for (const PredCheck &PC : TI.PredTerm) 2231fa3d789dSPierre van Houtryve dbgs() << LS << SchedModels.getSchedRW(PC.RWIdx, PC.IsRead).Name << ":" 2232fa3d789dSPierre van Houtryve << PC.Predicate->getName(); 2233fa3d789dSPierre van Houtryve dbgs() << "},\n => {"; 2234fa3d789dSPierre van Houtryve for (SmallVectorImpl<SmallVector<unsigned, 4>>::const_iterator 2235fa3d789dSPierre van Houtryve WSI = TI.WriteSequences.begin(), 2236fa3d789dSPierre van Houtryve WSE = TI.WriteSequences.end(); 2237fa3d789dSPierre van Houtryve WSI != WSE; ++WSI) { 2238fa3d789dSPierre van Houtryve dbgs() << "("; 2239fa3d789dSPierre van Houtryve ListSeparator LS; 2240fa3d789dSPierre van Houtryve for (unsigned N : *WSI) 2241fa3d789dSPierre van Houtryve dbgs() << LS << SchedModels.getSchedWrite(N).Name; 2242fa3d789dSPierre van Houtryve dbgs() << "),"; 2243fa3d789dSPierre van Houtryve } 2244fa3d789dSPierre van Houtryve dbgs() << "}\n"; 2245fa3d789dSPierre van Houtryve } 2246fa3d789dSPierre van Houtryve } 2247fa3d789dSPierre van Houtryve #endif // NDEBUG 2248