10b57cec5SDimitry Andric //===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines structures to encapsulate the machine model as described in
100b57cec5SDimitry Andric // the target description.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "CodeGenSchedule.h"
150b57cec5SDimitry Andric #include "CodeGenInstruction.h"
160b57cec5SDimitry Andric #include "CodeGenTarget.h"
170b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h"
180b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
210b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
220b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
230b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
260b57cec5SDimitry Andric #include <algorithm>
270b57cec5SDimitry Andric #include <iterator>
280b57cec5SDimitry Andric #include <utility>
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric using namespace llvm;
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric #define DEBUG_TYPE "subtarget-emitter"
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric #ifndef NDEBUG
dumpIdxVec(ArrayRef<unsigned> V)350b57cec5SDimitry Andric static void dumpIdxVec(ArrayRef<unsigned> V) {
360b57cec5SDimitry Andric for (unsigned Idx : V)
370b57cec5SDimitry Andric dbgs() << Idx << ", ";
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric #endif
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric namespace {
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp.
440b57cec5SDimitry Andric struct InstrsOp : public SetTheory::Operator {
apply__anon3a1684130111::InstrsOp450b57cec5SDimitry Andric void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
460b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) override {
470b57cec5SDimitry Andric ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric };
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric // (instregex "OpcPat",...) Find all instructions matching an opcode pattern.
520b57cec5SDimitry Andric struct InstRegexOp : public SetTheory::Operator {
530b57cec5SDimitry Andric const CodeGenTarget &Target;
InstRegexOp__anon3a1684130111::InstRegexOp540b57cec5SDimitry Andric InstRegexOp(const CodeGenTarget &t): Target(t) {}
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric /// Remove any text inside of parentheses from S.
removeParens__anon3a1684130111::InstRegexOp570b57cec5SDimitry Andric static std::string removeParens(llvm::StringRef S) {
580b57cec5SDimitry Andric std::string Result;
590b57cec5SDimitry Andric unsigned Paren = 0;
600b57cec5SDimitry Andric // NB: We don't care about escaped parens here.
610b57cec5SDimitry Andric for (char C : S) {
620b57cec5SDimitry Andric switch (C) {
630b57cec5SDimitry Andric case '(':
640b57cec5SDimitry Andric ++Paren;
650b57cec5SDimitry Andric break;
660b57cec5SDimitry Andric case ')':
670b57cec5SDimitry Andric --Paren;
680b57cec5SDimitry Andric break;
690b57cec5SDimitry Andric default:
700b57cec5SDimitry Andric if (Paren == 0)
710b57cec5SDimitry Andric Result += C;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric return Result;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric
apply__anon3a1684130111::InstRegexOp770b57cec5SDimitry Andric void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
780b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) override {
790b57cec5SDimitry Andric ArrayRef<const CodeGenInstruction *> Instructions =
800b57cec5SDimitry Andric Target.getInstructionsByEnumValue();
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric unsigned NumGeneric = Target.getNumFixedInstructions();
830b57cec5SDimitry Andric unsigned NumPseudos = Target.getNumPseudoInstructions();
840b57cec5SDimitry Andric auto Generics = Instructions.slice(0, NumGeneric);
850b57cec5SDimitry Andric auto Pseudos = Instructions.slice(NumGeneric, NumPseudos);
860b57cec5SDimitry Andric auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos);
870b57cec5SDimitry Andric
88e8d8bef9SDimitry Andric for (Init *Arg : Expr->getArgs()) {
890b57cec5SDimitry Andric StringInit *SI = dyn_cast<StringInit>(Arg);
900b57cec5SDimitry Andric if (!SI)
910b57cec5SDimitry Andric PrintFatalError(Loc, "instregex requires pattern string: " +
920b57cec5SDimitry Andric Expr->getAsString());
930b57cec5SDimitry Andric StringRef Original = SI->getValue();
94*c9157d92SDimitry Andric // Drop an explicit ^ anchor to not interfere with prefix search.
95*c9157d92SDimitry Andric bool HadAnchor = Original.consume_front("^");
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric // Extract a prefix that we can binary search on.
980b57cec5SDimitry Andric static const char RegexMetachars[] = "()^$|*+?.[]\\{}";
990b57cec5SDimitry Andric auto FirstMeta = Original.find_first_of(RegexMetachars);
100*c9157d92SDimitry Andric if (FirstMeta != StringRef::npos && FirstMeta > 0) {
101*c9157d92SDimitry Andric // If we have a regex like ABC* we can only use AB as the prefix, as
102*c9157d92SDimitry Andric // the * acts on C.
103*c9157d92SDimitry Andric switch (Original[FirstMeta]) {
104*c9157d92SDimitry Andric case '+':
105*c9157d92SDimitry Andric case '*':
106*c9157d92SDimitry Andric case '?':
107*c9157d92SDimitry Andric --FirstMeta;
108*c9157d92SDimitry Andric break;
109*c9157d92SDimitry Andric default:
110*c9157d92SDimitry Andric break;
111*c9157d92SDimitry Andric }
112*c9157d92SDimitry Andric }
1130b57cec5SDimitry Andric
1140b57cec5SDimitry Andric // Look for top-level | or ?. We cannot optimize them to binary search.
1150b57cec5SDimitry Andric if (removeParens(Original).find_first_of("|?") != std::string::npos)
1160b57cec5SDimitry Andric FirstMeta = 0;
1170b57cec5SDimitry Andric
118bdd1243dSDimitry Andric std::optional<Regex> Regexpr;
1190b57cec5SDimitry Andric StringRef Prefix = Original.substr(0, FirstMeta);
1200b57cec5SDimitry Andric StringRef PatStr = Original.substr(FirstMeta);
1210b57cec5SDimitry Andric if (!PatStr.empty()) {
1220b57cec5SDimitry Andric // For the rest use a python-style prefix match.
1235ffd83dbSDimitry Andric std::string pat = std::string(PatStr);
124*c9157d92SDimitry Andric // Add ^ anchor. If we had one originally, don't need the group.
125*c9157d92SDimitry Andric if (HadAnchor) {
126*c9157d92SDimitry Andric pat.insert(0, "^");
127*c9157d92SDimitry Andric } else {
1280b57cec5SDimitry Andric pat.insert(0, "^(");
1290b57cec5SDimitry Andric pat.insert(pat.end(), ')');
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric Regexpr = Regex(pat);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric int NumMatches = 0;
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric // The generic opcodes are unsorted, handle them manually.
1370b57cec5SDimitry Andric for (auto *Inst : Generics) {
1380b57cec5SDimitry Andric StringRef InstName = Inst->TheDef->getName();
139*c9157d92SDimitry Andric if (InstName.starts_with(Prefix) &&
1400b57cec5SDimitry Andric (!Regexpr || Regexpr->match(InstName.substr(Prefix.size())))) {
1410b57cec5SDimitry Andric Elts.insert(Inst->TheDef);
1420b57cec5SDimitry Andric NumMatches++;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
1460b57cec5SDimitry Andric // Target instructions are split into two ranges: pseudo instructions
1470b57cec5SDimitry Andric // first, than non-pseudos. Each range is in lexicographical order
1480b57cec5SDimitry Andric // sorted by name. Find the sub-ranges that start with our prefix.
1490b57cec5SDimitry Andric struct Comp {
1500b57cec5SDimitry Andric bool operator()(const CodeGenInstruction *LHS, StringRef RHS) {
1510b57cec5SDimitry Andric return LHS->TheDef->getName() < RHS;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric bool operator()(StringRef LHS, const CodeGenInstruction *RHS) {
1540b57cec5SDimitry Andric return LHS < RHS->TheDef->getName() &&
155*c9157d92SDimitry Andric !RHS->TheDef->getName().starts_with(LHS);
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric };
1580b57cec5SDimitry Andric auto Range1 =
1590b57cec5SDimitry Andric std::equal_range(Pseudos.begin(), Pseudos.end(), Prefix, Comp());
1600b57cec5SDimitry Andric auto Range2 = std::equal_range(NonPseudos.begin(), NonPseudos.end(),
1610b57cec5SDimitry Andric Prefix, Comp());
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric // For these ranges we know that instruction names start with the prefix.
1640b57cec5SDimitry Andric // Check if there's a regex that needs to be checked.
1650b57cec5SDimitry Andric const auto HandleNonGeneric = [&](const CodeGenInstruction *Inst) {
1660b57cec5SDimitry Andric StringRef InstName = Inst->TheDef->getName();
1670b57cec5SDimitry Andric if (!Regexpr || Regexpr->match(InstName.substr(Prefix.size()))) {
1680b57cec5SDimitry Andric Elts.insert(Inst->TheDef);
1690b57cec5SDimitry Andric NumMatches++;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric };
1720b57cec5SDimitry Andric std::for_each(Range1.first, Range1.second, HandleNonGeneric);
1730b57cec5SDimitry Andric std::for_each(Range2.first, Range2.second, HandleNonGeneric);
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric if (0 == NumMatches)
1760b57cec5SDimitry Andric PrintFatalError(Loc, "instregex has no matches: " + Original);
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric };
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric } // end anonymous namespace
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric /// CodeGenModels ctor interprets machine model records and populates maps.
CodeGenSchedModels(RecordKeeper & RK,const CodeGenTarget & TGT)1840b57cec5SDimitry Andric CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
1850b57cec5SDimitry Andric const CodeGenTarget &TGT):
1860b57cec5SDimitry Andric Records(RK), Target(TGT) {
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric Sets.addFieldExpander("InstRW", "Instrs");
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric // Allow Set evaluation to recognize the dags used in InstRW records:
1910b57cec5SDimitry Andric // (instrs Op1, Op1...)
1928bcb0991SDimitry Andric Sets.addOperator("instrs", std::make_unique<InstrsOp>());
1938bcb0991SDimitry Andric Sets.addOperator("instregex", std::make_unique<InstRegexOp>(Target));
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric // Instantiate a CodeGenProcModel for each SchedMachineModel with the values
1960b57cec5SDimitry Andric // that are explicitly referenced in tablegen records. Resources associated
1970b57cec5SDimitry Andric // with each processor will be derived later. Populate ProcModelMap with the
1980b57cec5SDimitry Andric // CodeGenProcModel instances.
1990b57cec5SDimitry Andric collectProcModels();
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly
2020b57cec5SDimitry Andric // defined, and populate SchedReads and SchedWrites vectors. Implicit
2030b57cec5SDimitry Andric // SchedReadWrites that represent sequences derived from expanded variant will
2040b57cec5SDimitry Andric // be inferred later.
2050b57cec5SDimitry Andric collectSchedRW();
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly
2080b57cec5SDimitry Andric // required by an instruction definition, and populate SchedClassIdxMap. Set
2090b57cec5SDimitry Andric // NumItineraryClasses to the number of explicit itinerary classes referenced
2100b57cec5SDimitry Andric // by instructions. Set NumInstrSchedClasses to the number of itinerary
2110b57cec5SDimitry Andric // classes plus any classes implied by instructions that derive from class
2120b57cec5SDimitry Andric // Sched and provide SchedRW list. This does not infer any new classes from
2130b57cec5SDimitry Andric // SchedVariant.
2140b57cec5SDimitry Andric collectSchedClasses();
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric // Find instruction itineraries for each processor. Sort and populate
2170b57cec5SDimitry Andric // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires
2180b57cec5SDimitry Andric // all itinerary classes to be discovered.
2190b57cec5SDimitry Andric collectProcItins();
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric // Find ItinRW records for each processor and itinerary class.
2220b57cec5SDimitry Andric // (For per-operand resources mapped to itinerary classes).
2230b57cec5SDimitry Andric collectProcItinRW();
2240b57cec5SDimitry Andric
2250b57cec5SDimitry Andric // Find UnsupportedFeatures records for each processor.
2260b57cec5SDimitry Andric // (For per-operand resources mapped to itinerary classes).
2270b57cec5SDimitry Andric collectProcUnsupportedFeatures();
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric // Infer new SchedClasses from SchedVariant.
2300b57cec5SDimitry Andric inferSchedClasses();
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and
2330b57cec5SDimitry Andric // ProcResourceDefs.
2340b57cec5SDimitry Andric LLVM_DEBUG(
2350b57cec5SDimitry Andric dbgs() << "\n+++ RESOURCE DEFINITIONS (collectProcResources) +++\n");
2360b57cec5SDimitry Andric collectProcResources();
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric // Collect optional processor description.
2390b57cec5SDimitry Andric collectOptionalProcessorInfo();
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric // Check MCInstPredicate definitions.
2420b57cec5SDimitry Andric checkMCInstPredicates();
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric // Check STIPredicate definitions.
2450b57cec5SDimitry Andric checkSTIPredicates();
2460b57cec5SDimitry Andric
2470b57cec5SDimitry Andric // Find STIPredicate definitions for each processor model, and construct
2480b57cec5SDimitry Andric // STIPredicateFunction objects.
2490b57cec5SDimitry Andric collectSTIPredicates();
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric checkCompleteness();
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
checkSTIPredicates() const2540b57cec5SDimitry Andric void CodeGenSchedModels::checkSTIPredicates() const {
2550b57cec5SDimitry Andric DenseMap<StringRef, const Record *> Declarations;
2560b57cec5SDimitry Andric
2570b57cec5SDimitry Andric // There cannot be multiple declarations with the same name.
2580b57cec5SDimitry Andric const RecVec Decls = Records.getAllDerivedDefinitions("STIPredicateDecl");
2590b57cec5SDimitry Andric for (const Record *R : Decls) {
2600b57cec5SDimitry Andric StringRef Name = R->getValueAsString("Name");
2610b57cec5SDimitry Andric const auto It = Declarations.find(Name);
2620b57cec5SDimitry Andric if (It == Declarations.end()) {
2630b57cec5SDimitry Andric Declarations[Name] = R;
2640b57cec5SDimitry Andric continue;
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric
2670b57cec5SDimitry Andric PrintError(R->getLoc(), "STIPredicate " + Name + " multiply declared.");
268e8d8bef9SDimitry Andric PrintFatalNote(It->second->getLoc(), "Previous declaration was here.");
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric
2710b57cec5SDimitry Andric // Disallow InstructionEquivalenceClasses with an empty instruction list.
2720b57cec5SDimitry Andric const RecVec Defs =
2730b57cec5SDimitry Andric Records.getAllDerivedDefinitions("InstructionEquivalenceClass");
2740b57cec5SDimitry Andric for (const Record *R : Defs) {
2750b57cec5SDimitry Andric RecVec Opcodes = R->getValueAsListOfDefs("Opcodes");
2760b57cec5SDimitry Andric if (Opcodes.empty()) {
2770b57cec5SDimitry Andric PrintFatalError(R->getLoc(), "Invalid InstructionEquivalenceClass "
2780b57cec5SDimitry Andric "defined with an empty opcode list.");
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric // Used by function `processSTIPredicate` to construct a mask of machine
2840b57cec5SDimitry Andric // instruction operands.
constructOperandMask(ArrayRef<int64_t> Indices)2850b57cec5SDimitry Andric static APInt constructOperandMask(ArrayRef<int64_t> Indices) {
2860b57cec5SDimitry Andric APInt OperandMask;
2870b57cec5SDimitry Andric if (Indices.empty())
2880b57cec5SDimitry Andric return OperandMask;
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric int64_t MaxIndex = *std::max_element(Indices.begin(), Indices.end());
2910b57cec5SDimitry Andric assert(MaxIndex >= 0 && "Invalid negative indices in input!");
2920b57cec5SDimitry Andric OperandMask = OperandMask.zext(MaxIndex + 1);
2930b57cec5SDimitry Andric for (const int64_t Index : Indices) {
2940b57cec5SDimitry Andric assert(Index >= 0 && "Invalid negative indices!");
2950b57cec5SDimitry Andric OperandMask.setBit(Index);
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric
2980b57cec5SDimitry Andric return OperandMask;
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric static void
processSTIPredicate(STIPredicateFunction & Fn,const ProcModelMapTy & ProcModelMap)3020b57cec5SDimitry Andric processSTIPredicate(STIPredicateFunction &Fn,
303e8d8bef9SDimitry Andric const ProcModelMapTy &ProcModelMap) {
3040b57cec5SDimitry Andric DenseMap<const Record *, unsigned> Opcode2Index;
3050b57cec5SDimitry Andric using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>;
3060b57cec5SDimitry Andric std::vector<OpcodeMapPair> OpcodeMappings;
3070b57cec5SDimitry Andric std::vector<std::pair<APInt, APInt>> OpcodeMasks;
3080b57cec5SDimitry Andric
3090b57cec5SDimitry Andric DenseMap<const Record *, unsigned> Predicate2Index;
3100b57cec5SDimitry Andric unsigned NumUniquePredicates = 0;
3110b57cec5SDimitry Andric
3120b57cec5SDimitry Andric // Number unique predicates and opcodes used by InstructionEquivalenceClass
3130b57cec5SDimitry Andric // definitions. Each unique opcode will be associated with an OpcodeInfo
3140b57cec5SDimitry Andric // object.
3150b57cec5SDimitry Andric for (const Record *Def : Fn.getDefinitions()) {
3160b57cec5SDimitry Andric RecVec Classes = Def->getValueAsListOfDefs("Classes");
3170b57cec5SDimitry Andric for (const Record *EC : Classes) {
3180b57cec5SDimitry Andric const Record *Pred = EC->getValueAsDef("Predicate");
319fe013be4SDimitry Andric if (!Predicate2Index.contains(Pred))
3200b57cec5SDimitry Andric Predicate2Index[Pred] = NumUniquePredicates++;
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andric RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes");
3230b57cec5SDimitry Andric for (const Record *Opcode : Opcodes) {
324fe013be4SDimitry Andric if (!Opcode2Index.contains(Opcode)) {
3250b57cec5SDimitry Andric Opcode2Index[Opcode] = OpcodeMappings.size();
3260b57cec5SDimitry Andric OpcodeMappings.emplace_back(Opcode, OpcodeInfo());
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric
3320b57cec5SDimitry Andric // Initialize vector `OpcodeMasks` with default values. We want to keep track
3330b57cec5SDimitry Andric // of which processors "use" which opcodes. We also want to be able to
3340b57cec5SDimitry Andric // identify predicates that are used by different processors for a same
3350b57cec5SDimitry Andric // opcode.
3360b57cec5SDimitry Andric // This information is used later on by this algorithm to sort OpcodeMapping
3370b57cec5SDimitry Andric // elements based on their processor and predicate sets.
3380b57cec5SDimitry Andric OpcodeMasks.resize(OpcodeMappings.size());
3390b57cec5SDimitry Andric APInt DefaultProcMask(ProcModelMap.size(), 0);
3400b57cec5SDimitry Andric APInt DefaultPredMask(NumUniquePredicates, 0);
3410b57cec5SDimitry Andric for (std::pair<APInt, APInt> &MaskPair : OpcodeMasks)
3420b57cec5SDimitry Andric MaskPair = std::make_pair(DefaultProcMask, DefaultPredMask);
3430b57cec5SDimitry Andric
3440b57cec5SDimitry Andric // Construct a OpcodeInfo object for every unique opcode declared by an
3450b57cec5SDimitry Andric // InstructionEquivalenceClass definition.
3460b57cec5SDimitry Andric for (const Record *Def : Fn.getDefinitions()) {
3470b57cec5SDimitry Andric RecVec Classes = Def->getValueAsListOfDefs("Classes");
3480b57cec5SDimitry Andric const Record *SchedModel = Def->getValueAsDef("SchedModel");
3490b57cec5SDimitry Andric unsigned ProcIndex = ProcModelMap.find(SchedModel)->second;
3500b57cec5SDimitry Andric APInt ProcMask(ProcModelMap.size(), 0);
3510b57cec5SDimitry Andric ProcMask.setBit(ProcIndex);
3520b57cec5SDimitry Andric
3530b57cec5SDimitry Andric for (const Record *EC : Classes) {
3540b57cec5SDimitry Andric RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes");
3550b57cec5SDimitry Andric
3560b57cec5SDimitry Andric std::vector<int64_t> OpIndices =
3570b57cec5SDimitry Andric EC->getValueAsListOfInts("OperandIndices");
3580b57cec5SDimitry Andric APInt OperandMask = constructOperandMask(OpIndices);
3590b57cec5SDimitry Andric
3600b57cec5SDimitry Andric const Record *Pred = EC->getValueAsDef("Predicate");
3610b57cec5SDimitry Andric APInt PredMask(NumUniquePredicates, 0);
3620b57cec5SDimitry Andric PredMask.setBit(Predicate2Index[Pred]);
3630b57cec5SDimitry Andric
3640b57cec5SDimitry Andric for (const Record *Opcode : Opcodes) {
3650b57cec5SDimitry Andric unsigned OpcodeIdx = Opcode2Index[Opcode];
3660b57cec5SDimitry Andric if (OpcodeMasks[OpcodeIdx].first[ProcIndex]) {
3670b57cec5SDimitry Andric std::string Message =
3680b57cec5SDimitry Andric "Opcode " + Opcode->getName().str() +
3690b57cec5SDimitry Andric " used by multiple InstructionEquivalenceClass definitions.";
3700b57cec5SDimitry Andric PrintFatalError(EC->getLoc(), Message);
3710b57cec5SDimitry Andric }
3720b57cec5SDimitry Andric OpcodeMasks[OpcodeIdx].first |= ProcMask;
3730b57cec5SDimitry Andric OpcodeMasks[OpcodeIdx].second |= PredMask;
3740b57cec5SDimitry Andric OpcodeInfo &OI = OpcodeMappings[OpcodeIdx].second;
3750b57cec5SDimitry Andric
3760b57cec5SDimitry Andric OI.addPredicateForProcModel(ProcMask, OperandMask, Pred);
3770b57cec5SDimitry Andric }
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric
3810b57cec5SDimitry Andric // Sort OpcodeMappings elements based on their CPU and predicate masks.
3820b57cec5SDimitry Andric // As a last resort, order elements by opcode identifier.
3830b57cec5SDimitry Andric llvm::sort(OpcodeMappings,
3840b57cec5SDimitry Andric [&](const OpcodeMapPair &Lhs, const OpcodeMapPair &Rhs) {
3850b57cec5SDimitry Andric unsigned LhsIdx = Opcode2Index[Lhs.first];
3860b57cec5SDimitry Andric unsigned RhsIdx = Opcode2Index[Rhs.first];
3870b57cec5SDimitry Andric const std::pair<APInt, APInt> &LhsMasks = OpcodeMasks[LhsIdx];
3880b57cec5SDimitry Andric const std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx];
3890b57cec5SDimitry Andric
390*c9157d92SDimitry Andric auto PopulationCountAndLeftBit =
391*c9157d92SDimitry Andric [](const APInt &Other) -> std::pair<int, int> {
392*c9157d92SDimitry Andric return std::pair<int, int>(Other.popcount(),
393*c9157d92SDimitry Andric -Other.countl_zero());
3940b57cec5SDimitry Andric };
395*c9157d92SDimitry Andric auto lhsmask_first = PopulationCountAndLeftBit(LhsMasks.first);
396*c9157d92SDimitry Andric auto rhsmask_first = PopulationCountAndLeftBit(RhsMasks.first);
397*c9157d92SDimitry Andric if (lhsmask_first != rhsmask_first)
398*c9157d92SDimitry Andric return lhsmask_first < rhsmask_first;
3990b57cec5SDimitry Andric
400*c9157d92SDimitry Andric auto lhsmask_second = PopulationCountAndLeftBit(LhsMasks.second);
401*c9157d92SDimitry Andric auto rhsmask_second = PopulationCountAndLeftBit(RhsMasks.second);
402*c9157d92SDimitry Andric if (lhsmask_second != rhsmask_second)
403*c9157d92SDimitry Andric return lhsmask_second < rhsmask_second;
4040b57cec5SDimitry Andric
4050b57cec5SDimitry Andric return LhsIdx < RhsIdx;
4060b57cec5SDimitry Andric });
4070b57cec5SDimitry Andric
4080b57cec5SDimitry Andric // Now construct opcode groups. Groups are used by the SubtargetEmitter when
4090b57cec5SDimitry Andric // expanding the body of a STIPredicate function. In particular, each opcode
4100b57cec5SDimitry Andric // group is expanded into a sequence of labels in a switch statement.
4110b57cec5SDimitry Andric // It identifies opcodes for which different processors define same predicates
4120b57cec5SDimitry Andric // and same opcode masks.
4130b57cec5SDimitry Andric for (OpcodeMapPair &Info : OpcodeMappings)
4140b57cec5SDimitry Andric Fn.addOpcode(Info.first, std::move(Info.second));
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric
collectSTIPredicates()4170b57cec5SDimitry Andric void CodeGenSchedModels::collectSTIPredicates() {
4180b57cec5SDimitry Andric // Map STIPredicateDecl records to elements of vector
4190b57cec5SDimitry Andric // CodeGenSchedModels::STIPredicates.
4200b57cec5SDimitry Andric DenseMap<const Record *, unsigned> Decl2Index;
4210b57cec5SDimitry Andric
4220b57cec5SDimitry Andric RecVec RV = Records.getAllDerivedDefinitions("STIPredicate");
4230b57cec5SDimitry Andric for (const Record *R : RV) {
4240b57cec5SDimitry Andric const Record *Decl = R->getValueAsDef("Declaration");
4250b57cec5SDimitry Andric
4260b57cec5SDimitry Andric const auto It = Decl2Index.find(Decl);
4270b57cec5SDimitry Andric if (It == Decl2Index.end()) {
4280b57cec5SDimitry Andric Decl2Index[Decl] = STIPredicates.size();
4290b57cec5SDimitry Andric STIPredicateFunction Predicate(Decl);
4300b57cec5SDimitry Andric Predicate.addDefinition(R);
4310b57cec5SDimitry Andric STIPredicates.emplace_back(std::move(Predicate));
4320b57cec5SDimitry Andric continue;
4330b57cec5SDimitry Andric }
4340b57cec5SDimitry Andric
4350b57cec5SDimitry Andric STIPredicateFunction &PreviousDef = STIPredicates[It->second];
4360b57cec5SDimitry Andric PreviousDef.addDefinition(R);
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andric for (STIPredicateFunction &Fn : STIPredicates)
4400b57cec5SDimitry Andric processSTIPredicate(Fn, ProcModelMap);
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric
addPredicateForProcModel(const llvm::APInt & CpuMask,const llvm::APInt & OperandMask,const Record * Predicate)4430b57cec5SDimitry Andric void OpcodeInfo::addPredicateForProcModel(const llvm::APInt &CpuMask,
4440b57cec5SDimitry Andric const llvm::APInt &OperandMask,
4450b57cec5SDimitry Andric const Record *Predicate) {
4460b57cec5SDimitry Andric auto It = llvm::find_if(
4470b57cec5SDimitry Andric Predicates, [&OperandMask, &Predicate](const PredicateInfo &P) {
4480b57cec5SDimitry Andric return P.Predicate == Predicate && P.OperandMask == OperandMask;
4490b57cec5SDimitry Andric });
4500b57cec5SDimitry Andric if (It == Predicates.end()) {
4510b57cec5SDimitry Andric Predicates.emplace_back(CpuMask, OperandMask, Predicate);
4520b57cec5SDimitry Andric return;
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric It->ProcModelMask |= CpuMask;
4550b57cec5SDimitry Andric }
4560b57cec5SDimitry Andric
checkMCInstPredicates() const4570b57cec5SDimitry Andric void CodeGenSchedModels::checkMCInstPredicates() const {
4580b57cec5SDimitry Andric RecVec MCPredicates = Records.getAllDerivedDefinitions("TIIPredicate");
4590b57cec5SDimitry Andric if (MCPredicates.empty())
4600b57cec5SDimitry Andric return;
4610b57cec5SDimitry Andric
4620b57cec5SDimitry Andric // A target cannot have multiple TIIPredicate definitions with a same name.
4630b57cec5SDimitry Andric llvm::StringMap<const Record *> TIIPredicates(MCPredicates.size());
4640b57cec5SDimitry Andric for (const Record *TIIPred : MCPredicates) {
4650b57cec5SDimitry Andric StringRef Name = TIIPred->getValueAsString("FunctionName");
4660b57cec5SDimitry Andric StringMap<const Record *>::const_iterator It = TIIPredicates.find(Name);
4670b57cec5SDimitry Andric if (It == TIIPredicates.end()) {
4680b57cec5SDimitry Andric TIIPredicates[Name] = TIIPred;
4690b57cec5SDimitry Andric continue;
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric
4720b57cec5SDimitry Andric PrintError(TIIPred->getLoc(),
4730b57cec5SDimitry Andric "TIIPredicate " + Name + " is multiply defined.");
474e8d8bef9SDimitry Andric PrintFatalNote(It->second->getLoc(),
4750b57cec5SDimitry Andric " Previous definition of " + Name + " was here.");
4760b57cec5SDimitry Andric }
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric
collectRetireControlUnits()4790b57cec5SDimitry Andric void CodeGenSchedModels::collectRetireControlUnits() {
4800b57cec5SDimitry Andric RecVec Units = Records.getAllDerivedDefinitions("RetireControlUnit");
4810b57cec5SDimitry Andric
4820b57cec5SDimitry Andric for (Record *RCU : Units) {
4830b57cec5SDimitry Andric CodeGenProcModel &PM = getProcModel(RCU->getValueAsDef("SchedModel"));
4840b57cec5SDimitry Andric if (PM.RetireControlUnit) {
4850b57cec5SDimitry Andric PrintError(RCU->getLoc(),
4860b57cec5SDimitry Andric "Expected a single RetireControlUnit definition");
4870b57cec5SDimitry Andric PrintNote(PM.RetireControlUnit->getLoc(),
4880b57cec5SDimitry Andric "Previous definition of RetireControlUnit was here");
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric PM.RetireControlUnit = RCU;
4910b57cec5SDimitry Andric }
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric
collectLoadStoreQueueInfo()4940b57cec5SDimitry Andric void CodeGenSchedModels::collectLoadStoreQueueInfo() {
4950b57cec5SDimitry Andric RecVec Queues = Records.getAllDerivedDefinitions("MemoryQueue");
4960b57cec5SDimitry Andric
4970b57cec5SDimitry Andric for (Record *Queue : Queues) {
4980b57cec5SDimitry Andric CodeGenProcModel &PM = getProcModel(Queue->getValueAsDef("SchedModel"));
4990b57cec5SDimitry Andric if (Queue->isSubClassOf("LoadQueue")) {
5000b57cec5SDimitry Andric if (PM.LoadQueue) {
5010b57cec5SDimitry Andric PrintError(Queue->getLoc(),
5020b57cec5SDimitry Andric "Expected a single LoadQueue definition");
5030b57cec5SDimitry Andric PrintNote(PM.LoadQueue->getLoc(),
5040b57cec5SDimitry Andric "Previous definition of LoadQueue was here");
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric
5070b57cec5SDimitry Andric PM.LoadQueue = Queue;
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric
5100b57cec5SDimitry Andric if (Queue->isSubClassOf("StoreQueue")) {
5110b57cec5SDimitry Andric if (PM.StoreQueue) {
5120b57cec5SDimitry Andric PrintError(Queue->getLoc(),
5130b57cec5SDimitry Andric "Expected a single StoreQueue definition");
514bdd1243dSDimitry Andric PrintNote(PM.StoreQueue->getLoc(),
5150b57cec5SDimitry Andric "Previous definition of StoreQueue was here");
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric
5180b57cec5SDimitry Andric PM.StoreQueue = Queue;
5190b57cec5SDimitry Andric }
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric }
5220b57cec5SDimitry Andric
5230b57cec5SDimitry Andric /// Collect optional processor information.
collectOptionalProcessorInfo()5240b57cec5SDimitry Andric void CodeGenSchedModels::collectOptionalProcessorInfo() {
5250b57cec5SDimitry Andric // Find register file definitions for each processor.
5260b57cec5SDimitry Andric collectRegisterFiles();
5270b57cec5SDimitry Andric
5280b57cec5SDimitry Andric // Collect processor RetireControlUnit descriptors if available.
5290b57cec5SDimitry Andric collectRetireControlUnits();
5300b57cec5SDimitry Andric
5310b57cec5SDimitry Andric // Collect information about load/store queues.
5320b57cec5SDimitry Andric collectLoadStoreQueueInfo();
5330b57cec5SDimitry Andric
5340b57cec5SDimitry Andric checkCompleteness();
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric
5370b57cec5SDimitry Andric /// Gather all processor models.
collectProcModels()5380b57cec5SDimitry Andric void CodeGenSchedModels::collectProcModels() {
5390b57cec5SDimitry Andric RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor");
5400b57cec5SDimitry Andric llvm::sort(ProcRecords, LessRecordFieldName());
5410b57cec5SDimitry Andric
5421fd87a68SDimitry Andric // Check for duplicated names.
5431fd87a68SDimitry Andric auto I = std::adjacent_find(ProcRecords.begin(), ProcRecords.end(),
5441fd87a68SDimitry Andric [](const Record *Rec1, const Record *Rec2) {
5451fd87a68SDimitry Andric return Rec1->getValueAsString("Name") == Rec2->getValueAsString("Name");
5461fd87a68SDimitry Andric });
5471fd87a68SDimitry Andric if (I != ProcRecords.end())
5481fd87a68SDimitry Andric PrintFatalError((*I)->getLoc(), "Duplicate processor name " +
5491fd87a68SDimitry Andric (*I)->getValueAsString("Name"));
5501fd87a68SDimitry Andric
5510b57cec5SDimitry Andric // Reserve space because we can. Reallocation would be ok.
5520b57cec5SDimitry Andric ProcModels.reserve(ProcRecords.size()+1);
5530b57cec5SDimitry Andric
5540b57cec5SDimitry Andric // Use idx=0 for NoModel/NoItineraries.
5550b57cec5SDimitry Andric Record *NoModelDef = Records.getDef("NoSchedModel");
5560b57cec5SDimitry Andric Record *NoItinsDef = Records.getDef("NoItineraries");
5570b57cec5SDimitry Andric ProcModels.emplace_back(0, "NoSchedModel", NoModelDef, NoItinsDef);
5580b57cec5SDimitry Andric ProcModelMap[NoModelDef] = 0;
5590b57cec5SDimitry Andric
5600b57cec5SDimitry Andric // For each processor, find a unique machine model.
5610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "+++ PROCESSOR MODELs (addProcModel) +++\n");
5620b57cec5SDimitry Andric for (Record *ProcRecord : ProcRecords)
5630b57cec5SDimitry Andric addProcModel(ProcRecord);
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric
5660b57cec5SDimitry Andric /// Get a unique processor model based on the defined MachineModel and
5670b57cec5SDimitry Andric /// ProcessorItineraries.
addProcModel(Record * ProcDef)5680b57cec5SDimitry Andric void CodeGenSchedModels::addProcModel(Record *ProcDef) {
5690b57cec5SDimitry Andric Record *ModelKey = getModelOrItinDef(ProcDef);
5700b57cec5SDimitry Andric if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second)
5710b57cec5SDimitry Andric return;
5720b57cec5SDimitry Andric
5735ffd83dbSDimitry Andric std::string Name = std::string(ModelKey->getName());
5740b57cec5SDimitry Andric if (ModelKey->isSubClassOf("SchedMachineModel")) {
5750b57cec5SDimitry Andric Record *ItinsDef = ModelKey->getValueAsDef("Itineraries");
5760b57cec5SDimitry Andric ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef);
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric else {
5790b57cec5SDimitry Andric // An itinerary is defined without a machine model. Infer a new model.
5800b57cec5SDimitry Andric if (!ModelKey->getValueAsListOfDefs("IID").empty())
5810b57cec5SDimitry Andric Name = Name + "Model";
5820b57cec5SDimitry Andric ProcModels.emplace_back(ProcModels.size(), Name,
5830b57cec5SDimitry Andric ProcDef->getValueAsDef("SchedModel"), ModelKey);
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric LLVM_DEBUG(ProcModels.back().dump());
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric // Recursively find all reachable SchedReadWrite records.
scanSchedRW(Record * RWDef,RecVec & RWDefs,SmallPtrSet<Record *,16> & RWSet)5890b57cec5SDimitry Andric static void scanSchedRW(Record *RWDef, RecVec &RWDefs,
5900b57cec5SDimitry Andric SmallPtrSet<Record*, 16> &RWSet) {
5910b57cec5SDimitry Andric if (!RWSet.insert(RWDef).second)
5920b57cec5SDimitry Andric return;
5930b57cec5SDimitry Andric RWDefs.push_back(RWDef);
5940b57cec5SDimitry Andric // Reads don't currently have sequence records, but it can be added later.
5950b57cec5SDimitry Andric if (RWDef->isSubClassOf("WriteSequence")) {
5960b57cec5SDimitry Andric RecVec Seq = RWDef->getValueAsListOfDefs("Writes");
5970b57cec5SDimitry Andric for (Record *WSRec : Seq)
5980b57cec5SDimitry Andric scanSchedRW(WSRec, RWDefs, RWSet);
5990b57cec5SDimitry Andric }
6000b57cec5SDimitry Andric else if (RWDef->isSubClassOf("SchedVariant")) {
6010b57cec5SDimitry Andric // Visit each variant (guarded by a different predicate).
6020b57cec5SDimitry Andric RecVec Vars = RWDef->getValueAsListOfDefs("Variants");
6030b57cec5SDimitry Andric for (Record *Variant : Vars) {
6040b57cec5SDimitry Andric // Visit each RW in the sequence selected by the current variant.
6050b57cec5SDimitry Andric RecVec Selected = Variant->getValueAsListOfDefs("Selected");
6060b57cec5SDimitry Andric for (Record *SelDef : Selected)
6070b57cec5SDimitry Andric scanSchedRW(SelDef, RWDefs, RWSet);
6080b57cec5SDimitry Andric }
6090b57cec5SDimitry Andric }
6100b57cec5SDimitry Andric }
6110b57cec5SDimitry Andric
6120b57cec5SDimitry Andric // Collect and sort all SchedReadWrites reachable via tablegen records.
6130b57cec5SDimitry Andric // More may be inferred later when inferring new SchedClasses from variants.
collectSchedRW()6140b57cec5SDimitry Andric void CodeGenSchedModels::collectSchedRW() {
6150b57cec5SDimitry Andric // Reserve idx=0 for invalid writes/reads.
6160b57cec5SDimitry Andric SchedWrites.resize(1);
6170b57cec5SDimitry Andric SchedReads.resize(1);
6180b57cec5SDimitry Andric
6190b57cec5SDimitry Andric SmallPtrSet<Record*, 16> RWSet;
6200b57cec5SDimitry Andric
6210b57cec5SDimitry Andric // Find all SchedReadWrites referenced by instruction defs.
6220b57cec5SDimitry Andric RecVec SWDefs, SRDefs;
6230b57cec5SDimitry Andric for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
6240b57cec5SDimitry Andric Record *SchedDef = Inst->TheDef;
6250b57cec5SDimitry Andric if (SchedDef->isValueUnset("SchedRW"))
6260b57cec5SDimitry Andric continue;
6270b57cec5SDimitry Andric RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW");
6280b57cec5SDimitry Andric for (Record *RW : RWs) {
6290b57cec5SDimitry Andric if (RW->isSubClassOf("SchedWrite"))
6300b57cec5SDimitry Andric scanSchedRW(RW, SWDefs, RWSet);
6310b57cec5SDimitry Andric else {
6320b57cec5SDimitry Andric assert(RW->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
6330b57cec5SDimitry Andric scanSchedRW(RW, SRDefs, RWSet);
6340b57cec5SDimitry Andric }
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric }
6370b57cec5SDimitry Andric // Find all ReadWrites referenced by InstRW.
6380b57cec5SDimitry Andric RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
6390b57cec5SDimitry Andric for (Record *InstRWDef : InstRWDefs) {
6400b57cec5SDimitry Andric // For all OperandReadWrites.
6410b57cec5SDimitry Andric RecVec RWDefs = InstRWDef->getValueAsListOfDefs("OperandReadWrites");
6420b57cec5SDimitry Andric for (Record *RWDef : RWDefs) {
6430b57cec5SDimitry Andric if (RWDef->isSubClassOf("SchedWrite"))
6440b57cec5SDimitry Andric scanSchedRW(RWDef, SWDefs, RWSet);
6450b57cec5SDimitry Andric else {
6460b57cec5SDimitry Andric assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
6470b57cec5SDimitry Andric scanSchedRW(RWDef, SRDefs, RWSet);
6480b57cec5SDimitry Andric }
6490b57cec5SDimitry Andric }
6500b57cec5SDimitry Andric }
6510b57cec5SDimitry Andric // Find all ReadWrites referenced by ItinRW.
6520b57cec5SDimitry Andric RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
6530b57cec5SDimitry Andric for (Record *ItinRWDef : ItinRWDefs) {
6540b57cec5SDimitry Andric // For all OperandReadWrites.
6550b57cec5SDimitry Andric RecVec RWDefs = ItinRWDef->getValueAsListOfDefs("OperandReadWrites");
6560b57cec5SDimitry Andric for (Record *RWDef : RWDefs) {
6570b57cec5SDimitry Andric if (RWDef->isSubClassOf("SchedWrite"))
6580b57cec5SDimitry Andric scanSchedRW(RWDef, SWDefs, RWSet);
6590b57cec5SDimitry Andric else {
6600b57cec5SDimitry Andric assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
6610b57cec5SDimitry Andric scanSchedRW(RWDef, SRDefs, RWSet);
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric }
6640b57cec5SDimitry Andric }
6650b57cec5SDimitry Andric // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted
6660b57cec5SDimitry Andric // for the loop below that initializes Alias vectors.
6670b57cec5SDimitry Andric RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias");
6680b57cec5SDimitry Andric llvm::sort(AliasDefs, LessRecord());
6690b57cec5SDimitry Andric for (Record *ADef : AliasDefs) {
6700b57cec5SDimitry Andric Record *MatchDef = ADef->getValueAsDef("MatchRW");
6710b57cec5SDimitry Andric Record *AliasDef = ADef->getValueAsDef("AliasRW");
6720b57cec5SDimitry Andric if (MatchDef->isSubClassOf("SchedWrite")) {
6730b57cec5SDimitry Andric if (!AliasDef->isSubClassOf("SchedWrite"))
6740b57cec5SDimitry Andric PrintFatalError(ADef->getLoc(), "SchedWrite Alias must be SchedWrite");
6750b57cec5SDimitry Andric scanSchedRW(AliasDef, SWDefs, RWSet);
6760b57cec5SDimitry Andric }
6770b57cec5SDimitry Andric else {
6780b57cec5SDimitry Andric assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
6790b57cec5SDimitry Andric if (!AliasDef->isSubClassOf("SchedRead"))
6800b57cec5SDimitry Andric PrintFatalError(ADef->getLoc(), "SchedRead Alias must be SchedRead");
6810b57cec5SDimitry Andric scanSchedRW(AliasDef, SRDefs, RWSet);
6820b57cec5SDimitry Andric }
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric // Sort and add the SchedReadWrites directly referenced by instructions or
6850b57cec5SDimitry Andric // itinerary resources. Index reads and writes in separate domains.
6860b57cec5SDimitry Andric llvm::sort(SWDefs, LessRecord());
6870b57cec5SDimitry Andric for (Record *SWDef : SWDefs) {
6880b57cec5SDimitry Andric assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite");
6890b57cec5SDimitry Andric SchedWrites.emplace_back(SchedWrites.size(), SWDef);
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric llvm::sort(SRDefs, LessRecord());
6920b57cec5SDimitry Andric for (Record *SRDef : SRDefs) {
6930b57cec5SDimitry Andric assert(!getSchedRWIdx(SRDef, /*IsRead-*/true) && "duplicate SchedWrite");
6940b57cec5SDimitry Andric SchedReads.emplace_back(SchedReads.size(), SRDef);
6950b57cec5SDimitry Andric }
6960b57cec5SDimitry Andric // Initialize WriteSequence vectors.
6970b57cec5SDimitry Andric for (CodeGenSchedRW &CGRW : SchedWrites) {
6980b57cec5SDimitry Andric if (!CGRW.IsSequence)
6990b57cec5SDimitry Andric continue;
7000b57cec5SDimitry Andric findRWs(CGRW.TheDef->getValueAsListOfDefs("Writes"), CGRW.Sequence,
7010b57cec5SDimitry Andric /*IsRead=*/false);
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric // Initialize Aliases vectors.
7040b57cec5SDimitry Andric for (Record *ADef : AliasDefs) {
7050b57cec5SDimitry Andric Record *AliasDef = ADef->getValueAsDef("AliasRW");
7060b57cec5SDimitry Andric getSchedRW(AliasDef).IsAlias = true;
7070b57cec5SDimitry Andric Record *MatchDef = ADef->getValueAsDef("MatchRW");
7080b57cec5SDimitry Andric CodeGenSchedRW &RW = getSchedRW(MatchDef);
7090b57cec5SDimitry Andric if (RW.IsAlias)
7100b57cec5SDimitry Andric PrintFatalError(ADef->getLoc(), "Cannot Alias an Alias");
7110b57cec5SDimitry Andric RW.Aliases.push_back(ADef);
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric LLVM_DEBUG(
7140b57cec5SDimitry Andric dbgs() << "\n+++ SCHED READS and WRITES (collectSchedRW) +++\n";
7150b57cec5SDimitry Andric for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) {
7160b57cec5SDimitry Andric dbgs() << WIdx << ": ";
7170b57cec5SDimitry Andric SchedWrites[WIdx].dump();
7180b57cec5SDimitry Andric dbgs() << '\n';
7190b57cec5SDimitry Andric } for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd;
7200b57cec5SDimitry Andric ++RIdx) {
7210b57cec5SDimitry Andric dbgs() << RIdx << ": ";
7220b57cec5SDimitry Andric SchedReads[RIdx].dump();
7230b57cec5SDimitry Andric dbgs() << '\n';
7240b57cec5SDimitry Andric } RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite");
7250b57cec5SDimitry Andric for (Record *RWDef
7260b57cec5SDimitry Andric : RWDefs) {
7270b57cec5SDimitry Andric if (!getSchedRWIdx(RWDef, RWDef->isSubClassOf("SchedRead"))) {
7280b57cec5SDimitry Andric StringRef Name = RWDef->getName();
7290b57cec5SDimitry Andric if (Name != "NoWrite" && Name != "ReadDefault")
7300b57cec5SDimitry Andric dbgs() << "Unused SchedReadWrite " << Name << '\n';
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric });
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric
7350b57cec5SDimitry Andric /// Compute a SchedWrite name from a sequence of writes.
genRWName(ArrayRef<unsigned> Seq,bool IsRead)7360b57cec5SDimitry Andric std::string CodeGenSchedModels::genRWName(ArrayRef<unsigned> Seq, bool IsRead) {
7370b57cec5SDimitry Andric std::string Name("(");
738fe6060f1SDimitry Andric ListSeparator LS("_");
739fe6060f1SDimitry Andric for (unsigned I : Seq) {
740fe6060f1SDimitry Andric Name += LS;
741fe6060f1SDimitry Andric Name += getSchedRW(I, IsRead).Name;
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric Name += ')';
7440b57cec5SDimitry Andric return Name;
7450b57cec5SDimitry Andric }
7460b57cec5SDimitry Andric
getSchedRWIdx(const Record * Def,bool IsRead) const7470b57cec5SDimitry Andric unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def,
7480b57cec5SDimitry Andric bool IsRead) const {
7490b57cec5SDimitry Andric const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
7500b57cec5SDimitry Andric const auto I = find_if(
7510b57cec5SDimitry Andric RWVec, [Def](const CodeGenSchedRW &RW) { return RW.TheDef == Def; });
7520b57cec5SDimitry Andric return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I);
7530b57cec5SDimitry Andric }
7540b57cec5SDimitry Andric
hasReadOfWrite(Record * WriteDef) const7550b57cec5SDimitry Andric bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const {
756bdd1243dSDimitry Andric for (auto& ProcModel : ProcModels) {
757bdd1243dSDimitry Andric const RecVec &RADefs = ProcModel.ReadAdvanceDefs;
758bdd1243dSDimitry Andric for (auto& RADef : RADefs) {
759bdd1243dSDimitry Andric RecVec ValidWrites = RADef->getValueAsListOfDefs("ValidWrites");
760bdd1243dSDimitry Andric if (is_contained(ValidWrites, WriteDef))
7610b57cec5SDimitry Andric return true;
7620b57cec5SDimitry Andric }
7630b57cec5SDimitry Andric }
7640b57cec5SDimitry Andric return false;
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric
splitSchedReadWrites(const RecVec & RWDefs,RecVec & WriteDefs,RecVec & ReadDefs)7670b57cec5SDimitry Andric static void splitSchedReadWrites(const RecVec &RWDefs,
7680b57cec5SDimitry Andric RecVec &WriteDefs, RecVec &ReadDefs) {
7690b57cec5SDimitry Andric for (Record *RWDef : RWDefs) {
7700b57cec5SDimitry Andric if (RWDef->isSubClassOf("SchedWrite"))
7710b57cec5SDimitry Andric WriteDefs.push_back(RWDef);
7720b57cec5SDimitry Andric else {
7730b57cec5SDimitry Andric assert(RWDef->isSubClassOf("SchedRead") && "unknown SchedReadWrite");
7740b57cec5SDimitry Andric ReadDefs.push_back(RWDef);
7750b57cec5SDimitry Andric }
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric // Split the SchedReadWrites defs and call findRWs for each list.
findRWs(const RecVec & RWDefs,IdxVec & Writes,IdxVec & Reads) const7800b57cec5SDimitry Andric void CodeGenSchedModels::findRWs(const RecVec &RWDefs,
7810b57cec5SDimitry Andric IdxVec &Writes, IdxVec &Reads) const {
7820b57cec5SDimitry Andric RecVec WriteDefs;
7830b57cec5SDimitry Andric RecVec ReadDefs;
7840b57cec5SDimitry Andric splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs);
7850b57cec5SDimitry Andric findRWs(WriteDefs, Writes, false);
7860b57cec5SDimitry Andric findRWs(ReadDefs, Reads, true);
7870b57cec5SDimitry Andric }
7880b57cec5SDimitry Andric
7890b57cec5SDimitry Andric // Call getSchedRWIdx for all elements in a sequence of SchedRW defs.
findRWs(const RecVec & RWDefs,IdxVec & RWs,bool IsRead) const7900b57cec5SDimitry Andric void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs,
7910b57cec5SDimitry Andric bool IsRead) const {
7920b57cec5SDimitry Andric for (Record *RWDef : RWDefs) {
7930b57cec5SDimitry Andric unsigned Idx = getSchedRWIdx(RWDef, IsRead);
7940b57cec5SDimitry Andric assert(Idx && "failed to collect SchedReadWrite");
7950b57cec5SDimitry Andric RWs.push_back(Idx);
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric
expandRWSequence(unsigned RWIdx,IdxVec & RWSeq,bool IsRead) const7990b57cec5SDimitry Andric void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq,
8000b57cec5SDimitry Andric bool IsRead) const {
8010b57cec5SDimitry Andric const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);
8020b57cec5SDimitry Andric if (!SchedRW.IsSequence) {
8030b57cec5SDimitry Andric RWSeq.push_back(RWIdx);
8040b57cec5SDimitry Andric return;
8050b57cec5SDimitry Andric }
8060b57cec5SDimitry Andric int Repeat =
8070b57cec5SDimitry Andric SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1;
8080b57cec5SDimitry Andric for (int i = 0; i < Repeat; ++i) {
8090b57cec5SDimitry Andric for (unsigned I : SchedRW.Sequence) {
8100b57cec5SDimitry Andric expandRWSequence(I, RWSeq, IsRead);
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric }
8130b57cec5SDimitry Andric }
8140b57cec5SDimitry Andric
8150b57cec5SDimitry Andric // Expand a SchedWrite as a sequence following any aliases that coincide with
8160b57cec5SDimitry Andric // the given processor model.
expandRWSeqForProc(unsigned RWIdx,IdxVec & RWSeq,bool IsRead,const CodeGenProcModel & ProcModel) const8170b57cec5SDimitry Andric void CodeGenSchedModels::expandRWSeqForProc(
8180b57cec5SDimitry Andric unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
8190b57cec5SDimitry Andric const CodeGenProcModel &ProcModel) const {
8200b57cec5SDimitry Andric
8210b57cec5SDimitry Andric const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead);
8220b57cec5SDimitry Andric Record *AliasDef = nullptr;
8230b57cec5SDimitry Andric for (const Record *Rec : SchedWrite.Aliases) {
8240b57cec5SDimitry Andric const CodeGenSchedRW &AliasRW = getSchedRW(Rec->getValueAsDef("AliasRW"));
8250b57cec5SDimitry Andric if (Rec->getValueInit("SchedModel")->isComplete()) {
8260b57cec5SDimitry Andric Record *ModelDef = Rec->getValueAsDef("SchedModel");
8270b57cec5SDimitry Andric if (&getProcModel(ModelDef) != &ProcModel)
8280b57cec5SDimitry Andric continue;
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric if (AliasDef)
8310b57cec5SDimitry Andric PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
8320b57cec5SDimitry Andric "defined for processor " + ProcModel.ModelName +
8330b57cec5SDimitry Andric " Ensure only one SchedAlias exists per RW.");
8340b57cec5SDimitry Andric AliasDef = AliasRW.TheDef;
8350b57cec5SDimitry Andric }
8360b57cec5SDimitry Andric if (AliasDef) {
8370b57cec5SDimitry Andric expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead),
8380b57cec5SDimitry Andric RWSeq, IsRead,ProcModel);
8390b57cec5SDimitry Andric return;
8400b57cec5SDimitry Andric }
8410b57cec5SDimitry Andric if (!SchedWrite.IsSequence) {
8420b57cec5SDimitry Andric RWSeq.push_back(RWIdx);
8430b57cec5SDimitry Andric return;
8440b57cec5SDimitry Andric }
8450b57cec5SDimitry Andric int Repeat =
8460b57cec5SDimitry Andric SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1;
8470b57cec5SDimitry Andric for (int I = 0, E = Repeat; I < E; ++I) {
8480b57cec5SDimitry Andric for (unsigned Idx : SchedWrite.Sequence) {
8490b57cec5SDimitry Andric expandRWSeqForProc(Idx, RWSeq, IsRead, ProcModel);
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric }
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric
8540b57cec5SDimitry Andric // Find the existing SchedWrite that models this sequence of writes.
findRWForSequence(ArrayRef<unsigned> Seq,bool IsRead)8550b57cec5SDimitry Andric unsigned CodeGenSchedModels::findRWForSequence(ArrayRef<unsigned> Seq,
8560b57cec5SDimitry Andric bool IsRead) {
8570b57cec5SDimitry Andric std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
8580b57cec5SDimitry Andric
8590b57cec5SDimitry Andric auto I = find_if(RWVec, [Seq](CodeGenSchedRW &RW) {
860bdd1243dSDimitry Andric return ArrayRef(RW.Sequence) == Seq;
8610b57cec5SDimitry Andric });
8620b57cec5SDimitry Andric // Index zero reserved for invalid RW.
8630b57cec5SDimitry Andric return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I);
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric
8660b57cec5SDimitry Andric /// Add this ReadWrite if it doesn't already exist.
findOrInsertRW(ArrayRef<unsigned> Seq,bool IsRead)8670b57cec5SDimitry Andric unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq,
8680b57cec5SDimitry Andric bool IsRead) {
8690b57cec5SDimitry Andric assert(!Seq.empty() && "cannot insert empty sequence");
8700b57cec5SDimitry Andric if (Seq.size() == 1)
8710b57cec5SDimitry Andric return Seq.back();
8720b57cec5SDimitry Andric
8730b57cec5SDimitry Andric unsigned Idx = findRWForSequence(Seq, IsRead);
8740b57cec5SDimitry Andric if (Idx)
8750b57cec5SDimitry Andric return Idx;
8760b57cec5SDimitry Andric
8770b57cec5SDimitry Andric std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
8780b57cec5SDimitry Andric unsigned RWIdx = RWVec.size();
8790b57cec5SDimitry Andric CodeGenSchedRW SchedRW(RWIdx, IsRead, Seq, genRWName(Seq, IsRead));
8800b57cec5SDimitry Andric RWVec.push_back(SchedRW);
8810b57cec5SDimitry Andric return RWIdx;
8820b57cec5SDimitry Andric }
8830b57cec5SDimitry Andric
8840b57cec5SDimitry Andric /// Visit all the instruction definitions for this target to gather and
8850b57cec5SDimitry Andric /// enumerate the itinerary classes. These are the explicitly specified
8860b57cec5SDimitry Andric /// SchedClasses. More SchedClasses may be inferred.
collectSchedClasses()8870b57cec5SDimitry Andric void CodeGenSchedModels::collectSchedClasses() {
8880b57cec5SDimitry Andric
8890b57cec5SDimitry Andric // NoItinerary is always the first class at Idx=0
8900b57cec5SDimitry Andric assert(SchedClasses.empty() && "Expected empty sched class");
8910b57cec5SDimitry Andric SchedClasses.emplace_back(0, "NoInstrModel",
8920b57cec5SDimitry Andric Records.getDef("NoItinerary"));
8930b57cec5SDimitry Andric SchedClasses.back().ProcIndices.push_back(0);
8940b57cec5SDimitry Andric
8950b57cec5SDimitry Andric // Create a SchedClass for each unique combination of itinerary class and
8960b57cec5SDimitry Andric // SchedRW list.
8970b57cec5SDimitry Andric for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
8980b57cec5SDimitry Andric Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary");
8990b57cec5SDimitry Andric IdxVec Writes, Reads;
9000b57cec5SDimitry Andric if (!Inst->TheDef->isValueUnset("SchedRW"))
9010b57cec5SDimitry Andric findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
9020b57cec5SDimitry Andric
9030b57cec5SDimitry Andric // ProcIdx == 0 indicates the class applies to all processors.
9040b57cec5SDimitry Andric unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/{0});
9050b57cec5SDimitry Andric InstrClassMap[Inst->TheDef] = SCIdx;
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric // Create classes for InstRW defs.
9080b57cec5SDimitry Andric RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
9090b57cec5SDimitry Andric llvm::sort(InstRWDefs, LessRecord());
9100b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n");
9110b57cec5SDimitry Andric for (Record *RWDef : InstRWDefs)
9120b57cec5SDimitry Andric createInstRWClass(RWDef);
9130b57cec5SDimitry Andric
9140b57cec5SDimitry Andric NumInstrSchedClasses = SchedClasses.size();
9150b57cec5SDimitry Andric
9160b57cec5SDimitry Andric bool EnableDump = false;
9170b57cec5SDimitry Andric LLVM_DEBUG(EnableDump = true);
9180b57cec5SDimitry Andric if (!EnableDump)
9190b57cec5SDimitry Andric return;
9200b57cec5SDimitry Andric
9210b57cec5SDimitry Andric LLVM_DEBUG(
9220b57cec5SDimitry Andric dbgs()
9230b57cec5SDimitry Andric << "\n+++ ITINERARIES and/or MACHINE MODELS (collectSchedClasses) +++\n");
9240b57cec5SDimitry Andric for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
9250b57cec5SDimitry Andric StringRef InstName = Inst->TheDef->getName();
9260b57cec5SDimitry Andric unsigned SCIdx = getSchedClassIdx(*Inst);
9270b57cec5SDimitry Andric if (!SCIdx) {
9280b57cec5SDimitry Andric LLVM_DEBUG({
9290b57cec5SDimitry Andric if (!Inst->hasNoSchedulingInfo)
9300b57cec5SDimitry Andric dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n';
9310b57cec5SDimitry Andric });
9320b57cec5SDimitry Andric continue;
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric CodeGenSchedClass &SC = getSchedClass(SCIdx);
9350b57cec5SDimitry Andric if (SC.ProcIndices[0] != 0)
9360b57cec5SDimitry Andric PrintFatalError(Inst->TheDef->getLoc(), "Instruction's sched class "
9370b57cec5SDimitry Andric "must not be subtarget specific.");
9380b57cec5SDimitry Andric
9390b57cec5SDimitry Andric IdxVec ProcIndices;
9400b57cec5SDimitry Andric if (SC.ItinClassDef->getName() != "NoItinerary") {
9410b57cec5SDimitry Andric ProcIndices.push_back(0);
9420b57cec5SDimitry Andric dbgs() << "Itinerary for " << InstName << ": "
9430b57cec5SDimitry Andric << SC.ItinClassDef->getName() << '\n';
9440b57cec5SDimitry Andric }
9450b57cec5SDimitry Andric if (!SC.Writes.empty()) {
9460b57cec5SDimitry Andric ProcIndices.push_back(0);
9470b57cec5SDimitry Andric LLVM_DEBUG({
9480b57cec5SDimitry Andric dbgs() << "SchedRW machine model for " << InstName;
949fe6060f1SDimitry Andric for (unsigned int Write : SC.Writes)
950fe6060f1SDimitry Andric dbgs() << " " << SchedWrites[Write].Name;
951fe6060f1SDimitry Andric for (unsigned int Read : SC.Reads)
952fe6060f1SDimitry Andric dbgs() << " " << SchedReads[Read].Name;
9530b57cec5SDimitry Andric dbgs() << '\n';
9540b57cec5SDimitry Andric });
9550b57cec5SDimitry Andric }
9560b57cec5SDimitry Andric const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
9570b57cec5SDimitry Andric for (Record *RWDef : RWDefs) {
9580b57cec5SDimitry Andric const CodeGenProcModel &ProcModel =
9590b57cec5SDimitry Andric getProcModel(RWDef->getValueAsDef("SchedModel"));
9600b57cec5SDimitry Andric ProcIndices.push_back(ProcModel.Index);
9610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "InstRW on " << ProcModel.ModelName << " for "
9620b57cec5SDimitry Andric << InstName);
9630b57cec5SDimitry Andric IdxVec Writes;
9640b57cec5SDimitry Andric IdxVec Reads;
9650b57cec5SDimitry Andric findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
9660b57cec5SDimitry Andric Writes, Reads);
9670b57cec5SDimitry Andric LLVM_DEBUG({
9680b57cec5SDimitry Andric for (unsigned WIdx : Writes)
9690b57cec5SDimitry Andric dbgs() << " " << SchedWrites[WIdx].Name;
9700b57cec5SDimitry Andric for (unsigned RIdx : Reads)
9710b57cec5SDimitry Andric dbgs() << " " << SchedReads[RIdx].Name;
9720b57cec5SDimitry Andric dbgs() << '\n';
9730b57cec5SDimitry Andric });
9740b57cec5SDimitry Andric }
9750b57cec5SDimitry Andric // If ProcIndices contains zero, the class applies to all processors.
9760b57cec5SDimitry Andric LLVM_DEBUG({
977e8d8bef9SDimitry Andric if (!llvm::is_contained(ProcIndices, 0)) {
9780b57cec5SDimitry Andric for (const CodeGenProcModel &PM : ProcModels) {
979e8d8bef9SDimitry Andric if (!llvm::is_contained(ProcIndices, PM.Index))
9800b57cec5SDimitry Andric dbgs() << "No machine model for " << Inst->TheDef->getName()
9810b57cec5SDimitry Andric << " on processor " << PM.ModelName << '\n';
9820b57cec5SDimitry Andric }
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric });
9850b57cec5SDimitry Andric }
9860b57cec5SDimitry Andric }
9870b57cec5SDimitry Andric
9880b57cec5SDimitry Andric // Get the SchedClass index for an instruction.
9890b57cec5SDimitry Andric unsigned
getSchedClassIdx(const CodeGenInstruction & Inst) const9900b57cec5SDimitry Andric CodeGenSchedModels::getSchedClassIdx(const CodeGenInstruction &Inst) const {
9910b57cec5SDimitry Andric return InstrClassMap.lookup(Inst.TheDef);
9920b57cec5SDimitry Andric }
9930b57cec5SDimitry Andric
9940b57cec5SDimitry Andric std::string
createSchedClassName(Record * ItinClassDef,ArrayRef<unsigned> OperWrites,ArrayRef<unsigned> OperReads)9950b57cec5SDimitry Andric CodeGenSchedModels::createSchedClassName(Record *ItinClassDef,
9960b57cec5SDimitry Andric ArrayRef<unsigned> OperWrites,
9970b57cec5SDimitry Andric ArrayRef<unsigned> OperReads) {
9980b57cec5SDimitry Andric
9990b57cec5SDimitry Andric std::string Name;
10000b57cec5SDimitry Andric if (ItinClassDef && ItinClassDef->getName() != "NoItinerary")
10015ffd83dbSDimitry Andric Name = std::string(ItinClassDef->getName());
10020b57cec5SDimitry Andric for (unsigned Idx : OperWrites) {
10030b57cec5SDimitry Andric if (!Name.empty())
10040b57cec5SDimitry Andric Name += '_';
10050b57cec5SDimitry Andric Name += SchedWrites[Idx].Name;
10060b57cec5SDimitry Andric }
10070b57cec5SDimitry Andric for (unsigned Idx : OperReads) {
10080b57cec5SDimitry Andric Name += '_';
10090b57cec5SDimitry Andric Name += SchedReads[Idx].Name;
10100b57cec5SDimitry Andric }
10110b57cec5SDimitry Andric return Name;
10120b57cec5SDimitry Andric }
10130b57cec5SDimitry Andric
createSchedClassName(const RecVec & InstDefs)10140b57cec5SDimitry Andric std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) {
10150b57cec5SDimitry Andric
10160b57cec5SDimitry Andric std::string Name;
1017fe6060f1SDimitry Andric ListSeparator LS("_");
1018fe6060f1SDimitry Andric for (const Record *InstDef : InstDefs) {
1019fe6060f1SDimitry Andric Name += LS;
1020fe6060f1SDimitry Andric Name += InstDef->getName();
10210b57cec5SDimitry Andric }
10220b57cec5SDimitry Andric return Name;
10230b57cec5SDimitry Andric }
10240b57cec5SDimitry Andric
10250b57cec5SDimitry Andric /// Add an inferred sched class from an itinerary class and per-operand list of
10260b57cec5SDimitry Andric /// SchedWrites and SchedReads. ProcIndices contains the set of IDs of
10270b57cec5SDimitry Andric /// processors that may utilize this class.
addSchedClass(Record * ItinClassDef,ArrayRef<unsigned> OperWrites,ArrayRef<unsigned> OperReads,ArrayRef<unsigned> ProcIndices)10280b57cec5SDimitry Andric unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef,
10290b57cec5SDimitry Andric ArrayRef<unsigned> OperWrites,
10300b57cec5SDimitry Andric ArrayRef<unsigned> OperReads,
10310b57cec5SDimitry Andric ArrayRef<unsigned> ProcIndices) {
10320b57cec5SDimitry Andric assert(!ProcIndices.empty() && "expect at least one ProcIdx");
10330b57cec5SDimitry Andric
10340b57cec5SDimitry Andric auto IsKeyEqual = [=](const CodeGenSchedClass &SC) {
10350b57cec5SDimitry Andric return SC.isKeyEqual(ItinClassDef, OperWrites, OperReads);
10360b57cec5SDimitry Andric };
10370b57cec5SDimitry Andric
10380b57cec5SDimitry Andric auto I = find_if(make_range(schedClassBegin(), schedClassEnd()), IsKeyEqual);
10390b57cec5SDimitry Andric unsigned Idx = I == schedClassEnd() ? 0 : std::distance(schedClassBegin(), I);
10400b57cec5SDimitry Andric if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) {
10410b57cec5SDimitry Andric IdxVec PI;
10420b57cec5SDimitry Andric std::set_union(SchedClasses[Idx].ProcIndices.begin(),
10430b57cec5SDimitry Andric SchedClasses[Idx].ProcIndices.end(),
10440b57cec5SDimitry Andric ProcIndices.begin(), ProcIndices.end(),
10450b57cec5SDimitry Andric std::back_inserter(PI));
10460b57cec5SDimitry Andric SchedClasses[Idx].ProcIndices = std::move(PI);
10470b57cec5SDimitry Andric return Idx;
10480b57cec5SDimitry Andric }
10490b57cec5SDimitry Andric Idx = SchedClasses.size();
10500b57cec5SDimitry Andric SchedClasses.emplace_back(Idx,
10510b57cec5SDimitry Andric createSchedClassName(ItinClassDef, OperWrites,
10520b57cec5SDimitry Andric OperReads),
10530b57cec5SDimitry Andric ItinClassDef);
10540b57cec5SDimitry Andric CodeGenSchedClass &SC = SchedClasses.back();
10550b57cec5SDimitry Andric SC.Writes = OperWrites;
10560b57cec5SDimitry Andric SC.Reads = OperReads;
10570b57cec5SDimitry Andric SC.ProcIndices = ProcIndices;
10580b57cec5SDimitry Andric
10590b57cec5SDimitry Andric return Idx;
10600b57cec5SDimitry Andric }
10610b57cec5SDimitry Andric
10620b57cec5SDimitry Andric // Create classes for each set of opcodes that are in the same InstReadWrite
10630b57cec5SDimitry Andric // definition across all processors.
createInstRWClass(Record * InstRWDef)10640b57cec5SDimitry Andric void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
10650b57cec5SDimitry Andric // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that
10660b57cec5SDimitry Andric // intersects with an existing class via a previous InstRWDef. Instrs that do
10670b57cec5SDimitry Andric // not intersect with an existing class refer back to their former class as
10680b57cec5SDimitry Andric // determined from ItinDef or SchedRW.
10690b57cec5SDimitry Andric SmallMapVector<unsigned, SmallVector<Record *, 8>, 4> ClassInstrs;
10700b57cec5SDimitry Andric // Sort Instrs into sets.
10710b57cec5SDimitry Andric const RecVec *InstDefs = Sets.expand(InstRWDef);
10720b57cec5SDimitry Andric if (InstDefs->empty())
10730b57cec5SDimitry Andric PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes");
10740b57cec5SDimitry Andric
10750b57cec5SDimitry Andric for (Record *InstDef : *InstDefs) {
10760b57cec5SDimitry Andric InstClassMapTy::const_iterator Pos = InstrClassMap.find(InstDef);
10770b57cec5SDimitry Andric if (Pos == InstrClassMap.end())
10780b57cec5SDimitry Andric PrintFatalError(InstDef->getLoc(), "No sched class for instruction.");
10790b57cec5SDimitry Andric unsigned SCIdx = Pos->second;
10800b57cec5SDimitry Andric ClassInstrs[SCIdx].push_back(InstDef);
10810b57cec5SDimitry Andric }
10820b57cec5SDimitry Andric // For each set of Instrs, create a new class if necessary, and map or remap
10830b57cec5SDimitry Andric // the Instrs to it.
10840b57cec5SDimitry Andric for (auto &Entry : ClassInstrs) {
10850b57cec5SDimitry Andric unsigned OldSCIdx = Entry.first;
10860b57cec5SDimitry Andric ArrayRef<Record*> InstDefs = Entry.second;
10870b57cec5SDimitry Andric // If the all instrs in the current class are accounted for, then leave
10880b57cec5SDimitry Andric // them mapped to their old class.
10890b57cec5SDimitry Andric if (OldSCIdx) {
10900b57cec5SDimitry Andric const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs;
10910b57cec5SDimitry Andric if (!RWDefs.empty()) {
10920b57cec5SDimitry Andric const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]);
10930b57cec5SDimitry Andric unsigned OrigNumInstrs =
10940b57cec5SDimitry Andric count_if(*OrigInstDefs, [&](Record *OIDef) {
10950b57cec5SDimitry Andric return InstrClassMap[OIDef] == OldSCIdx;
10960b57cec5SDimitry Andric });
10970b57cec5SDimitry Andric if (OrigNumInstrs == InstDefs.size()) {
10980b57cec5SDimitry Andric assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
10990b57cec5SDimitry Andric "expected a generic SchedClass");
11000b57cec5SDimitry Andric Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel");
11010b57cec5SDimitry Andric // Make sure we didn't already have a InstRW containing this
11020b57cec5SDimitry Andric // instruction on this model.
11030b57cec5SDimitry Andric for (Record *RWD : RWDefs) {
11040b57cec5SDimitry Andric if (RWD->getValueAsDef("SchedModel") == RWModelDef &&
11050b57cec5SDimitry Andric RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) {
11065ffd83dbSDimitry Andric assert(!InstDefs.empty()); // Checked at function start.
1107e8d8bef9SDimitry Andric PrintError(
1108e8d8bef9SDimitry Andric InstRWDef->getLoc(),
11098bcb0991SDimitry Andric "Overlapping InstRW definition for \"" +
11105ffd83dbSDimitry Andric InstDefs.front()->getName() +
11118bcb0991SDimitry Andric "\" also matches previous \"" +
11128bcb0991SDimitry Andric RWD->getValue("Instrs")->getValue()->getAsString() +
11138bcb0991SDimitry Andric "\".");
1114e8d8bef9SDimitry Andric PrintFatalNote(RWD->getLoc(), "Previous match was here.");
11150b57cec5SDimitry Andric }
11160b57cec5SDimitry Andric }
11170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":"
11180b57cec5SDimitry Andric << SchedClasses[OldSCIdx].Name << " on "
11190b57cec5SDimitry Andric << RWModelDef->getName() << "\n");
11200b57cec5SDimitry Andric SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef);
11210b57cec5SDimitry Andric continue;
11220b57cec5SDimitry Andric }
11230b57cec5SDimitry Andric }
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric unsigned SCIdx = SchedClasses.size();
11260b57cec5SDimitry Andric SchedClasses.emplace_back(SCIdx, createSchedClassName(InstDefs), nullptr);
11270b57cec5SDimitry Andric CodeGenSchedClass &SC = SchedClasses.back();
11280b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on "
11290b57cec5SDimitry Andric << InstRWDef->getValueAsDef("SchedModel")->getName()
11300b57cec5SDimitry Andric << "\n");
11310b57cec5SDimitry Andric
11320b57cec5SDimitry Andric // Preserve ItinDef and Writes/Reads for processors without an InstRW entry.
11330b57cec5SDimitry Andric SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef;
11340b57cec5SDimitry Andric SC.Writes = SchedClasses[OldSCIdx].Writes;
11350b57cec5SDimitry Andric SC.Reads = SchedClasses[OldSCIdx].Reads;
11360b57cec5SDimitry Andric SC.ProcIndices.push_back(0);
11370b57cec5SDimitry Andric // If we had an old class, copy it's InstRWs to this new class.
11380b57cec5SDimitry Andric if (OldSCIdx) {
11390b57cec5SDimitry Andric Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel");
11400b57cec5SDimitry Andric for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) {
11410b57cec5SDimitry Andric if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) {
11425ffd83dbSDimitry Andric assert(!InstDefs.empty()); // Checked at function start.
1143e8d8bef9SDimitry Andric PrintError(
1144e8d8bef9SDimitry Andric InstRWDef->getLoc(),
11458bcb0991SDimitry Andric "Overlapping InstRW definition for \"" +
1146e8d8bef9SDimitry Andric InstDefs.front()->getName() + "\" also matches previous \"" +
11478bcb0991SDimitry Andric OldRWDef->getValue("Instrs")->getValue()->getAsString() +
11488bcb0991SDimitry Andric "\".");
1149e8d8bef9SDimitry Andric PrintFatalNote(OldRWDef->getLoc(), "Previous match was here.");
11500b57cec5SDimitry Andric }
11510b57cec5SDimitry Andric assert(OldRWDef != InstRWDef &&
11520b57cec5SDimitry Andric "SchedClass has duplicate InstRW def");
11530b57cec5SDimitry Andric SC.InstRWs.push_back(OldRWDef);
11540b57cec5SDimitry Andric }
11550b57cec5SDimitry Andric }
11560b57cec5SDimitry Andric // Map each Instr to this new class.
11570b57cec5SDimitry Andric for (Record *InstDef : InstDefs)
11580b57cec5SDimitry Andric InstrClassMap[InstDef] = SCIdx;
11590b57cec5SDimitry Andric SC.InstRWs.push_back(InstRWDef);
11600b57cec5SDimitry Andric }
11610b57cec5SDimitry Andric }
11620b57cec5SDimitry Andric
11630b57cec5SDimitry Andric // True if collectProcItins found anything.
hasItineraries() const11640b57cec5SDimitry Andric bool CodeGenSchedModels::hasItineraries() const {
11650b57cec5SDimitry Andric for (const CodeGenProcModel &PM : make_range(procModelBegin(),procModelEnd()))
11660b57cec5SDimitry Andric if (PM.hasItineraries())
11670b57cec5SDimitry Andric return true;
11680b57cec5SDimitry Andric return false;
11690b57cec5SDimitry Andric }
11700b57cec5SDimitry Andric
11710b57cec5SDimitry Andric // Gather the processor itineraries.
collectProcItins()11720b57cec5SDimitry Andric void CodeGenSchedModels::collectProcItins() {
11730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n+++ PROBLEM ITINERARIES (collectProcItins) +++\n");
11740b57cec5SDimitry Andric for (CodeGenProcModel &ProcModel : ProcModels) {
11750b57cec5SDimitry Andric if (!ProcModel.hasItineraries())
11760b57cec5SDimitry Andric continue;
11770b57cec5SDimitry Andric
11780b57cec5SDimitry Andric RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID");
11790b57cec5SDimitry Andric assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect");
11800b57cec5SDimitry Andric
11810b57cec5SDimitry Andric // Populate ItinDefList with Itinerary records.
11820b57cec5SDimitry Andric ProcModel.ItinDefList.resize(NumInstrSchedClasses);
11830b57cec5SDimitry Andric
11840b57cec5SDimitry Andric // Insert each itinerary data record in the correct position within
11850b57cec5SDimitry Andric // the processor model's ItinDefList.
11860b57cec5SDimitry Andric for (Record *ItinData : ItinRecords) {
11870b57cec5SDimitry Andric const Record *ItinDef = ItinData->getValueAsDef("TheClass");
11880b57cec5SDimitry Andric bool FoundClass = false;
11890b57cec5SDimitry Andric
11900b57cec5SDimitry Andric for (const CodeGenSchedClass &SC :
11910b57cec5SDimitry Andric make_range(schedClassBegin(), schedClassEnd())) {
11920b57cec5SDimitry Andric // Multiple SchedClasses may share an itinerary. Update all of them.
11930b57cec5SDimitry Andric if (SC.ItinClassDef == ItinDef) {
11940b57cec5SDimitry Andric ProcModel.ItinDefList[SC.Index] = ItinData;
11950b57cec5SDimitry Andric FoundClass = true;
11960b57cec5SDimitry Andric }
11970b57cec5SDimitry Andric }
11980b57cec5SDimitry Andric if (!FoundClass) {
11990b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ProcModel.ItinsDef->getName()
12000b57cec5SDimitry Andric << " missing class for itinerary "
12010b57cec5SDimitry Andric << ItinDef->getName() << '\n');
12020b57cec5SDimitry Andric }
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric // Check for missing itinerary entries.
12050b57cec5SDimitry Andric assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec");
12060b57cec5SDimitry Andric LLVM_DEBUG(
12070b57cec5SDimitry Andric for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) {
12080b57cec5SDimitry Andric if (!ProcModel.ItinDefList[i])
12090b57cec5SDimitry Andric dbgs() << ProcModel.ItinsDef->getName()
12100b57cec5SDimitry Andric << " missing itinerary for class " << SchedClasses[i].Name
12110b57cec5SDimitry Andric << '\n';
12120b57cec5SDimitry Andric });
12130b57cec5SDimitry Andric }
12140b57cec5SDimitry Andric }
12150b57cec5SDimitry Andric
12160b57cec5SDimitry Andric // Gather the read/write types for each itinerary class.
collectProcItinRW()12170b57cec5SDimitry Andric void CodeGenSchedModels::collectProcItinRW() {
12180b57cec5SDimitry Andric RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
12190b57cec5SDimitry Andric llvm::sort(ItinRWDefs, LessRecord());
12200b57cec5SDimitry Andric for (Record *RWDef : ItinRWDefs) {
12210b57cec5SDimitry Andric if (!RWDef->getValueInit("SchedModel")->isComplete())
12220b57cec5SDimitry Andric PrintFatalError(RWDef->getLoc(), "SchedModel is undefined");
12230b57cec5SDimitry Andric Record *ModelDef = RWDef->getValueAsDef("SchedModel");
12240b57cec5SDimitry Andric ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
12250b57cec5SDimitry Andric if (I == ProcModelMap.end()) {
12260b57cec5SDimitry Andric PrintFatalError(RWDef->getLoc(), "Undefined SchedMachineModel "
12270b57cec5SDimitry Andric + ModelDef->getName());
12280b57cec5SDimitry Andric }
12290b57cec5SDimitry Andric ProcModels[I->second].ItinRWDefs.push_back(RWDef);
12300b57cec5SDimitry Andric }
12310b57cec5SDimitry Andric }
12320b57cec5SDimitry Andric
12330b57cec5SDimitry Andric // Gather the unsupported features for processor models.
collectProcUnsupportedFeatures()12340b57cec5SDimitry Andric void CodeGenSchedModels::collectProcUnsupportedFeatures() {
1235e8d8bef9SDimitry Andric for (CodeGenProcModel &ProcModel : ProcModels)
1236e8d8bef9SDimitry Andric append_range(
1237e8d8bef9SDimitry Andric ProcModel.UnsupportedFeaturesDefs,
1238e8d8bef9SDimitry Andric ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures"));
12390b57cec5SDimitry Andric }
12400b57cec5SDimitry Andric
12410b57cec5SDimitry Andric /// Infer new classes from existing classes. In the process, this may create new
12420b57cec5SDimitry Andric /// SchedWrites from sequences of existing SchedWrites.
inferSchedClasses()12430b57cec5SDimitry Andric void CodeGenSchedModels::inferSchedClasses() {
12440b57cec5SDimitry Andric LLVM_DEBUG(
12450b57cec5SDimitry Andric dbgs() << "\n+++ INFERRING SCHED CLASSES (inferSchedClasses) +++\n");
12460b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n");
12470b57cec5SDimitry Andric
12480b57cec5SDimitry Andric // Visit all existing classes and newly created classes.
12490b57cec5SDimitry Andric for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) {
12500b57cec5SDimitry Andric assert(SchedClasses[Idx].Index == Idx && "bad SCIdx");
12510b57cec5SDimitry Andric
12520b57cec5SDimitry Andric if (SchedClasses[Idx].ItinClassDef)
12530b57cec5SDimitry Andric inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx);
12540b57cec5SDimitry Andric if (!SchedClasses[Idx].InstRWs.empty())
12550b57cec5SDimitry Andric inferFromInstRWs(Idx);
12560b57cec5SDimitry Andric if (!SchedClasses[Idx].Writes.empty()) {
12570b57cec5SDimitry Andric inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,
12580b57cec5SDimitry Andric Idx, SchedClasses[Idx].ProcIndices);
12590b57cec5SDimitry Andric }
12600b57cec5SDimitry Andric assert(SchedClasses.size() < (NumInstrSchedClasses*6) &&
12610b57cec5SDimitry Andric "too many SchedVariants");
12620b57cec5SDimitry Andric }
12630b57cec5SDimitry Andric }
12640b57cec5SDimitry Andric
12650b57cec5SDimitry Andric /// Infer classes from per-processor itinerary resources.
inferFromItinClass(Record * ItinClassDef,unsigned FromClassIdx)12660b57cec5SDimitry Andric void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef,
12670b57cec5SDimitry Andric unsigned FromClassIdx) {
12680b57cec5SDimitry Andric for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {
12690b57cec5SDimitry Andric const CodeGenProcModel &PM = ProcModels[PIdx];
12700b57cec5SDimitry Andric // For all ItinRW entries.
12710b57cec5SDimitry Andric bool HasMatch = false;
12720b57cec5SDimitry Andric for (const Record *Rec : PM.ItinRWDefs) {
12730b57cec5SDimitry Andric RecVec Matched = Rec->getValueAsListOfDefs("MatchedItinClasses");
1274e8d8bef9SDimitry Andric if (!llvm::is_contained(Matched, ItinClassDef))
12750b57cec5SDimitry Andric continue;
12760b57cec5SDimitry Andric if (HasMatch)
12770b57cec5SDimitry Andric PrintFatalError(Rec->getLoc(), "Duplicate itinerary class "
12780b57cec5SDimitry Andric + ItinClassDef->getName()
12790b57cec5SDimitry Andric + " in ItinResources for " + PM.ModelName);
12800b57cec5SDimitry Andric HasMatch = true;
12810b57cec5SDimitry Andric IdxVec Writes, Reads;
12820b57cec5SDimitry Andric findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
12830b57cec5SDimitry Andric inferFromRW(Writes, Reads, FromClassIdx, PIdx);
12840b57cec5SDimitry Andric }
12850b57cec5SDimitry Andric }
12860b57cec5SDimitry Andric }
12870b57cec5SDimitry Andric
12880b57cec5SDimitry Andric /// Infer classes from per-processor InstReadWrite definitions.
inferFromInstRWs(unsigned SCIdx)12890b57cec5SDimitry Andric void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) {
12900b57cec5SDimitry Andric for (unsigned I = 0, E = SchedClasses[SCIdx].InstRWs.size(); I != E; ++I) {
12910b57cec5SDimitry Andric assert(SchedClasses[SCIdx].InstRWs.size() == E && "InstrRWs was mutated!");
12920b57cec5SDimitry Andric Record *Rec = SchedClasses[SCIdx].InstRWs[I];
12930b57cec5SDimitry Andric const RecVec *InstDefs = Sets.expand(Rec);
12940b57cec5SDimitry Andric RecIter II = InstDefs->begin(), IE = InstDefs->end();
12950b57cec5SDimitry Andric for (; II != IE; ++II) {
12960b57cec5SDimitry Andric if (InstrClassMap[*II] == SCIdx)
12970b57cec5SDimitry Andric break;
12980b57cec5SDimitry Andric }
12990b57cec5SDimitry Andric // If this class no longer has any instructions mapped to it, it has become
13000b57cec5SDimitry Andric // irrelevant.
13010b57cec5SDimitry Andric if (II == IE)
13020b57cec5SDimitry Andric continue;
13030b57cec5SDimitry Andric IdxVec Writes, Reads;
13040b57cec5SDimitry Andric findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
13050b57cec5SDimitry Andric unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index;
13060b57cec5SDimitry Andric inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses.
1307e8d8bef9SDimitry Andric SchedClasses[SCIdx].InstRWProcIndices.insert(PIdx);
13080b57cec5SDimitry Andric }
13090b57cec5SDimitry Andric }
13100b57cec5SDimitry Andric
13110b57cec5SDimitry Andric namespace {
13120b57cec5SDimitry Andric
13130b57cec5SDimitry Andric // Helper for substituteVariantOperand.
13140b57cec5SDimitry Andric struct TransVariant {
13150b57cec5SDimitry Andric Record *VarOrSeqDef; // Variant or sequence.
13160b57cec5SDimitry Andric unsigned RWIdx; // Index of this variant or sequence's matched type.
13170b57cec5SDimitry Andric unsigned ProcIdx; // Processor model index or zero for any.
13180b57cec5SDimitry Andric unsigned TransVecIdx; // Index into PredTransitions::TransVec.
13190b57cec5SDimitry Andric
TransVariant__anon3a1684130b11::TransVariant13200b57cec5SDimitry Andric TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti):
13210b57cec5SDimitry Andric VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {}
13220b57cec5SDimitry Andric };
13230b57cec5SDimitry Andric
13240b57cec5SDimitry Andric // Associate a predicate with the SchedReadWrite that it guards.
13250b57cec5SDimitry Andric // RWIdx is the index of the read/write variant.
13260b57cec5SDimitry Andric struct PredCheck {
13270b57cec5SDimitry Andric bool IsRead;
13280b57cec5SDimitry Andric unsigned RWIdx;
13290b57cec5SDimitry Andric Record *Predicate;
13300b57cec5SDimitry Andric
PredCheck__anon3a1684130b11::PredCheck13310b57cec5SDimitry Andric PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {}
13320b57cec5SDimitry Andric };
13330b57cec5SDimitry Andric
13340b57cec5SDimitry Andric // A Predicate transition is a list of RW sequences guarded by a PredTerm.
13350b57cec5SDimitry Andric struct PredTransition {
13360b57cec5SDimitry Andric // A predicate term is a conjunction of PredChecks.
13370b57cec5SDimitry Andric SmallVector<PredCheck, 4> PredTerm;
13380b57cec5SDimitry Andric SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;
13390b57cec5SDimitry Andric SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;
1340e8d8bef9SDimitry Andric unsigned ProcIndex = 0;
1341e8d8bef9SDimitry Andric
1342e8d8bef9SDimitry Andric PredTransition() = default;
PredTransition__anon3a1684130b11::PredTransition1343e8d8bef9SDimitry Andric PredTransition(ArrayRef<PredCheck> PT, unsigned ProcId) {
1344e8d8bef9SDimitry Andric PredTerm.assign(PT.begin(), PT.end());
1345e8d8bef9SDimitry Andric ProcIndex = ProcId;
1346e8d8bef9SDimitry Andric }
13470b57cec5SDimitry Andric };
13480b57cec5SDimitry Andric
13490b57cec5SDimitry Andric // Encapsulate a set of partially constructed transitions.
13500b57cec5SDimitry Andric // The results are built by repeated calls to substituteVariants.
13510b57cec5SDimitry Andric class PredTransitions {
13520b57cec5SDimitry Andric CodeGenSchedModels &SchedModels;
13530b57cec5SDimitry Andric
13540b57cec5SDimitry Andric public:
13550b57cec5SDimitry Andric std::vector<PredTransition> TransVec;
13560b57cec5SDimitry Andric
PredTransitions(CodeGenSchedModels & sm)13570b57cec5SDimitry Andric PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {}
13580b57cec5SDimitry Andric
1359e8d8bef9SDimitry Andric bool substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,
13600b57cec5SDimitry Andric bool IsRead, unsigned StartIdx);
13610b57cec5SDimitry Andric
1362e8d8bef9SDimitry Andric bool substituteVariants(const PredTransition &Trans);
13630b57cec5SDimitry Andric
13640b57cec5SDimitry Andric #ifndef NDEBUG
13650b57cec5SDimitry Andric void dump() const;
13660b57cec5SDimitry Andric #endif
13670b57cec5SDimitry Andric
13680b57cec5SDimitry Andric private:
1369e8d8bef9SDimitry Andric bool mutuallyExclusive(Record *PredDef, ArrayRef<Record *> Preds,
1370e8d8bef9SDimitry Andric ArrayRef<PredCheck> Term);
13710b57cec5SDimitry Andric void getIntersectingVariants(
13720b57cec5SDimitry Andric const CodeGenSchedRW &SchedRW, unsigned TransIdx,
13730b57cec5SDimitry Andric std::vector<TransVariant> &IntersectingVariants);
13740b57cec5SDimitry Andric void pushVariant(const TransVariant &VInfo, bool IsRead);
13750b57cec5SDimitry Andric };
13760b57cec5SDimitry Andric
13770b57cec5SDimitry Andric } // end anonymous namespace
13780b57cec5SDimitry Andric
13790b57cec5SDimitry Andric // Return true if this predicate is mutually exclusive with a PredTerm. This
13800b57cec5SDimitry Andric // degenerates into checking if the predicate is mutually exclusive with any
13810b57cec5SDimitry Andric // predicate in the Term's conjunction.
13820b57cec5SDimitry Andric //
13830b57cec5SDimitry Andric // All predicates associated with a given SchedRW are considered mutually
13840b57cec5SDimitry Andric // exclusive. This should work even if the conditions expressed by the
13850b57cec5SDimitry Andric // predicates are not exclusive because the predicates for a given SchedWrite
13860b57cec5SDimitry Andric // are always checked in the order they are defined in the .td file. Later
13870b57cec5SDimitry Andric // conditions implicitly negate any prior condition.
mutuallyExclusive(Record * PredDef,ArrayRef<Record * > Preds,ArrayRef<PredCheck> Term)13880b57cec5SDimitry Andric bool PredTransitions::mutuallyExclusive(Record *PredDef,
1389e8d8bef9SDimitry Andric ArrayRef<Record *> Preds,
13900b57cec5SDimitry Andric ArrayRef<PredCheck> Term) {
13910b57cec5SDimitry Andric for (const PredCheck &PC: Term) {
13920b57cec5SDimitry Andric if (PC.Predicate == PredDef)
13930b57cec5SDimitry Andric return false;
13940b57cec5SDimitry Andric
13950b57cec5SDimitry Andric const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(PC.RWIdx, PC.IsRead);
13960b57cec5SDimitry Andric assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant");
13970b57cec5SDimitry Andric RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
13980b57cec5SDimitry Andric if (any_of(Variants, [PredDef](const Record *R) {
13990b57cec5SDimitry Andric return R->getValueAsDef("Predicate") == PredDef;
1400e8d8bef9SDimitry Andric })) {
1401e8d8bef9SDimitry Andric // To check if PredDef is mutually exclusive with PC we also need to
1402e8d8bef9SDimitry Andric // check that PC.Predicate is exclusive with all predicates from variant
1403e8d8bef9SDimitry Andric // we're expanding. Consider following RW sequence with two variants
1404e8d8bef9SDimitry Andric // (1 & 2), where A, B and C are predicates from corresponding SchedVars:
1405e8d8bef9SDimitry Andric //
1406e8d8bef9SDimitry Andric // 1:A/B - 2:C/B
1407e8d8bef9SDimitry Andric //
1408e8d8bef9SDimitry Andric // Here C is not mutually exclusive with variant (1), because A doesn't
1409e8d8bef9SDimitry Andric // exist in variant (2). This means we have possible transitions from A
1410e8d8bef9SDimitry Andric // to C and from A to B, and fully expanded sequence would look like:
1411e8d8bef9SDimitry Andric //
1412e8d8bef9SDimitry Andric // if (A & C) return ...;
1413e8d8bef9SDimitry Andric // if (A & B) return ...;
1414e8d8bef9SDimitry Andric // if (B) return ...;
1415e8d8bef9SDimitry Andric //
1416e8d8bef9SDimitry Andric // Now let's consider another sequence:
1417e8d8bef9SDimitry Andric //
1418e8d8bef9SDimitry Andric // 1:A/B - 2:A/B
1419e8d8bef9SDimitry Andric //
1420e8d8bef9SDimitry Andric // Here A in variant (2) is mutually exclusive with variant (1), because
1421e8d8bef9SDimitry Andric // A also exists in (2). This means A->B transition is impossible and
1422e8d8bef9SDimitry Andric // expanded sequence would look like:
1423e8d8bef9SDimitry Andric //
1424e8d8bef9SDimitry Andric // if (A) return ...;
1425e8d8bef9SDimitry Andric // if (B) return ...;
14260eae32dcSDimitry Andric if (!llvm::is_contained(Preds, PC.Predicate))
1427e8d8bef9SDimitry Andric continue;
14280b57cec5SDimitry Andric return true;
14290b57cec5SDimitry Andric }
14300b57cec5SDimitry Andric }
14310b57cec5SDimitry Andric return false;
14320b57cec5SDimitry Andric }
14330b57cec5SDimitry Andric
getAllPredicates(ArrayRef<TransVariant> Variants,unsigned ProcId)1434e8d8bef9SDimitry Andric static std::vector<Record *> getAllPredicates(ArrayRef<TransVariant> Variants,
1435e8d8bef9SDimitry Andric unsigned ProcId) {
1436e8d8bef9SDimitry Andric std::vector<Record *> Preds;
1437e8d8bef9SDimitry Andric for (auto &Variant : Variants) {
1438e8d8bef9SDimitry Andric if (!Variant.VarOrSeqDef->isSubClassOf("SchedVar"))
1439e8d8bef9SDimitry Andric continue;
1440e8d8bef9SDimitry Andric Preds.push_back(Variant.VarOrSeqDef->getValueAsDef("Predicate"));
14410b57cec5SDimitry Andric }
1442e8d8bef9SDimitry Andric return Preds;
14430b57cec5SDimitry Andric }
14440b57cec5SDimitry Andric
14450b57cec5SDimitry Andric // Populate IntersectingVariants with any variants or aliased sequences of the
14460b57cec5SDimitry Andric // given SchedRW whose processor indices and predicates are not mutually
14470b57cec5SDimitry Andric // exclusive with the given transition.
getIntersectingVariants(const CodeGenSchedRW & SchedRW,unsigned TransIdx,std::vector<TransVariant> & IntersectingVariants)14480b57cec5SDimitry Andric void PredTransitions::getIntersectingVariants(
14490b57cec5SDimitry Andric const CodeGenSchedRW &SchedRW, unsigned TransIdx,
14500b57cec5SDimitry Andric std::vector<TransVariant> &IntersectingVariants) {
14510b57cec5SDimitry Andric
14520b57cec5SDimitry Andric bool GenericRW = false;
14530b57cec5SDimitry Andric
14540b57cec5SDimitry Andric std::vector<TransVariant> Variants;
14550b57cec5SDimitry Andric if (SchedRW.HasVariants) {
14560b57cec5SDimitry Andric unsigned VarProcIdx = 0;
14570b57cec5SDimitry Andric if (SchedRW.TheDef->getValueInit("SchedModel")->isComplete()) {
14580b57cec5SDimitry Andric Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel");
14590b57cec5SDimitry Andric VarProcIdx = SchedModels.getProcModel(ModelDef).Index;
14600b57cec5SDimitry Andric }
1461e8d8bef9SDimitry Andric if (VarProcIdx == 0 || VarProcIdx == TransVec[TransIdx].ProcIndex) {
14620b57cec5SDimitry Andric // Push each variant. Assign TransVecIdx later.
14630b57cec5SDimitry Andric const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants");
14640b57cec5SDimitry Andric for (Record *VarDef : VarDefs)
14650b57cec5SDimitry Andric Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0);
14660b57cec5SDimitry Andric if (VarProcIdx == 0)
14670b57cec5SDimitry Andric GenericRW = true;
14680b57cec5SDimitry Andric }
1469e8d8bef9SDimitry Andric }
14700b57cec5SDimitry Andric for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
14710b57cec5SDimitry Andric AI != AE; ++AI) {
14720b57cec5SDimitry Andric // If either the SchedAlias itself or the SchedReadWrite that it aliases
14730b57cec5SDimitry Andric // to is defined within a processor model, constrain all variants to
14740b57cec5SDimitry Andric // that processor.
14750b57cec5SDimitry Andric unsigned AliasProcIdx = 0;
14760b57cec5SDimitry Andric if ((*AI)->getValueInit("SchedModel")->isComplete()) {
14770b57cec5SDimitry Andric Record *ModelDef = (*AI)->getValueAsDef("SchedModel");
14780b57cec5SDimitry Andric AliasProcIdx = SchedModels.getProcModel(ModelDef).Index;
14790b57cec5SDimitry Andric }
1480e8d8bef9SDimitry Andric if (AliasProcIdx && AliasProcIdx != TransVec[TransIdx].ProcIndex)
1481e8d8bef9SDimitry Andric continue;
1482e8d8bef9SDimitry Andric if (!Variants.empty()) {
1483e8d8bef9SDimitry Andric const CodeGenProcModel &PM =
1484e8d8bef9SDimitry Andric *(SchedModels.procModelBegin() + AliasProcIdx);
1485e8d8bef9SDimitry Andric PrintFatalError((*AI)->getLoc(),
1486e8d8bef9SDimitry Andric "Multiple variants defined for processor " +
1487e8d8bef9SDimitry Andric PM.ModelName +
1488e8d8bef9SDimitry Andric " Ensure only one SchedAlias exists per RW.");
1489e8d8bef9SDimitry Andric }
1490e8d8bef9SDimitry Andric
14910b57cec5SDimitry Andric const CodeGenSchedRW &AliasRW =
14920b57cec5SDimitry Andric SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
14930b57cec5SDimitry Andric
14940b57cec5SDimitry Andric if (AliasRW.HasVariants) {
14950b57cec5SDimitry Andric const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants");
14960b57cec5SDimitry Andric for (Record *VD : VarDefs)
14970b57cec5SDimitry Andric Variants.emplace_back(VD, AliasRW.Index, AliasProcIdx, 0);
14980b57cec5SDimitry Andric }
14990b57cec5SDimitry Andric if (AliasRW.IsSequence)
15000b57cec5SDimitry Andric Variants.emplace_back(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0);
15010b57cec5SDimitry Andric if (AliasProcIdx == 0)
15020b57cec5SDimitry Andric GenericRW = true;
15030b57cec5SDimitry Andric }
1504e8d8bef9SDimitry Andric std::vector<Record *> AllPreds =
1505e8d8bef9SDimitry Andric getAllPredicates(Variants, TransVec[TransIdx].ProcIndex);
15060b57cec5SDimitry Andric for (TransVariant &Variant : Variants) {
15070b57cec5SDimitry Andric // Don't expand variants if the processor models don't intersect.
15080b57cec5SDimitry Andric // A zero processor index means any processor.
15090b57cec5SDimitry Andric if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) {
15100b57cec5SDimitry Andric Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate");
1511e8d8bef9SDimitry Andric if (mutuallyExclusive(PredDef, AllPreds, TransVec[TransIdx].PredTerm))
15120b57cec5SDimitry Andric continue;
15130b57cec5SDimitry Andric }
1514e8d8bef9SDimitry Andric
15150b57cec5SDimitry Andric if (IntersectingVariants.empty()) {
15160b57cec5SDimitry Andric // The first variant builds on the existing transition.
15170b57cec5SDimitry Andric Variant.TransVecIdx = TransIdx;
15180b57cec5SDimitry Andric IntersectingVariants.push_back(Variant);
15190b57cec5SDimitry Andric }
15200b57cec5SDimitry Andric else {
15210b57cec5SDimitry Andric // Push another copy of the current transition for more variants.
15220b57cec5SDimitry Andric Variant.TransVecIdx = TransVec.size();
15230b57cec5SDimitry Andric IntersectingVariants.push_back(Variant);
15240b57cec5SDimitry Andric TransVec.push_back(TransVec[TransIdx]);
15250b57cec5SDimitry Andric }
15260b57cec5SDimitry Andric }
15270b57cec5SDimitry Andric if (GenericRW && IntersectingVariants.empty()) {
15280b57cec5SDimitry Andric PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has "
15290b57cec5SDimitry Andric "a matching predicate on any processor");
15300b57cec5SDimitry Andric }
15310b57cec5SDimitry Andric }
15320b57cec5SDimitry Andric
15330b57cec5SDimitry Andric // Push the Reads/Writes selected by this variant onto the PredTransition
15340b57cec5SDimitry Andric // specified by VInfo.
15350b57cec5SDimitry Andric void PredTransitions::
pushVariant(const TransVariant & VInfo,bool IsRead)15360b57cec5SDimitry Andric pushVariant(const TransVariant &VInfo, bool IsRead) {
15370b57cec5SDimitry Andric PredTransition &Trans = TransVec[VInfo.TransVecIdx];
15380b57cec5SDimitry Andric
15390b57cec5SDimitry Andric // If this operand transition is reached through a processor-specific alias,
15400b57cec5SDimitry Andric // then the whole transition is specific to this processor.
15410b57cec5SDimitry Andric IdxVec SelectedRWs;
15420b57cec5SDimitry Andric if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) {
15430b57cec5SDimitry Andric Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate");
15440b57cec5SDimitry Andric Trans.PredTerm.emplace_back(IsRead, VInfo.RWIdx,PredDef);
15450b57cec5SDimitry Andric RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected");
15460b57cec5SDimitry Andric SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead);
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric else {
15490b57cec5SDimitry Andric assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") &&
15500b57cec5SDimitry Andric "variant must be a SchedVariant or aliased WriteSequence");
15510b57cec5SDimitry Andric SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead));
15520b57cec5SDimitry Andric }
15530b57cec5SDimitry Andric
15540b57cec5SDimitry Andric const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead);
15550b57cec5SDimitry Andric
15560b57cec5SDimitry Andric SmallVectorImpl<SmallVector<unsigned,4>> &RWSequences = IsRead
15570b57cec5SDimitry Andric ? Trans.ReadSequences : Trans.WriteSequences;
15580b57cec5SDimitry Andric if (SchedRW.IsVariadic) {
15590b57cec5SDimitry Andric unsigned OperIdx = RWSequences.size()-1;
15600b57cec5SDimitry Andric // Make N-1 copies of this transition's last sequence.
1561e8d8bef9SDimitry Andric RWSequences.reserve(RWSequences.size() + SelectedRWs.size() - 1);
15620b57cec5SDimitry Andric RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1,
15630b57cec5SDimitry Andric RWSequences[OperIdx]);
15640b57cec5SDimitry Andric // Push each of the N elements of the SelectedRWs onto a copy of the last
15650b57cec5SDimitry Andric // sequence (split the current operand into N operands).
15660b57cec5SDimitry Andric // Note that write sequences should be expanded within this loop--the entire
15670b57cec5SDimitry Andric // sequence belongs to a single operand.
15680b57cec5SDimitry Andric for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();
15690b57cec5SDimitry Andric RWI != RWE; ++RWI, ++OperIdx) {
15700b57cec5SDimitry Andric IdxVec ExpandedRWs;
15710b57cec5SDimitry Andric if (IsRead)
15720b57cec5SDimitry Andric ExpandedRWs.push_back(*RWI);
15730b57cec5SDimitry Andric else
15740b57cec5SDimitry Andric SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
1575e8d8bef9SDimitry Andric llvm::append_range(RWSequences[OperIdx], ExpandedRWs);
15760b57cec5SDimitry Andric }
15770b57cec5SDimitry Andric assert(OperIdx == RWSequences.size() && "missed a sequence");
15780b57cec5SDimitry Andric }
15790b57cec5SDimitry Andric else {
15800b57cec5SDimitry Andric // Push this transition's expanded sequence onto this transition's last
15810b57cec5SDimitry Andric // sequence (add to the current operand's sequence).
15820b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Seq = RWSequences.back();
15830b57cec5SDimitry Andric IdxVec ExpandedRWs;
1584fe6060f1SDimitry Andric for (unsigned int SelectedRW : SelectedRWs) {
15850b57cec5SDimitry Andric if (IsRead)
1586fe6060f1SDimitry Andric ExpandedRWs.push_back(SelectedRW);
15870b57cec5SDimitry Andric else
1588fe6060f1SDimitry Andric SchedModels.expandRWSequence(SelectedRW, ExpandedRWs, IsRead);
15890b57cec5SDimitry Andric }
1590e8d8bef9SDimitry Andric llvm::append_range(Seq, ExpandedRWs);
15910b57cec5SDimitry Andric }
15920b57cec5SDimitry Andric }
15930b57cec5SDimitry Andric
15940b57cec5SDimitry Andric // RWSeq is a sequence of all Reads or all Writes for the next read or write
15950b57cec5SDimitry Andric // operand. StartIdx is an index into TransVec where partial results
15960b57cec5SDimitry Andric // starts. RWSeq must be applied to all transitions between StartIdx and the end
15970b57cec5SDimitry Andric // of TransVec.
substituteVariantOperand(const SmallVectorImpl<unsigned> & RWSeq,bool IsRead,unsigned StartIdx)1598e8d8bef9SDimitry Andric bool PredTransitions::substituteVariantOperand(
15990b57cec5SDimitry Andric const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {
1600e8d8bef9SDimitry Andric bool Subst = false;
16010b57cec5SDimitry Andric // Visit each original RW within the current sequence.
1602fe6060f1SDimitry Andric for (unsigned int RWI : RWSeq) {
1603fe6060f1SDimitry Andric const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(RWI, IsRead);
16040b57cec5SDimitry Andric // Push this RW on all partial PredTransitions or distribute variants.
16050b57cec5SDimitry Andric // New PredTransitions may be pushed within this loop which should not be
16060b57cec5SDimitry Andric // revisited (TransEnd must be loop invariant).
16070b57cec5SDimitry Andric for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size();
16080b57cec5SDimitry Andric TransIdx != TransEnd; ++TransIdx) {
16090b57cec5SDimitry Andric // Distribute this partial PredTransition across intersecting variants.
16100b57cec5SDimitry Andric // This will push a copies of TransVec[TransIdx] on the back of TransVec.
16110b57cec5SDimitry Andric std::vector<TransVariant> IntersectingVariants;
16120b57cec5SDimitry Andric getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants);
16130b57cec5SDimitry Andric // Now expand each variant on top of its copy of the transition.
1614e8d8bef9SDimitry Andric for (const TransVariant &IV : IntersectingVariants)
1615e8d8bef9SDimitry Andric pushVariant(IV, IsRead);
1616e8d8bef9SDimitry Andric if (IntersectingVariants.empty()) {
1617e8d8bef9SDimitry Andric if (IsRead)
1618fe6060f1SDimitry Andric TransVec[TransIdx].ReadSequences.back().push_back(RWI);
1619e8d8bef9SDimitry Andric else
1620fe6060f1SDimitry Andric TransVec[TransIdx].WriteSequences.back().push_back(RWI);
1621e8d8bef9SDimitry Andric continue;
1622e8d8bef9SDimitry Andric } else {
1623e8d8bef9SDimitry Andric Subst = true;
16240b57cec5SDimitry Andric }
16250b57cec5SDimitry Andric }
16260b57cec5SDimitry Andric }
1627e8d8bef9SDimitry Andric return Subst;
16280b57cec5SDimitry Andric }
16290b57cec5SDimitry Andric
16300b57cec5SDimitry Andric // For each variant of a Read/Write in Trans, substitute the sequence of
16310b57cec5SDimitry Andric // Read/Writes guarded by the variant. This is exponential in the number of
16320b57cec5SDimitry Andric // variant Read/Writes, but in practice detection of mutually exclusive
16330b57cec5SDimitry Andric // predicates should result in linear growth in the total number variants.
16340b57cec5SDimitry Andric //
16350b57cec5SDimitry Andric // This is one step in a breadth-first search of nested variants.
substituteVariants(const PredTransition & Trans)1636e8d8bef9SDimitry Andric bool PredTransitions::substituteVariants(const PredTransition &Trans) {
16370b57cec5SDimitry Andric // Build up a set of partial results starting at the back of
16380b57cec5SDimitry Andric // PredTransitions. Remember the first new transition.
16390b57cec5SDimitry Andric unsigned StartIdx = TransVec.size();
1640e8d8bef9SDimitry Andric bool Subst = false;
1641e8d8bef9SDimitry Andric assert(Trans.ProcIndex != 0);
1642e8d8bef9SDimitry Andric TransVec.emplace_back(Trans.PredTerm, Trans.ProcIndex);
16430b57cec5SDimitry Andric
16440b57cec5SDimitry Andric // Visit each original write sequence.
1645fe6060f1SDimitry Andric for (const auto &WriteSequence : Trans.WriteSequences) {
16460b57cec5SDimitry Andric // Push a new (empty) write sequence onto all partial Transitions.
16470b57cec5SDimitry Andric for (std::vector<PredTransition>::iterator I =
16480b57cec5SDimitry Andric TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
16490b57cec5SDimitry Andric I->WriteSequences.emplace_back();
16500b57cec5SDimitry Andric }
1651fe6060f1SDimitry Andric Subst |=
1652fe6060f1SDimitry Andric substituteVariantOperand(WriteSequence, /*IsRead=*/false, StartIdx);
16530b57cec5SDimitry Andric }
16540b57cec5SDimitry Andric // Visit each original read sequence.
1655fe6060f1SDimitry Andric for (const auto &ReadSequence : Trans.ReadSequences) {
16560b57cec5SDimitry Andric // Push a new (empty) read sequence onto all partial Transitions.
16570b57cec5SDimitry Andric for (std::vector<PredTransition>::iterator I =
16580b57cec5SDimitry Andric TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
16590b57cec5SDimitry Andric I->ReadSequences.emplace_back();
16600b57cec5SDimitry Andric }
1661fe6060f1SDimitry Andric Subst |= substituteVariantOperand(ReadSequence, /*IsRead=*/true, StartIdx);
16620b57cec5SDimitry Andric }
1663e8d8bef9SDimitry Andric return Subst;
16640b57cec5SDimitry Andric }
16650b57cec5SDimitry Andric
addSequences(CodeGenSchedModels & SchedModels,const SmallVectorImpl<SmallVector<unsigned,4>> & Seqs,IdxVec & Result,bool IsRead)1666e8d8bef9SDimitry Andric static void addSequences(CodeGenSchedModels &SchedModels,
1667e8d8bef9SDimitry Andric const SmallVectorImpl<SmallVector<unsigned, 4>> &Seqs,
1668e8d8bef9SDimitry Andric IdxVec &Result, bool IsRead) {
1669e8d8bef9SDimitry Andric for (const auto &S : Seqs)
1670e8d8bef9SDimitry Andric if (!S.empty())
1671e8d8bef9SDimitry Andric Result.push_back(SchedModels.findOrInsertRW(S, IsRead));
1672e8d8bef9SDimitry Andric }
1673e8d8bef9SDimitry Andric
1674e8d8bef9SDimitry Andric #ifndef NDEBUG
dumpRecVec(const RecVec & RV)1675e8d8bef9SDimitry Andric static void dumpRecVec(const RecVec &RV) {
1676e8d8bef9SDimitry Andric for (const Record *R : RV)
1677e8d8bef9SDimitry Andric dbgs() << R->getName() << ", ";
1678e8d8bef9SDimitry Andric }
1679e8d8bef9SDimitry Andric #endif
1680e8d8bef9SDimitry Andric
dumpTransition(const CodeGenSchedModels & SchedModels,const CodeGenSchedClass & FromSC,const CodeGenSchedTransition & SCTrans,const RecVec & Preds)1681e8d8bef9SDimitry Andric static void dumpTransition(const CodeGenSchedModels &SchedModels,
1682e8d8bef9SDimitry Andric const CodeGenSchedClass &FromSC,
1683e8d8bef9SDimitry Andric const CodeGenSchedTransition &SCTrans,
1684e8d8bef9SDimitry Andric const RecVec &Preds) {
1685e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Adding transition from " << FromSC.Name << "("
1686e8d8bef9SDimitry Andric << FromSC.Index << ") to "
1687e8d8bef9SDimitry Andric << SchedModels.getSchedClass(SCTrans.ToClassIdx).Name << "("
1688e8d8bef9SDimitry Andric << SCTrans.ToClassIdx << ") on pred term: (";
1689e8d8bef9SDimitry Andric dumpRecVec(Preds);
1690e8d8bef9SDimitry Andric dbgs() << ") on processor (" << SCTrans.ProcIndex << ")\n");
1691e8d8bef9SDimitry Andric }
16920b57cec5SDimitry Andric // Create a new SchedClass for each variant found by inferFromRW. Pass
inferFromTransitions(ArrayRef<PredTransition> LastTransitions,unsigned FromClassIdx,CodeGenSchedModels & SchedModels)16930b57cec5SDimitry Andric static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
16940b57cec5SDimitry Andric unsigned FromClassIdx,
16950b57cec5SDimitry Andric CodeGenSchedModels &SchedModels) {
16960b57cec5SDimitry Andric // For each PredTransition, create a new CodeGenSchedTransition, which usually
16970b57cec5SDimitry Andric // requires creating a new SchedClass.
1698fe6060f1SDimitry Andric for (const auto &LastTransition : LastTransitions) {
1699e8d8bef9SDimitry Andric // Variant expansion (substituteVariants) may create unconditional
1700e8d8bef9SDimitry Andric // transitions. We don't need to build sched classes for them.
1701fe6060f1SDimitry Andric if (LastTransition.PredTerm.empty())
1702e8d8bef9SDimitry Andric continue;
1703e8d8bef9SDimitry Andric IdxVec OperWritesVariant, OperReadsVariant;
1704fe6060f1SDimitry Andric addSequences(SchedModels, LastTransition.WriteSequences, OperWritesVariant,
1705fe6060f1SDimitry Andric false);
1706fe6060f1SDimitry Andric addSequences(SchedModels, LastTransition.ReadSequences, OperReadsVariant,
1707fe6060f1SDimitry Andric true);
17080b57cec5SDimitry Andric CodeGenSchedTransition SCTrans;
1709e8d8bef9SDimitry Andric
1710e8d8bef9SDimitry Andric // Transition should not contain processor indices already assigned to
1711e8d8bef9SDimitry Andric // InstRWs in this scheduling class.
1712e8d8bef9SDimitry Andric const CodeGenSchedClass &FromSC = SchedModels.getSchedClass(FromClassIdx);
1713fe6060f1SDimitry Andric if (FromSC.InstRWProcIndices.count(LastTransition.ProcIndex))
1714e8d8bef9SDimitry Andric continue;
1715fe6060f1SDimitry Andric SCTrans.ProcIndex = LastTransition.ProcIndex;
17160b57cec5SDimitry Andric SCTrans.ToClassIdx =
17170b57cec5SDimitry Andric SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant,
1718fe6060f1SDimitry Andric OperReadsVariant, LastTransition.ProcIndex);
1719e8d8bef9SDimitry Andric
17200b57cec5SDimitry Andric // The final PredTerm is unique set of predicates guarding the transition.
17210b57cec5SDimitry Andric RecVec Preds;
1722fe6060f1SDimitry Andric transform(LastTransition.PredTerm, std::back_inserter(Preds),
1723fe6060f1SDimitry Andric [](const PredCheck &P) { return P.Predicate; });
17240b57cec5SDimitry Andric Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end());
1725e8d8bef9SDimitry Andric dumpTransition(SchedModels, FromSC, SCTrans, Preds);
17260b57cec5SDimitry Andric SCTrans.PredTerm = std::move(Preds);
17270b57cec5SDimitry Andric SchedModels.getSchedClass(FromClassIdx)
17280b57cec5SDimitry Andric .Transitions.push_back(std::move(SCTrans));
17290b57cec5SDimitry Andric }
17300b57cec5SDimitry Andric }
17310b57cec5SDimitry Andric
getAllProcIndices() const1732e8d8bef9SDimitry Andric std::vector<unsigned> CodeGenSchedModels::getAllProcIndices() const {
1733e8d8bef9SDimitry Andric std::vector<unsigned> ProcIdVec;
1734e8d8bef9SDimitry Andric for (const auto &PM : ProcModelMap)
1735e8d8bef9SDimitry Andric if (PM.second != 0)
1736e8d8bef9SDimitry Andric ProcIdVec.push_back(PM.second);
1737e8d8bef9SDimitry Andric // The order of the keys (Record pointers) of ProcModelMap are not stable.
1738e8d8bef9SDimitry Andric // Sort to stabalize the values.
1739e8d8bef9SDimitry Andric llvm::sort(ProcIdVec);
1740e8d8bef9SDimitry Andric return ProcIdVec;
1741e8d8bef9SDimitry Andric }
1742e8d8bef9SDimitry Andric
1743e8d8bef9SDimitry Andric static std::vector<PredTransition>
makePerProcessorTransitions(const PredTransition & Trans,ArrayRef<unsigned> ProcIndices)1744e8d8bef9SDimitry Andric makePerProcessorTransitions(const PredTransition &Trans,
1745e8d8bef9SDimitry Andric ArrayRef<unsigned> ProcIndices) {
1746e8d8bef9SDimitry Andric std::vector<PredTransition> PerCpuTransVec;
1747e8d8bef9SDimitry Andric for (unsigned ProcId : ProcIndices) {
1748e8d8bef9SDimitry Andric assert(ProcId != 0);
1749e8d8bef9SDimitry Andric PerCpuTransVec.push_back(Trans);
1750e8d8bef9SDimitry Andric PerCpuTransVec.back().ProcIndex = ProcId;
1751e8d8bef9SDimitry Andric }
1752e8d8bef9SDimitry Andric return PerCpuTransVec;
1753e8d8bef9SDimitry Andric }
1754e8d8bef9SDimitry Andric
17550b57cec5SDimitry Andric // Create new SchedClasses for the given ReadWrite list. If any of the
17560b57cec5SDimitry Andric // ReadWrites refers to a SchedVariant, create a new SchedClass for each variant
17570b57cec5SDimitry Andric // of the ReadWrite list, following Aliases if necessary.
inferFromRW(ArrayRef<unsigned> OperWrites,ArrayRef<unsigned> OperReads,unsigned FromClassIdx,ArrayRef<unsigned> ProcIndices)17580b57cec5SDimitry Andric void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites,
17590b57cec5SDimitry Andric ArrayRef<unsigned> OperReads,
17600b57cec5SDimitry Andric unsigned FromClassIdx,
17610b57cec5SDimitry Andric ArrayRef<unsigned> ProcIndices) {
17620b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices);
17630b57cec5SDimitry Andric dbgs() << ") ");
17640b57cec5SDimitry Andric // Create a seed transition with an empty PredTerm and the expanded sequences
17650b57cec5SDimitry Andric // of SchedWrites for the current SchedClass.
17660b57cec5SDimitry Andric std::vector<PredTransition> LastTransitions;
17670b57cec5SDimitry Andric LastTransitions.emplace_back();
17680b57cec5SDimitry Andric
17690b57cec5SDimitry Andric for (unsigned WriteIdx : OperWrites) {
17700b57cec5SDimitry Andric IdxVec WriteSeq;
17710b57cec5SDimitry Andric expandRWSequence(WriteIdx, WriteSeq, /*IsRead=*/false);
17720b57cec5SDimitry Andric LastTransitions[0].WriteSequences.emplace_back();
17730b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences.back();
17740b57cec5SDimitry Andric Seq.append(WriteSeq.begin(), WriteSeq.end());
17750b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");
17760b57cec5SDimitry Andric }
17770b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Reads: ");
17780b57cec5SDimitry Andric for (unsigned ReadIdx : OperReads) {
17790b57cec5SDimitry Andric IdxVec ReadSeq;
17800b57cec5SDimitry Andric expandRWSequence(ReadIdx, ReadSeq, /*IsRead=*/true);
17810b57cec5SDimitry Andric LastTransitions[0].ReadSequences.emplace_back();
17820b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences.back();
17830b57cec5SDimitry Andric Seq.append(ReadSeq.begin(), ReadSeq.end());
17840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");
17850b57cec5SDimitry Andric }
17860b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << '\n');
17870b57cec5SDimitry Andric
1788e8d8bef9SDimitry Andric LastTransitions = makePerProcessorTransitions(
1789e8d8bef9SDimitry Andric LastTransitions[0], llvm::is_contained(ProcIndices, 0)
1790e8d8bef9SDimitry Andric ? ArrayRef<unsigned>(getAllProcIndices())
1791e8d8bef9SDimitry Andric : ProcIndices);
17920b57cec5SDimitry Andric // Collect all PredTransitions for individual operands.
17930b57cec5SDimitry Andric // Iterate until no variant writes remain.
1794e8d8bef9SDimitry Andric bool SubstitutedAny;
1795e8d8bef9SDimitry Andric do {
1796e8d8bef9SDimitry Andric SubstitutedAny = false;
17970b57cec5SDimitry Andric PredTransitions Transitions(*this);
17980b57cec5SDimitry Andric for (const PredTransition &Trans : LastTransitions)
1799e8d8bef9SDimitry Andric SubstitutedAny |= Transitions.substituteVariants(Trans);
18000b57cec5SDimitry Andric LLVM_DEBUG(Transitions.dump());
18010b57cec5SDimitry Andric LastTransitions.swap(Transitions.TransVec);
1802e8d8bef9SDimitry Andric } while (SubstitutedAny);
18030b57cec5SDimitry Andric
18040b57cec5SDimitry Andric // WARNING: We are about to mutate the SchedClasses vector. Do not refer to
18050b57cec5SDimitry Andric // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions.
18060b57cec5SDimitry Andric inferFromTransitions(LastTransitions, FromClassIdx, *this);
18070b57cec5SDimitry Andric }
18080b57cec5SDimitry Andric
18090b57cec5SDimitry Andric // Check if any processor resource group contains all resource records in
18100b57cec5SDimitry Andric // SubUnits.
hasSuperGroup(RecVec & SubUnits,CodeGenProcModel & PM)18110b57cec5SDimitry Andric bool CodeGenSchedModels::hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM) {
1812fe6060f1SDimitry Andric for (Record *ProcResourceDef : PM.ProcResourceDefs) {
1813fe6060f1SDimitry Andric if (!ProcResourceDef->isSubClassOf("ProcResGroup"))
18140b57cec5SDimitry Andric continue;
1815fe6060f1SDimitry Andric RecVec SuperUnits = ProcResourceDef->getValueAsListOfDefs("Resources");
18160b57cec5SDimitry Andric RecIter RI = SubUnits.begin(), RE = SubUnits.end();
18170b57cec5SDimitry Andric for ( ; RI != RE; ++RI) {
18180b57cec5SDimitry Andric if (!is_contained(SuperUnits, *RI)) {
18190b57cec5SDimitry Andric break;
18200b57cec5SDimitry Andric }
18210b57cec5SDimitry Andric }
18220b57cec5SDimitry Andric if (RI == RE)
18230b57cec5SDimitry Andric return true;
18240b57cec5SDimitry Andric }
18250b57cec5SDimitry Andric return false;
18260b57cec5SDimitry Andric }
18270b57cec5SDimitry Andric
18280b57cec5SDimitry Andric // Verify that overlapping groups have a common supergroup.
verifyProcResourceGroups(CodeGenProcModel & PM)18290b57cec5SDimitry Andric void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) {
18300b57cec5SDimitry Andric for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) {
18310b57cec5SDimitry Andric if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup"))
18320b57cec5SDimitry Andric continue;
18330b57cec5SDimitry Andric RecVec CheckUnits =
18340b57cec5SDimitry Andric PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources");
18350b57cec5SDimitry Andric for (unsigned j = i+1; j < e; ++j) {
18360b57cec5SDimitry Andric if (!PM.ProcResourceDefs[j]->isSubClassOf("ProcResGroup"))
18370b57cec5SDimitry Andric continue;
18380b57cec5SDimitry Andric RecVec OtherUnits =
18390b57cec5SDimitry Andric PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources");
18400b57cec5SDimitry Andric if (std::find_first_of(CheckUnits.begin(), CheckUnits.end(),
18410b57cec5SDimitry Andric OtherUnits.begin(), OtherUnits.end())
18420b57cec5SDimitry Andric != CheckUnits.end()) {
18430b57cec5SDimitry Andric // CheckUnits and OtherUnits overlap
1844e8d8bef9SDimitry Andric llvm::append_range(OtherUnits, CheckUnits);
18450b57cec5SDimitry Andric if (!hasSuperGroup(OtherUnits, PM)) {
18460b57cec5SDimitry Andric PrintFatalError((PM.ProcResourceDefs[i])->getLoc(),
18470b57cec5SDimitry Andric "proc resource group overlaps with "
18480b57cec5SDimitry Andric + PM.ProcResourceDefs[j]->getName()
18490b57cec5SDimitry Andric + " but no supergroup contains both.");
18500b57cec5SDimitry Andric }
18510b57cec5SDimitry Andric }
18520b57cec5SDimitry Andric }
18530b57cec5SDimitry Andric }
18540b57cec5SDimitry Andric }
18550b57cec5SDimitry Andric
18560b57cec5SDimitry Andric // Collect all the RegisterFile definitions available in this target.
collectRegisterFiles()18570b57cec5SDimitry Andric void CodeGenSchedModels::collectRegisterFiles() {
18580b57cec5SDimitry Andric RecVec RegisterFileDefs = Records.getAllDerivedDefinitions("RegisterFile");
18590b57cec5SDimitry Andric
18600b57cec5SDimitry Andric // RegisterFiles is the vector of CodeGenRegisterFile.
18610b57cec5SDimitry Andric for (Record *RF : RegisterFileDefs) {
18620b57cec5SDimitry Andric // For each register file definition, construct a CodeGenRegisterFile object
18630b57cec5SDimitry Andric // and add it to the appropriate scheduling model.
18640b57cec5SDimitry Andric CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel"));
18650b57cec5SDimitry Andric PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(),RF));
18660b57cec5SDimitry Andric CodeGenRegisterFile &CGRF = PM.RegisterFiles.back();
18670b57cec5SDimitry Andric CGRF.MaxMovesEliminatedPerCycle =
18680b57cec5SDimitry Andric RF->getValueAsInt("MaxMovesEliminatedPerCycle");
18690b57cec5SDimitry Andric CGRF.AllowZeroMoveEliminationOnly =
18700b57cec5SDimitry Andric RF->getValueAsBit("AllowZeroMoveEliminationOnly");
18710b57cec5SDimitry Andric
18720b57cec5SDimitry Andric // Now set the number of physical registers as well as the cost of registers
18730b57cec5SDimitry Andric // in each register class.
18740b57cec5SDimitry Andric CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs");
18750b57cec5SDimitry Andric if (!CGRF.NumPhysRegs) {
18760b57cec5SDimitry Andric PrintFatalError(RF->getLoc(),
18770b57cec5SDimitry Andric "Invalid RegisterFile with zero physical registers");
18780b57cec5SDimitry Andric }
18790b57cec5SDimitry Andric
18800b57cec5SDimitry Andric RecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses");
18810b57cec5SDimitry Andric std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts");
18820b57cec5SDimitry Andric ListInit *MoveElimInfo = RF->getValueAsListInit("AllowMoveElimination");
18830b57cec5SDimitry Andric for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) {
18840b57cec5SDimitry Andric int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1;
18850b57cec5SDimitry Andric
18860b57cec5SDimitry Andric bool AllowMoveElim = false;
18870b57cec5SDimitry Andric if (MoveElimInfo->size() > I) {
18880b57cec5SDimitry Andric BitInit *Val = cast<BitInit>(MoveElimInfo->getElement(I));
18890b57cec5SDimitry Andric AllowMoveElim = Val->getValue();
18900b57cec5SDimitry Andric }
18910b57cec5SDimitry Andric
18920b57cec5SDimitry Andric CGRF.Costs.emplace_back(RegisterClasses[I], Cost, AllowMoveElim);
18930b57cec5SDimitry Andric }
18940b57cec5SDimitry Andric }
18950b57cec5SDimitry Andric }
18960b57cec5SDimitry Andric
18970b57cec5SDimitry Andric // Collect and sort WriteRes, ReadAdvance, and ProcResources.
collectProcResources()18980b57cec5SDimitry Andric void CodeGenSchedModels::collectProcResources() {
18990b57cec5SDimitry Andric ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits");
19000b57cec5SDimitry Andric ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
19010b57cec5SDimitry Andric
19020b57cec5SDimitry Andric // Add any subtarget-specific SchedReadWrites that are directly associated
19030b57cec5SDimitry Andric // with processor resources. Refer to the parent SchedClass's ProcIndices to
19040b57cec5SDimitry Andric // determine which processors they apply to.
19050b57cec5SDimitry Andric for (const CodeGenSchedClass &SC :
19060b57cec5SDimitry Andric make_range(schedClassBegin(), schedClassEnd())) {
19070b57cec5SDimitry Andric if (SC.ItinClassDef) {
19080b57cec5SDimitry Andric collectItinProcResources(SC.ItinClassDef);
19090b57cec5SDimitry Andric continue;
19100b57cec5SDimitry Andric }
19110b57cec5SDimitry Andric
19120b57cec5SDimitry Andric // This class may have a default ReadWrite list which can be overriden by
19130b57cec5SDimitry Andric // InstRW definitions.
19140b57cec5SDimitry Andric for (Record *RW : SC.InstRWs) {
19150b57cec5SDimitry Andric Record *RWModelDef = RW->getValueAsDef("SchedModel");
19160b57cec5SDimitry Andric unsigned PIdx = getProcModel(RWModelDef).Index;
19170b57cec5SDimitry Andric IdxVec Writes, Reads;
19180b57cec5SDimitry Andric findRWs(RW->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
19190b57cec5SDimitry Andric collectRWResources(Writes, Reads, PIdx);
19200b57cec5SDimitry Andric }
19210b57cec5SDimitry Andric
19220b57cec5SDimitry Andric collectRWResources(SC.Writes, SC.Reads, SC.ProcIndices);
19230b57cec5SDimitry Andric }
19240b57cec5SDimitry Andric // Add resources separately defined by each subtarget.
19250b57cec5SDimitry Andric RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes");
19260b57cec5SDimitry Andric for (Record *WR : WRDefs) {
19270b57cec5SDimitry Andric Record *ModelDef = WR->getValueAsDef("SchedModel");
19280b57cec5SDimitry Andric addWriteRes(WR, getProcModel(ModelDef).Index);
19290b57cec5SDimitry Andric }
19300b57cec5SDimitry Andric RecVec SWRDefs = Records.getAllDerivedDefinitions("SchedWriteRes");
19310b57cec5SDimitry Andric for (Record *SWR : SWRDefs) {
19320b57cec5SDimitry Andric Record *ModelDef = SWR->getValueAsDef("SchedModel");
19330b57cec5SDimitry Andric addWriteRes(SWR, getProcModel(ModelDef).Index);
19340b57cec5SDimitry Andric }
19350b57cec5SDimitry Andric RecVec RADefs = Records.getAllDerivedDefinitions("ReadAdvance");
19360b57cec5SDimitry Andric for (Record *RA : RADefs) {
19370b57cec5SDimitry Andric Record *ModelDef = RA->getValueAsDef("SchedModel");
19380b57cec5SDimitry Andric addReadAdvance(RA, getProcModel(ModelDef).Index);
19390b57cec5SDimitry Andric }
19400b57cec5SDimitry Andric RecVec SRADefs = Records.getAllDerivedDefinitions("SchedReadAdvance");
19410b57cec5SDimitry Andric for (Record *SRA : SRADefs) {
19420b57cec5SDimitry Andric if (SRA->getValueInit("SchedModel")->isComplete()) {
19430b57cec5SDimitry Andric Record *ModelDef = SRA->getValueAsDef("SchedModel");
19440b57cec5SDimitry Andric addReadAdvance(SRA, getProcModel(ModelDef).Index);
19450b57cec5SDimitry Andric }
19460b57cec5SDimitry Andric }
19470b57cec5SDimitry Andric // Add ProcResGroups that are defined within this processor model, which may
19480b57cec5SDimitry Andric // not be directly referenced but may directly specify a buffer size.
19490b57cec5SDimitry Andric RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
19500b57cec5SDimitry Andric for (Record *PRG : ProcResGroups) {
19510b57cec5SDimitry Andric if (!PRG->getValueInit("SchedModel")->isComplete())
19520b57cec5SDimitry Andric continue;
19530b57cec5SDimitry Andric CodeGenProcModel &PM = getProcModel(PRG->getValueAsDef("SchedModel"));
19540b57cec5SDimitry Andric if (!is_contained(PM.ProcResourceDefs, PRG))
19550b57cec5SDimitry Andric PM.ProcResourceDefs.push_back(PRG);
19560b57cec5SDimitry Andric }
19570b57cec5SDimitry Andric // Add ProcResourceUnits unconditionally.
19580b57cec5SDimitry Andric for (Record *PRU : Records.getAllDerivedDefinitions("ProcResourceUnits")) {
19590b57cec5SDimitry Andric if (!PRU->getValueInit("SchedModel")->isComplete())
19600b57cec5SDimitry Andric continue;
19610b57cec5SDimitry Andric CodeGenProcModel &PM = getProcModel(PRU->getValueAsDef("SchedModel"));
19620b57cec5SDimitry Andric if (!is_contained(PM.ProcResourceDefs, PRU))
19630b57cec5SDimitry Andric PM.ProcResourceDefs.push_back(PRU);
19640b57cec5SDimitry Andric }
19650b57cec5SDimitry Andric // Finalize each ProcModel by sorting the record arrays.
19660b57cec5SDimitry Andric for (CodeGenProcModel &PM : ProcModels) {
19670b57cec5SDimitry Andric llvm::sort(PM.WriteResDefs, LessRecord());
19680b57cec5SDimitry Andric llvm::sort(PM.ReadAdvanceDefs, LessRecord());
19690b57cec5SDimitry Andric llvm::sort(PM.ProcResourceDefs, LessRecord());
19700b57cec5SDimitry Andric LLVM_DEBUG(
1971fe6060f1SDimitry Andric PM.dump(); dbgs() << "WriteResDefs: "; for (auto WriteResDef
1972fe6060f1SDimitry Andric : PM.WriteResDefs) {
1973fe6060f1SDimitry Andric if (WriteResDef->isSubClassOf("WriteRes"))
1974fe6060f1SDimitry Andric dbgs() << WriteResDef->getValueAsDef("WriteType")->getName() << " ";
19750b57cec5SDimitry Andric else
1976fe6060f1SDimitry Andric dbgs() << WriteResDef->getName() << " ";
19770b57cec5SDimitry Andric } dbgs() << "\nReadAdvanceDefs: ";
1978fe6060f1SDimitry Andric for (Record *ReadAdvanceDef
1979fe6060f1SDimitry Andric : PM.ReadAdvanceDefs) {
1980fe6060f1SDimitry Andric if (ReadAdvanceDef->isSubClassOf("ReadAdvance"))
1981fe6060f1SDimitry Andric dbgs() << ReadAdvanceDef->getValueAsDef("ReadType")->getName()
1982fe6060f1SDimitry Andric << " ";
19830b57cec5SDimitry Andric else
1984fe6060f1SDimitry Andric dbgs() << ReadAdvanceDef->getName() << " ";
19850b57cec5SDimitry Andric } dbgs()
19860b57cec5SDimitry Andric << "\nProcResourceDefs: ";
1987fe6060f1SDimitry Andric for (Record *ProcResourceDef
1988fe6060f1SDimitry Andric : PM.ProcResourceDefs) {
1989fe6060f1SDimitry Andric dbgs() << ProcResourceDef->getName() << " ";
1990fe6060f1SDimitry Andric } dbgs()
19910b57cec5SDimitry Andric << '\n');
19920b57cec5SDimitry Andric verifyProcResourceGroups(PM);
19930b57cec5SDimitry Andric }
19940b57cec5SDimitry Andric
19950b57cec5SDimitry Andric ProcResourceDefs.clear();
19960b57cec5SDimitry Andric ProcResGroups.clear();
19970b57cec5SDimitry Andric }
19980b57cec5SDimitry Andric
checkCompleteness()19990b57cec5SDimitry Andric void CodeGenSchedModels::checkCompleteness() {
20000b57cec5SDimitry Andric bool Complete = true;
20010b57cec5SDimitry Andric for (const CodeGenProcModel &ProcModel : procModels()) {
20020b57cec5SDimitry Andric const bool HasItineraries = ProcModel.hasItineraries();
20030b57cec5SDimitry Andric if (!ProcModel.ModelDef->getValueAsBit("CompleteModel"))
20040b57cec5SDimitry Andric continue;
20050b57cec5SDimitry Andric for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
20060b57cec5SDimitry Andric if (Inst->hasNoSchedulingInfo)
20070b57cec5SDimitry Andric continue;
20080b57cec5SDimitry Andric if (ProcModel.isUnsupported(*Inst))
20090b57cec5SDimitry Andric continue;
20100b57cec5SDimitry Andric unsigned SCIdx = getSchedClassIdx(*Inst);
20110b57cec5SDimitry Andric if (!SCIdx) {
20121fd87a68SDimitry Andric if (Inst->TheDef->isValueUnset("SchedRW")) {
20130b57cec5SDimitry Andric PrintError(Inst->TheDef->getLoc(),
20140b57cec5SDimitry Andric "No schedule information for instruction '" +
20150b57cec5SDimitry Andric Inst->TheDef->getName() + "' in SchedMachineModel '" +
20160b57cec5SDimitry Andric ProcModel.ModelDef->getName() + "'");
20170b57cec5SDimitry Andric Complete = false;
20180b57cec5SDimitry Andric }
20190b57cec5SDimitry Andric continue;
20200b57cec5SDimitry Andric }
20210b57cec5SDimitry Andric
20220b57cec5SDimitry Andric const CodeGenSchedClass &SC = getSchedClass(SCIdx);
20230b57cec5SDimitry Andric if (!SC.Writes.empty())
20240b57cec5SDimitry Andric continue;
20250b57cec5SDimitry Andric if (HasItineraries && SC.ItinClassDef != nullptr &&
20260b57cec5SDimitry Andric SC.ItinClassDef->getName() != "NoItinerary")
20270b57cec5SDimitry Andric continue;
20280b57cec5SDimitry Andric
20290b57cec5SDimitry Andric const RecVec &InstRWs = SC.InstRWs;
20300b57cec5SDimitry Andric auto I = find_if(InstRWs, [&ProcModel](const Record *R) {
20310b57cec5SDimitry Andric return R->getValueAsDef("SchedModel") == ProcModel.ModelDef;
20320b57cec5SDimitry Andric });
20330b57cec5SDimitry Andric if (I == InstRWs.end()) {
20340b57cec5SDimitry Andric PrintError(Inst->TheDef->getLoc(), "'" + ProcModel.ModelName +
20350b57cec5SDimitry Andric "' lacks information for '" +
20360b57cec5SDimitry Andric Inst->TheDef->getName() + "'");
20370b57cec5SDimitry Andric Complete = false;
20380b57cec5SDimitry Andric }
20390b57cec5SDimitry Andric }
20400b57cec5SDimitry Andric }
20410b57cec5SDimitry Andric if (!Complete) {
20420b57cec5SDimitry Andric errs() << "\n\nIncomplete schedule models found.\n"
20430b57cec5SDimitry Andric << "- Consider setting 'CompleteModel = 0' while developing new models.\n"
20440b57cec5SDimitry Andric << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n"
20450b57cec5SDimitry Andric << "- Instructions should usually have Sched<[...]> as a superclass, "
20460b57cec5SDimitry Andric "you may temporarily use an empty list.\n"
20470b57cec5SDimitry Andric << "- Instructions related to unsupported features can be excluded with "
20480b57cec5SDimitry Andric "list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the "
20490b57cec5SDimitry Andric "processor model.\n\n";
20500b57cec5SDimitry Andric PrintFatalError("Incomplete schedule model");
20510b57cec5SDimitry Andric }
20520b57cec5SDimitry Andric }
20530b57cec5SDimitry Andric
20540b57cec5SDimitry Andric // Collect itinerary class resources for each processor.
collectItinProcResources(Record * ItinClassDef)20550b57cec5SDimitry Andric void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) {
20560b57cec5SDimitry Andric for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {
20570b57cec5SDimitry Andric const CodeGenProcModel &PM = ProcModels[PIdx];
20580b57cec5SDimitry Andric // For all ItinRW entries.
20590b57cec5SDimitry Andric bool HasMatch = false;
20600b57cec5SDimitry Andric for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();
20610b57cec5SDimitry Andric II != IE; ++II) {
20620b57cec5SDimitry Andric RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
2063e8d8bef9SDimitry Andric if (!llvm::is_contained(Matched, ItinClassDef))
20640b57cec5SDimitry Andric continue;
20650b57cec5SDimitry Andric if (HasMatch)
20660b57cec5SDimitry Andric PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "
20670b57cec5SDimitry Andric + ItinClassDef->getName()
20680b57cec5SDimitry Andric + " in ItinResources for " + PM.ModelName);
20690b57cec5SDimitry Andric HasMatch = true;
20700b57cec5SDimitry Andric IdxVec Writes, Reads;
20710b57cec5SDimitry Andric findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
20720b57cec5SDimitry Andric collectRWResources(Writes, Reads, PIdx);
20730b57cec5SDimitry Andric }
20740b57cec5SDimitry Andric }
20750b57cec5SDimitry Andric }
20760b57cec5SDimitry Andric
collectRWResources(unsigned RWIdx,bool IsRead,ArrayRef<unsigned> ProcIndices)20770b57cec5SDimitry Andric void CodeGenSchedModels::collectRWResources(unsigned RWIdx, bool IsRead,
20780b57cec5SDimitry Andric ArrayRef<unsigned> ProcIndices) {
20790b57cec5SDimitry Andric const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);
20800b57cec5SDimitry Andric if (SchedRW.TheDef) {
20810b57cec5SDimitry Andric if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) {
20820b57cec5SDimitry Andric for (unsigned Idx : ProcIndices)
20830b57cec5SDimitry Andric addWriteRes(SchedRW.TheDef, Idx);
20840b57cec5SDimitry Andric }
20850b57cec5SDimitry Andric else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) {
20860b57cec5SDimitry Andric for (unsigned Idx : ProcIndices)
20870b57cec5SDimitry Andric addReadAdvance(SchedRW.TheDef, Idx);
20880b57cec5SDimitry Andric }
20890b57cec5SDimitry Andric }
2090fe6060f1SDimitry Andric for (auto *Alias : SchedRW.Aliases) {
20910b57cec5SDimitry Andric IdxVec AliasProcIndices;
2092fe6060f1SDimitry Andric if (Alias->getValueInit("SchedModel")->isComplete()) {
20930b57cec5SDimitry Andric AliasProcIndices.push_back(
2094fe6060f1SDimitry Andric getProcModel(Alias->getValueAsDef("SchedModel")).Index);
2095fe6060f1SDimitry Andric } else
20960b57cec5SDimitry Andric AliasProcIndices = ProcIndices;
2097fe6060f1SDimitry Andric const CodeGenSchedRW &AliasRW = getSchedRW(Alias->getValueAsDef("AliasRW"));
20980b57cec5SDimitry Andric assert(AliasRW.IsRead == IsRead && "cannot alias reads to writes");
20990b57cec5SDimitry Andric
21000b57cec5SDimitry Andric IdxVec ExpandedRWs;
21010b57cec5SDimitry Andric expandRWSequence(AliasRW.Index, ExpandedRWs, IsRead);
2102fe6060f1SDimitry Andric for (unsigned int ExpandedRW : ExpandedRWs) {
2103fe6060f1SDimitry Andric collectRWResources(ExpandedRW, IsRead, AliasProcIndices);
21040b57cec5SDimitry Andric }
21050b57cec5SDimitry Andric }
21060b57cec5SDimitry Andric }
21070b57cec5SDimitry Andric
21080b57cec5SDimitry Andric // Collect resources for a set of read/write types and processor indices.
collectRWResources(ArrayRef<unsigned> Writes,ArrayRef<unsigned> Reads,ArrayRef<unsigned> ProcIndices)21090b57cec5SDimitry Andric void CodeGenSchedModels::collectRWResources(ArrayRef<unsigned> Writes,
21100b57cec5SDimitry Andric ArrayRef<unsigned> Reads,
21110b57cec5SDimitry Andric ArrayRef<unsigned> ProcIndices) {
21120b57cec5SDimitry Andric for (unsigned Idx : Writes)
21130b57cec5SDimitry Andric collectRWResources(Idx, /*IsRead=*/false, ProcIndices);
21140b57cec5SDimitry Andric
21150b57cec5SDimitry Andric for (unsigned Idx : Reads)
21160b57cec5SDimitry Andric collectRWResources(Idx, /*IsRead=*/true, ProcIndices);
21170b57cec5SDimitry Andric }
21180b57cec5SDimitry Andric
21190b57cec5SDimitry Andric // Find the processor's resource units for this kind of resource.
findProcResUnits(Record * ProcResKind,const CodeGenProcModel & PM,ArrayRef<SMLoc> Loc) const21200b57cec5SDimitry Andric Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind,
21210b57cec5SDimitry Andric const CodeGenProcModel &PM,
21220b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) const {
21230b57cec5SDimitry Andric if (ProcResKind->isSubClassOf("ProcResourceUnits"))
21240b57cec5SDimitry Andric return ProcResKind;
21250b57cec5SDimitry Andric
21260b57cec5SDimitry Andric Record *ProcUnitDef = nullptr;
21270b57cec5SDimitry Andric assert(!ProcResourceDefs.empty());
21280b57cec5SDimitry Andric assert(!ProcResGroups.empty());
21290b57cec5SDimitry Andric
21300b57cec5SDimitry Andric for (Record *ProcResDef : ProcResourceDefs) {
21310b57cec5SDimitry Andric if (ProcResDef->getValueAsDef("Kind") == ProcResKind
21320b57cec5SDimitry Andric && ProcResDef->getValueAsDef("SchedModel") == PM.ModelDef) {
21330b57cec5SDimitry Andric if (ProcUnitDef) {
21340b57cec5SDimitry Andric PrintFatalError(Loc,
21350b57cec5SDimitry Andric "Multiple ProcessorResourceUnits associated with "
21360b57cec5SDimitry Andric + ProcResKind->getName());
21370b57cec5SDimitry Andric }
21380b57cec5SDimitry Andric ProcUnitDef = ProcResDef;
21390b57cec5SDimitry Andric }
21400b57cec5SDimitry Andric }
21410b57cec5SDimitry Andric for (Record *ProcResGroup : ProcResGroups) {
21420b57cec5SDimitry Andric if (ProcResGroup == ProcResKind
21430b57cec5SDimitry Andric && ProcResGroup->getValueAsDef("SchedModel") == PM.ModelDef) {
21440b57cec5SDimitry Andric if (ProcUnitDef) {
21450b57cec5SDimitry Andric PrintFatalError(Loc,
21460b57cec5SDimitry Andric "Multiple ProcessorResourceUnits associated with "
21470b57cec5SDimitry Andric + ProcResKind->getName());
21480b57cec5SDimitry Andric }
21490b57cec5SDimitry Andric ProcUnitDef = ProcResGroup;
21500b57cec5SDimitry Andric }
21510b57cec5SDimitry Andric }
21520b57cec5SDimitry Andric if (!ProcUnitDef) {
21530b57cec5SDimitry Andric PrintFatalError(Loc,
21540b57cec5SDimitry Andric "No ProcessorResources associated with "
21550b57cec5SDimitry Andric + ProcResKind->getName());
21560b57cec5SDimitry Andric }
21570b57cec5SDimitry Andric return ProcUnitDef;
21580b57cec5SDimitry Andric }
21590b57cec5SDimitry Andric
21600b57cec5SDimitry Andric // Iteratively add a resource and its super resources.
addProcResource(Record * ProcResKind,CodeGenProcModel & PM,ArrayRef<SMLoc> Loc)21610b57cec5SDimitry Andric void CodeGenSchedModels::addProcResource(Record *ProcResKind,
21620b57cec5SDimitry Andric CodeGenProcModel &PM,
21630b57cec5SDimitry Andric ArrayRef<SMLoc> Loc) {
21640b57cec5SDimitry Andric while (true) {
21650b57cec5SDimitry Andric Record *ProcResUnits = findProcResUnits(ProcResKind, PM, Loc);
21660b57cec5SDimitry Andric
21670b57cec5SDimitry Andric // See if this ProcResource is already associated with this processor.
21680b57cec5SDimitry Andric if (is_contained(PM.ProcResourceDefs, ProcResUnits))
21690b57cec5SDimitry Andric return;
21700b57cec5SDimitry Andric
21710b57cec5SDimitry Andric PM.ProcResourceDefs.push_back(ProcResUnits);
21720b57cec5SDimitry Andric if (ProcResUnits->isSubClassOf("ProcResGroup"))
21730b57cec5SDimitry Andric return;
21740b57cec5SDimitry Andric
21750b57cec5SDimitry Andric if (!ProcResUnits->getValueInit("Super")->isComplete())
21760b57cec5SDimitry Andric return;
21770b57cec5SDimitry Andric
21780b57cec5SDimitry Andric ProcResKind = ProcResUnits->getValueAsDef("Super");
21790b57cec5SDimitry Andric }
21800b57cec5SDimitry Andric }
21810b57cec5SDimitry Andric
21820b57cec5SDimitry Andric // Add resources for a SchedWrite to this processor if they don't exist.
addWriteRes(Record * ProcWriteResDef,unsigned PIdx)21830b57cec5SDimitry Andric void CodeGenSchedModels::addWriteRes(Record *ProcWriteResDef, unsigned PIdx) {
21840b57cec5SDimitry Andric assert(PIdx && "don't add resources to an invalid Processor model");
21850b57cec5SDimitry Andric
21860b57cec5SDimitry Andric RecVec &WRDefs = ProcModels[PIdx].WriteResDefs;
21870b57cec5SDimitry Andric if (is_contained(WRDefs, ProcWriteResDef))
21880b57cec5SDimitry Andric return;
21890b57cec5SDimitry Andric WRDefs.push_back(ProcWriteResDef);
21900b57cec5SDimitry Andric
21910b57cec5SDimitry Andric // Visit ProcResourceKinds referenced by the newly discovered WriteRes.
21920b57cec5SDimitry Andric RecVec ProcResDefs = ProcWriteResDef->getValueAsListOfDefs("ProcResources");
2193fe6060f1SDimitry Andric for (auto *ProcResDef : ProcResDefs) {
2194fe6060f1SDimitry Andric addProcResource(ProcResDef, ProcModels[PIdx], ProcWriteResDef->getLoc());
21950b57cec5SDimitry Andric }
21960b57cec5SDimitry Andric }
21970b57cec5SDimitry Andric
21980b57cec5SDimitry Andric // Add resources for a ReadAdvance to this processor if they don't exist.
addReadAdvance(Record * ProcReadAdvanceDef,unsigned PIdx)21990b57cec5SDimitry Andric void CodeGenSchedModels::addReadAdvance(Record *ProcReadAdvanceDef,
22000b57cec5SDimitry Andric unsigned PIdx) {
22010b57cec5SDimitry Andric RecVec &RADefs = ProcModels[PIdx].ReadAdvanceDefs;
22020b57cec5SDimitry Andric if (is_contained(RADefs, ProcReadAdvanceDef))
22030b57cec5SDimitry Andric return;
22040b57cec5SDimitry Andric RADefs.push_back(ProcReadAdvanceDef);
22050b57cec5SDimitry Andric }
22060b57cec5SDimitry Andric
getProcResourceIdx(Record * PRDef) const22070b57cec5SDimitry Andric unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const {
22080b57cec5SDimitry Andric RecIter PRPos = find(ProcResourceDefs, PRDef);
22090b57cec5SDimitry Andric if (PRPos == ProcResourceDefs.end())
22100b57cec5SDimitry Andric PrintFatalError(PRDef->getLoc(), "ProcResource def is not included in "
22110b57cec5SDimitry Andric "the ProcResources list for " + ModelName);
22120b57cec5SDimitry Andric // Idx=0 is reserved for invalid.
22130b57cec5SDimitry Andric return 1 + (PRPos - ProcResourceDefs.begin());
22140b57cec5SDimitry Andric }
22150b57cec5SDimitry Andric
isUnsupported(const CodeGenInstruction & Inst) const22160b57cec5SDimitry Andric bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const {
22170b57cec5SDimitry Andric for (const Record *TheDef : UnsupportedFeaturesDefs) {
22180b57cec5SDimitry Andric for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) {
22190b57cec5SDimitry Andric if (TheDef->getName() == PredDef->getName())
22200b57cec5SDimitry Andric return true;
22210b57cec5SDimitry Andric }
22220b57cec5SDimitry Andric }
22230b57cec5SDimitry Andric return false;
22240b57cec5SDimitry Andric }
22250b57cec5SDimitry Andric
22260b57cec5SDimitry Andric #ifndef NDEBUG
dump() const22270b57cec5SDimitry Andric void CodeGenProcModel::dump() const {
22280b57cec5SDimitry Andric dbgs() << Index << ": " << ModelName << " "
22290b57cec5SDimitry Andric << (ModelDef ? ModelDef->getName() : "inferred") << " "
22300b57cec5SDimitry Andric << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n';
22310b57cec5SDimitry Andric }
22320b57cec5SDimitry Andric
dump() const22330b57cec5SDimitry Andric void CodeGenSchedRW::dump() const {
22340b57cec5SDimitry Andric dbgs() << Name << (IsVariadic ? " (V) " : " ");
22350b57cec5SDimitry Andric if (IsSequence) {
22360b57cec5SDimitry Andric dbgs() << "(";
22370b57cec5SDimitry Andric dumpIdxVec(Sequence);
22380b57cec5SDimitry Andric dbgs() << ")";
22390b57cec5SDimitry Andric }
22400b57cec5SDimitry Andric }
22410b57cec5SDimitry Andric
dump(const CodeGenSchedModels * SchedModels) const22420b57cec5SDimitry Andric void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
22430b57cec5SDimitry Andric dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n'
22440b57cec5SDimitry Andric << " Writes: ";
22450b57cec5SDimitry Andric for (unsigned i = 0, N = Writes.size(); i < N; ++i) {
22460b57cec5SDimitry Andric SchedModels->getSchedWrite(Writes[i]).dump();
22470b57cec5SDimitry Andric if (i < N-1) {
22480b57cec5SDimitry Andric dbgs() << '\n';
22490b57cec5SDimitry Andric dbgs().indent(10);
22500b57cec5SDimitry Andric }
22510b57cec5SDimitry Andric }
22520b57cec5SDimitry Andric dbgs() << "\n Reads: ";
22530b57cec5SDimitry Andric for (unsigned i = 0, N = Reads.size(); i < N; ++i) {
22540b57cec5SDimitry Andric SchedModels->getSchedRead(Reads[i]).dump();
22550b57cec5SDimitry Andric if (i < N-1) {
22560b57cec5SDimitry Andric dbgs() << '\n';
22570b57cec5SDimitry Andric dbgs().indent(10);
22580b57cec5SDimitry Andric }
22590b57cec5SDimitry Andric }
2260e8d8bef9SDimitry Andric dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices);
22610b57cec5SDimitry Andric if (!Transitions.empty()) {
22620b57cec5SDimitry Andric dbgs() << "\n Transitions for Proc ";
22630b57cec5SDimitry Andric for (const CodeGenSchedTransition &Transition : Transitions) {
2264e8d8bef9SDimitry Andric dbgs() << Transition.ProcIndex << ", ";
22650b57cec5SDimitry Andric }
22660b57cec5SDimitry Andric }
2267e8d8bef9SDimitry Andric dbgs() << '\n';
22680b57cec5SDimitry Andric }
22690b57cec5SDimitry Andric
dump() const22700b57cec5SDimitry Andric void PredTransitions::dump() const {
22710b57cec5SDimitry Andric dbgs() << "Expanded Variants:\n";
2272fe6060f1SDimitry Andric for (const auto &TI : TransVec) {
22730b57cec5SDimitry Andric dbgs() << "{";
2274fe6060f1SDimitry Andric ListSeparator LS;
2275fe6060f1SDimitry Andric for (const PredCheck &PC : TI.PredTerm)
2276fe6060f1SDimitry Andric dbgs() << LS << SchedModels.getSchedRW(PC.RWIdx, PC.IsRead).Name << ":"
2277fe6060f1SDimitry Andric << PC.Predicate->getName();
22780b57cec5SDimitry Andric dbgs() << "},\n => {";
22790b57cec5SDimitry Andric for (SmallVectorImpl<SmallVector<unsigned, 4>>::const_iterator
2280fe6060f1SDimitry Andric WSI = TI.WriteSequences.begin(),
2281fe6060f1SDimitry Andric WSE = TI.WriteSequences.end();
22820b57cec5SDimitry Andric WSI != WSE; ++WSI) {
22830b57cec5SDimitry Andric dbgs() << "(";
2284fe6060f1SDimitry Andric ListSeparator LS;
2285fe6060f1SDimitry Andric for (unsigned N : *WSI)
2286fe6060f1SDimitry Andric dbgs() << LS << SchedModels.getSchedWrite(N).Name;
22870b57cec5SDimitry Andric dbgs() << "),";
22880b57cec5SDimitry Andric }
22890b57cec5SDimitry Andric dbgs() << "}\n";
22900b57cec5SDimitry Andric }
22910b57cec5SDimitry Andric }
22920b57cec5SDimitry Andric #endif // NDEBUG
2293