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