blob: db6c909e8724106e11a812175398ef81b788fc90 [file] [log] [blame]
Andrew Trick87255e32012-07-07 04:00:00 +00001//===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Alp Tokercb402912014-01-24 17:20:08 +000010// This file defines structures to encapsulate the machine model as described in
Andrew Trick87255e32012-07-07 04:00:00 +000011// the target description.
12//
13//===----------------------------------------------------------------------===//
14
Andrew Trick87255e32012-07-07 04:00:00 +000015#include "CodeGenSchedule.h"
Benjamin Kramercbce2f02018-01-23 23:05:04 +000016#include "CodeGenInstruction.h"
Andrew Trick87255e32012-07-07 04:00:00 +000017#include "CodeGenTarget.h"
Craig Topperf19eacf2018-03-21 02:48:34 +000018#include "llvm/ADT/MapVector.h"
Benjamin Kramercbce2f02018-01-23 23:05:04 +000019#include "llvm/ADT/STLExtras.h"
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +000020#include "llvm/ADT/SmallPtrSet.h"
21#include "llvm/ADT/SmallSet.h"
22#include "llvm/ADT/SmallVector.h"
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +000023#include "llvm/Support/Casting.h"
Andrew Trick87255e32012-07-07 04:00:00 +000024#include "llvm/Support/Debug.h"
Andrew Trick9e1deb62012-10-03 23:06:32 +000025#include "llvm/Support/Regex.h"
Benjamin Kramercbce2f02018-01-23 23:05:04 +000026#include "llvm/Support/raw_ostream.h"
Chandler Carruth91d19d82012-12-04 10:37:14 +000027#include "llvm/TableGen/Error.h"
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +000028#include <algorithm>
29#include <iterator>
30#include <utility>
Andrew Trick87255e32012-07-07 04:00:00 +000031
32using namespace llvm;
33
Chandler Carruth97acce22014-04-22 03:06:00 +000034#define DEBUG_TYPE "subtarget-emitter"
35
Andrew Trick76686492012-09-15 00:19:57 +000036#ifndef NDEBUG
Benjamin Kramere1761952015-10-24 12:46:49 +000037static void dumpIdxVec(ArrayRef<unsigned> V) {
38 for (unsigned Idx : V)
39 dbgs() << Idx << ", ";
Andrew Trick33401e82012-09-15 00:19:59 +000040}
Andrew Trick76686492012-09-15 00:19:57 +000041#endif
42
Juergen Ributzka05c5a932013-11-19 03:08:35 +000043namespace {
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +000044
Andrew Trick9e1deb62012-10-03 23:06:32 +000045// (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp.
46struct InstrsOp : public SetTheory::Operator {
Craig Topper716b0732014-03-05 05:17:42 +000047 void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
48 ArrayRef<SMLoc> Loc) override {
Juergen Ributzka05c5a932013-11-19 03:08:35 +000049 ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc);
50 }
51};
Juergen Ributzkad12ccbd2013-11-19 00:57:56 +000052
Andrew Trick9e1deb62012-10-03 23:06:32 +000053// (instregex "OpcPat",...) Find all instructions matching an opcode pattern.
Andrew Trick9e1deb62012-10-03 23:06:32 +000054struct InstRegexOp : public SetTheory::Operator {
55 const CodeGenTarget &Target;
56 InstRegexOp(const CodeGenTarget &t): Target(t) {}
57
Benjamin Kramercbce2f02018-01-23 23:05:04 +000058 /// Remove any text inside of parentheses from S.
59 static std::string removeParens(llvm::StringRef S) {
60 std::string Result;
61 unsigned Paren = 0;
62 // NB: We don't care about escaped parens here.
63 for (char C : S) {
64 switch (C) {
65 case '(':
66 ++Paren;
67 break;
68 case ')':
69 --Paren;
70 break;
71 default:
72 if (Paren == 0)
73 Result += C;
74 }
75 }
76 return Result;
77 }
78
Juergen Ributzka05c5a932013-11-19 03:08:35 +000079 void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
Craig Topper716b0732014-03-05 05:17:42 +000080 ArrayRef<SMLoc> Loc) override {
Javed Absarfc500042017-10-05 13:27:43 +000081 for (Init *Arg : make_range(Expr->arg_begin(), Expr->arg_end())) {
82 StringInit *SI = dyn_cast<StringInit>(Arg);
Juergen Ributzka05c5a932013-11-19 03:08:35 +000083 if (!SI)
Benjamin Kramercbce2f02018-01-23 23:05:04 +000084 PrintFatalError(Loc, "instregex requires pattern string: " +
85 Expr->getAsString());
Simon Pilgrim75cc2f92018-03-20 22:20:28 +000086 StringRef Original = SI->getValue();
87
Benjamin Kramercbce2f02018-01-23 23:05:04 +000088 // Extract a prefix that we can binary search on.
89 static const char RegexMetachars[] = "()^$|*+?.[]\\{}";
Simon Pilgrim75cc2f92018-03-20 22:20:28 +000090 auto FirstMeta = Original.find_first_of(RegexMetachars);
91
Benjamin Kramercbce2f02018-01-23 23:05:04 +000092 // Look for top-level | or ?. We cannot optimize them to binary search.
Simon Pilgrim75cc2f92018-03-20 22:20:28 +000093 if (removeParens(Original).find_first_of("|?") != std::string::npos)
Benjamin Kramercbce2f02018-01-23 23:05:04 +000094 FirstMeta = 0;
Simon Pilgrim75cc2f92018-03-20 22:20:28 +000095
96 Optional<Regex> Regexpr = None;
97 StringRef Prefix = Original.substr(0, FirstMeta);
Simon Pilgrim34d512e2018-03-24 21:04:20 +000098 StringRef PatStr = Original.substr(FirstMeta);
99 if (!PatStr.empty()) {
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000100 // For the rest use a python-style prefix match.
Simon Pilgrim34d512e2018-03-24 21:04:20 +0000101 std::string pat = PatStr;
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000102 if (pat[0] != '^') {
103 pat.insert(0, "^(");
104 pat.insert(pat.end(), ')');
105 }
106 Regexpr = Regex(pat);
Benjamin Kramercbce2f02018-01-23 23:05:04 +0000107 }
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000108
Simon Pilgrimd044f9c2018-03-25 19:20:08 +0000109 int NumMatches = 0;
110
Benjamin Kramer4890a712018-01-24 22:35:11 +0000111 unsigned NumGeneric = Target.getNumFixedInstructions();
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000112 ArrayRef<const CodeGenInstruction *> Generics =
113 Target.getInstructionsByEnumValue().slice(0, NumGeneric + 1);
114
Benjamin Kramercbce2f02018-01-23 23:05:04 +0000115 // The generic opcodes are unsorted, handle them manually.
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000116 for (auto *Inst : Generics) {
117 StringRef InstName = Inst->TheDef->getName();
118 if (InstName.startswith(Prefix) &&
Simon Pilgrimd044f9c2018-03-25 19:20:08 +0000119 (!Regexpr || Regexpr->match(InstName.substr(Prefix.size())))) {
Benjamin Kramercbce2f02018-01-23 23:05:04 +0000120 Elts.insert(Inst->TheDef);
Simon Pilgrimd044f9c2018-03-25 19:20:08 +0000121 NumMatches++;
122 }
Benjamin Kramercbce2f02018-01-23 23:05:04 +0000123 }
124
125 ArrayRef<const CodeGenInstruction *> Instructions =
Benjamin Kramer4890a712018-01-24 22:35:11 +0000126 Target.getInstructionsByEnumValue().slice(NumGeneric + 1);
Benjamin Kramercbce2f02018-01-23 23:05:04 +0000127
128 // Target instructions are sorted. Find the range that starts with our
129 // prefix.
130 struct Comp {
131 bool operator()(const CodeGenInstruction *LHS, StringRef RHS) {
132 return LHS->TheDef->getName() < RHS;
133 }
134 bool operator()(StringRef LHS, const CodeGenInstruction *RHS) {
135 return LHS < RHS->TheDef->getName() &&
136 !RHS->TheDef->getName().startswith(LHS);
137 }
138 };
139 auto Range = std::equal_range(Instructions.begin(), Instructions.end(),
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000140 Prefix, Comp());
Benjamin Kramercbce2f02018-01-23 23:05:04 +0000141
142 // For this range we know that it starts with the prefix. Check if there's
143 // a regex that needs to be checked.
144 for (auto *Inst : make_range(Range)) {
Simon Pilgrim75cc2f92018-03-20 22:20:28 +0000145 StringRef InstName = Inst->TheDef->getName();
Simon Pilgrimd044f9c2018-03-25 19:20:08 +0000146 if (!Regexpr || Regexpr->match(InstName.substr(Prefix.size()))) {
Craig Topper8a417c12014-12-09 08:05:51 +0000147 Elts.insert(Inst->TheDef);
Simon Pilgrimd044f9c2018-03-25 19:20:08 +0000148 NumMatches++;
149 }
Juergen Ributzka05c5a932013-11-19 03:08:35 +0000150 }
Simon Pilgrimd044f9c2018-03-25 19:20:08 +0000151
152 if (0 == NumMatches)
153 PrintFatalError(Loc, "instregex has no matches: " + Original);
Juergen Ributzka05c5a932013-11-19 03:08:35 +0000154 }
Juergen Ributzka05c5a932013-11-19 03:08:35 +0000155 }
Andrew Trick9e1deb62012-10-03 23:06:32 +0000156};
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +0000157
Juergen Ributzka05c5a932013-11-19 03:08:35 +0000158} // end anonymous namespace
Juergen Ributzkad12ccbd2013-11-19 00:57:56 +0000159
Andrew Trick76686492012-09-15 00:19:57 +0000160/// CodeGenModels ctor interprets machine model records and populates maps.
Andrew Trick87255e32012-07-07 04:00:00 +0000161CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
162 const CodeGenTarget &TGT):
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000163 Records(RK), Target(TGT) {
Andrew Trick87255e32012-07-07 04:00:00 +0000164
Andrew Trick9e1deb62012-10-03 23:06:32 +0000165 Sets.addFieldExpander("InstRW", "Instrs");
166
167 // Allow Set evaluation to recognize the dags used in InstRW records:
168 // (instrs Op1, Op1...)
Craig Topperba6057d2015-04-24 06:49:44 +0000169 Sets.addOperator("instrs", llvm::make_unique<InstrsOp>());
170 Sets.addOperator("instregex", llvm::make_unique<InstRegexOp>(Target));
Andrew Trick9e1deb62012-10-03 23:06:32 +0000171
Andrew Trick76686492012-09-15 00:19:57 +0000172 // Instantiate a CodeGenProcModel for each SchedMachineModel with the values
173 // that are explicitly referenced in tablegen records. Resources associated
174 // with each processor will be derived later. Populate ProcModelMap with the
175 // CodeGenProcModel instances.
176 collectProcModels();
Andrew Trick87255e32012-07-07 04:00:00 +0000177
Andrew Trick76686492012-09-15 00:19:57 +0000178 // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly
179 // defined, and populate SchedReads and SchedWrites vectors. Implicit
180 // SchedReadWrites that represent sequences derived from expanded variant will
181 // be inferred later.
182 collectSchedRW();
183
184 // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly
185 // required by an instruction definition, and populate SchedClassIdxMap. Set
186 // NumItineraryClasses to the number of explicit itinerary classes referenced
187 // by instructions. Set NumInstrSchedClasses to the number of itinerary
188 // classes plus any classes implied by instructions that derive from class
189 // Sched and provide SchedRW list. This does not infer any new classes from
190 // SchedVariant.
191 collectSchedClasses();
192
193 // Find instruction itineraries for each processor. Sort and populate
Andrew Trick9257b8f2012-09-22 02:24:21 +0000194 // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires
Andrew Trick76686492012-09-15 00:19:57 +0000195 // all itinerary classes to be discovered.
196 collectProcItins();
197
198 // Find ItinRW records for each processor and itinerary class.
199 // (For per-operand resources mapped to itinerary classes).
200 collectProcItinRW();
Andrew Trick33401e82012-09-15 00:19:59 +0000201
Simon Dardis5f95c9a2016-06-24 08:43:27 +0000202 // Find UnsupportedFeatures records for each processor.
203 // (For per-operand resources mapped to itinerary classes).
204 collectProcUnsupportedFeatures();
205
Andrew Trick33401e82012-09-15 00:19:59 +0000206 // Infer new SchedClasses from SchedVariant.
207 inferSchedClasses();
208
Andrew Trick1e46d482012-09-15 00:20:02 +0000209 // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and
210 // ProcResourceDefs.
Joel Jones80372332017-06-28 00:06:40 +0000211 DEBUG(dbgs() << "\n+++ RESOURCE DEFINITIONS (collectProcResources) +++\n");
Andrew Trick1e46d482012-09-15 00:20:02 +0000212 collectProcResources();
Matthias Braun17cb5792016-03-01 20:03:21 +0000213
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000214 // Collect optional processor description.
215 collectOptionalProcessorInfo();
216
217 checkCompleteness();
218}
219
220void CodeGenSchedModels::collectRetireControlUnits() {
221 RecVec Units = Records.getAllDerivedDefinitions("RetireControlUnit");
222
223 for (Record *RCU : Units) {
224 CodeGenProcModel &PM = getProcModel(RCU->getValueAsDef("SchedModel"));
225 if (PM.RetireControlUnit) {
226 PrintError(RCU->getLoc(),
227 "Expected a single RetireControlUnit definition");
228 PrintNote(PM.RetireControlUnit->getLoc(),
229 "Previous definition of RetireControlUnit was here");
230 }
231 PM.RetireControlUnit = RCU;
232 }
233}
234
235/// Collect optional processor information.
236void CodeGenSchedModels::collectOptionalProcessorInfo() {
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000237 // Find register file definitions for each processor.
238 collectRegisterFiles();
239
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000240 // Collect processor RetireControlUnit descriptors if available.
241 collectRetireControlUnits();
Clement Courbetb4493792018-04-10 08:16:37 +0000242
243 // Find pfm counter definitions for each processor.
244 collectPfmCounters();
245
246 checkCompleteness();
Andrew Trick87255e32012-07-07 04:00:00 +0000247}
248
Andrew Trick76686492012-09-15 00:19:57 +0000249/// Gather all processor models.
250void CodeGenSchedModels::collectProcModels() {
251 RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor");
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +0000252 llvm::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName());
Andrew Trick87255e32012-07-07 04:00:00 +0000253
Andrew Trick76686492012-09-15 00:19:57 +0000254 // Reserve space because we can. Reallocation would be ok.
255 ProcModels.reserve(ProcRecords.size()+1);
256
257 // Use idx=0 for NoModel/NoItineraries.
258 Record *NoModelDef = Records.getDef("NoSchedModel");
259 Record *NoItinsDef = Records.getDef("NoItineraries");
Benjamin Kramerf5e2fc42015-05-29 19:43:39 +0000260 ProcModels.emplace_back(0, "NoSchedModel", NoModelDef, NoItinsDef);
Andrew Trick76686492012-09-15 00:19:57 +0000261 ProcModelMap[NoModelDef] = 0;
262
263 // For each processor, find a unique machine model.
Joel Jones80372332017-06-28 00:06:40 +0000264 DEBUG(dbgs() << "+++ PROCESSOR MODELs (addProcModel) +++\n");
Javed Absar67b042c2017-09-13 10:31:10 +0000265 for (Record *ProcRecord : ProcRecords)
266 addProcModel(ProcRecord);
Andrew Trick76686492012-09-15 00:19:57 +0000267}
268
269/// Get a unique processor model based on the defined MachineModel and
270/// ProcessorItineraries.
271void CodeGenSchedModels::addProcModel(Record *ProcDef) {
272 Record *ModelKey = getModelOrItinDef(ProcDef);
273 if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second)
274 return;
275
276 std::string Name = ModelKey->getName();
277 if (ModelKey->isSubClassOf("SchedMachineModel")) {
278 Record *ItinsDef = ModelKey->getValueAsDef("Itineraries");
Benjamin Kramerf5e2fc42015-05-29 19:43:39 +0000279 ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef);
Andrew Trick76686492012-09-15 00:19:57 +0000280 }
281 else {
282 // An itinerary is defined without a machine model. Infer a new model.
283 if (!ModelKey->getValueAsListOfDefs("IID").empty())
284 Name = Name + "Model";
Benjamin Kramerf5e2fc42015-05-29 19:43:39 +0000285 ProcModels.emplace_back(ProcModels.size(), Name,
286 ProcDef->getValueAsDef("SchedModel"), ModelKey);
Andrew Trick76686492012-09-15 00:19:57 +0000287 }
288 DEBUG(ProcModels.back().dump());
289}
290
291// Recursively find all reachable SchedReadWrite records.
292static void scanSchedRW(Record *RWDef, RecVec &RWDefs,
293 SmallPtrSet<Record*, 16> &RWSet) {
David Blaikie70573dc2014-11-19 07:49:26 +0000294 if (!RWSet.insert(RWDef).second)
Andrew Trick76686492012-09-15 00:19:57 +0000295 return;
296 RWDefs.push_back(RWDef);
Javed Absar67b042c2017-09-13 10:31:10 +0000297 // Reads don't currently have sequence records, but it can be added later.
Andrew Trick76686492012-09-15 00:19:57 +0000298 if (RWDef->isSubClassOf("WriteSequence")) {
299 RecVec Seq = RWDef->getValueAsListOfDefs("Writes");
Javed Absar67b042c2017-09-13 10:31:10 +0000300 for (Record *WSRec : Seq)
301 scanSchedRW(WSRec, RWDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000302 }
303 else if (RWDef->isSubClassOf("SchedVariant")) {
304 // Visit each variant (guarded by a different predicate).
305 RecVec Vars = RWDef->getValueAsListOfDefs("Variants");
Javed Absar67b042c2017-09-13 10:31:10 +0000306 for (Record *Variant : Vars) {
Andrew Trick76686492012-09-15 00:19:57 +0000307 // Visit each RW in the sequence selected by the current variant.
Javed Absar67b042c2017-09-13 10:31:10 +0000308 RecVec Selected = Variant->getValueAsListOfDefs("Selected");
309 for (Record *SelDef : Selected)
310 scanSchedRW(SelDef, RWDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000311 }
312 }
313}
314
315// Collect and sort all SchedReadWrites reachable via tablegen records.
316// More may be inferred later when inferring new SchedClasses from variants.
317void CodeGenSchedModels::collectSchedRW() {
318 // Reserve idx=0 for invalid writes/reads.
319 SchedWrites.resize(1);
320 SchedReads.resize(1);
321
322 SmallPtrSet<Record*, 16> RWSet;
323
324 // Find all SchedReadWrites referenced by instruction defs.
325 RecVec SWDefs, SRDefs;
Craig Topper8cc904d2016-01-17 20:38:18 +0000326 for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
Craig Topper8a417c12014-12-09 08:05:51 +0000327 Record *SchedDef = Inst->TheDef;
Jakob Stoklund Olesena4a361d2013-03-15 22:51:13 +0000328 if (SchedDef->isValueUnset("SchedRW"))
Andrew Trick76686492012-09-15 00:19:57 +0000329 continue;
330 RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW");
Javed Absar67b042c2017-09-13 10:31:10 +0000331 for (Record *RW : RWs) {
332 if (RW->isSubClassOf("SchedWrite"))
333 scanSchedRW(RW, SWDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000334 else {
Javed Absar67b042c2017-09-13 10:31:10 +0000335 assert(RW->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
336 scanSchedRW(RW, SRDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000337 }
338 }
339 }
340 // Find all ReadWrites referenced by InstRW.
341 RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
Javed Absar67b042c2017-09-13 10:31:10 +0000342 for (Record *InstRWDef : InstRWDefs) {
Andrew Trick76686492012-09-15 00:19:57 +0000343 // For all OperandReadWrites.
Javed Absar67b042c2017-09-13 10:31:10 +0000344 RecVec RWDefs = InstRWDef->getValueAsListOfDefs("OperandReadWrites");
345 for (Record *RWDef : RWDefs) {
346 if (RWDef->isSubClassOf("SchedWrite"))
347 scanSchedRW(RWDef, SWDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000348 else {
Javed Absar67b042c2017-09-13 10:31:10 +0000349 assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
350 scanSchedRW(RWDef, SRDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000351 }
352 }
353 }
354 // Find all ReadWrites referenced by ItinRW.
355 RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
Javed Absar67b042c2017-09-13 10:31:10 +0000356 for (Record *ItinRWDef : ItinRWDefs) {
Andrew Trick76686492012-09-15 00:19:57 +0000357 // For all OperandReadWrites.
Javed Absar67b042c2017-09-13 10:31:10 +0000358 RecVec RWDefs = ItinRWDef->getValueAsListOfDefs("OperandReadWrites");
359 for (Record *RWDef : RWDefs) {
360 if (RWDef->isSubClassOf("SchedWrite"))
361 scanSchedRW(RWDef, SWDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000362 else {
Javed Absar67b042c2017-09-13 10:31:10 +0000363 assert(RWDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
364 scanSchedRW(RWDef, SRDefs, RWSet);
Andrew Trick76686492012-09-15 00:19:57 +0000365 }
366 }
367 }
Andrew Trick9257b8f2012-09-22 02:24:21 +0000368 // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted
369 // for the loop below that initializes Alias vectors.
370 RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias");
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +0000371 llvm::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord());
Javed Absar67b042c2017-09-13 10:31:10 +0000372 for (Record *ADef : AliasDefs) {
373 Record *MatchDef = ADef->getValueAsDef("MatchRW");
374 Record *AliasDef = ADef->getValueAsDef("AliasRW");
Andrew Trick9257b8f2012-09-22 02:24:21 +0000375 if (MatchDef->isSubClassOf("SchedWrite")) {
376 if (!AliasDef->isSubClassOf("SchedWrite"))
Javed Absar67b042c2017-09-13 10:31:10 +0000377 PrintFatalError(ADef->getLoc(), "SchedWrite Alias must be SchedWrite");
Andrew Trick9257b8f2012-09-22 02:24:21 +0000378 scanSchedRW(AliasDef, SWDefs, RWSet);
379 }
380 else {
381 assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
382 if (!AliasDef->isSubClassOf("SchedRead"))
Javed Absar67b042c2017-09-13 10:31:10 +0000383 PrintFatalError(ADef->getLoc(), "SchedRead Alias must be SchedRead");
Andrew Trick9257b8f2012-09-22 02:24:21 +0000384 scanSchedRW(AliasDef, SRDefs, RWSet);
385 }
386 }
Andrew Trick76686492012-09-15 00:19:57 +0000387 // Sort and add the SchedReadWrites directly referenced by instructions or
388 // itinerary resources. Index reads and writes in separate domains.
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +0000389 llvm::sort(SWDefs.begin(), SWDefs.end(), LessRecord());
Javed Absar67b042c2017-09-13 10:31:10 +0000390 for (Record *SWDef : SWDefs) {
391 assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite");
392 SchedWrites.emplace_back(SchedWrites.size(), SWDef);
Andrew Trick76686492012-09-15 00:19:57 +0000393 }
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +0000394 llvm::sort(SRDefs.begin(), SRDefs.end(), LessRecord());
Javed Absar67b042c2017-09-13 10:31:10 +0000395 for (Record *SRDef : SRDefs) {
396 assert(!getSchedRWIdx(SRDef, /*IsRead-*/true) && "duplicate SchedWrite");
397 SchedReads.emplace_back(SchedReads.size(), SRDef);
Andrew Trick76686492012-09-15 00:19:57 +0000398 }
399 // Initialize WriteSequence vectors.
Javed Absar67b042c2017-09-13 10:31:10 +0000400 for (CodeGenSchedRW &CGRW : SchedWrites) {
401 if (!CGRW.IsSequence)
Andrew Trick76686492012-09-15 00:19:57 +0000402 continue;
Javed Absar67b042c2017-09-13 10:31:10 +0000403 findRWs(CGRW.TheDef->getValueAsListOfDefs("Writes"), CGRW.Sequence,
Andrew Trick76686492012-09-15 00:19:57 +0000404 /*IsRead=*/false);
405 }
Andrew Trick9257b8f2012-09-22 02:24:21 +0000406 // Initialize Aliases vectors.
Javed Absar67b042c2017-09-13 10:31:10 +0000407 for (Record *ADef : AliasDefs) {
408 Record *AliasDef = ADef->getValueAsDef("AliasRW");
Andrew Trick9257b8f2012-09-22 02:24:21 +0000409 getSchedRW(AliasDef).IsAlias = true;
Javed Absar67b042c2017-09-13 10:31:10 +0000410 Record *MatchDef = ADef->getValueAsDef("MatchRW");
Andrew Trick9257b8f2012-09-22 02:24:21 +0000411 CodeGenSchedRW &RW = getSchedRW(MatchDef);
412 if (RW.IsAlias)
Javed Absar67b042c2017-09-13 10:31:10 +0000413 PrintFatalError(ADef->getLoc(), "Cannot Alias an Alias");
414 RW.Aliases.push_back(ADef);
Andrew Trick9257b8f2012-09-22 02:24:21 +0000415 }
Andrew Trick76686492012-09-15 00:19:57 +0000416 DEBUG(
Joel Jones80372332017-06-28 00:06:40 +0000417 dbgs() << "\n+++ SCHED READS and WRITES (collectSchedRW) +++\n";
Andrew Trick76686492012-09-15 00:19:57 +0000418 for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) {
419 dbgs() << WIdx << ": ";
420 SchedWrites[WIdx].dump();
421 dbgs() << '\n';
422 }
423 for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; ++RIdx) {
424 dbgs() << RIdx << ": ";
425 SchedReads[RIdx].dump();
426 dbgs() << '\n';
427 }
428 RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite");
Javed Absar67b042c2017-09-13 10:31:10 +0000429 for (Record *RWDef : RWDefs) {
430 if (!getSchedRWIdx(RWDef, RWDef->isSubClassOf("SchedRead"))) {
Simon Pilgrim494d0752018-03-24 21:22:32 +0000431 StringRef Name = RWDef->getName();
Andrew Trick76686492012-09-15 00:19:57 +0000432 if (Name != "NoWrite" && Name != "ReadDefault")
Simon Pilgrim494d0752018-03-24 21:22:32 +0000433 dbgs() << "Unused SchedReadWrite " << Name << '\n';
Andrew Trick76686492012-09-15 00:19:57 +0000434 }
435 });
436}
437
438/// Compute a SchedWrite name from a sequence of writes.
Benjamin Kramere1761952015-10-24 12:46:49 +0000439std::string CodeGenSchedModels::genRWName(ArrayRef<unsigned> Seq, bool IsRead) {
Andrew Trick76686492012-09-15 00:19:57 +0000440 std::string Name("(");
Benjamin Kramere1761952015-10-24 12:46:49 +0000441 for (auto I = Seq.begin(), E = Seq.end(); I != E; ++I) {
Andrew Trick76686492012-09-15 00:19:57 +0000442 if (I != Seq.begin())
443 Name += '_';
444 Name += getSchedRW(*I, IsRead).Name;
445 }
446 Name += ')';
447 return Name;
448}
449
Craig Toppere2611842018-03-21 05:13:04 +0000450unsigned CodeGenSchedModels::getSchedRWIdx(Record *Def, bool IsRead) const {
Andrew Trick76686492012-09-15 00:19:57 +0000451 const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
Craig Toppere2611842018-03-21 05:13:04 +0000452 for (std::vector<CodeGenSchedRW>::const_iterator I = RWVec.begin(),
Andrew Trick76686492012-09-15 00:19:57 +0000453 E = RWVec.end(); I != E; ++I) {
454 if (I->TheDef == Def)
455 return I - RWVec.begin();
456 }
457 return 0;
458}
459
Andrew Trickcfe222c2012-09-19 04:43:19 +0000460bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const {
Javed Absar67b042c2017-09-13 10:31:10 +0000461 for (const CodeGenSchedRW &Read : SchedReads) {
462 Record *ReadDef = Read.TheDef;
Andrew Trickcfe222c2012-09-19 04:43:19 +0000463 if (!ReadDef || !ReadDef->isSubClassOf("ProcReadAdvance"))
464 continue;
465
466 RecVec ValidWrites = ReadDef->getValueAsListOfDefs("ValidWrites");
David Majnemer0d955d02016-08-11 22:21:41 +0000467 if (is_contained(ValidWrites, WriteDef)) {
Andrew Trickcfe222c2012-09-19 04:43:19 +0000468 return true;
469 }
470 }
471 return false;
472}
473
Craig Topper6f2cc9b2018-03-21 05:13:01 +0000474static void splitSchedReadWrites(const RecVec &RWDefs,
475 RecVec &WriteDefs, RecVec &ReadDefs) {
Javed Absar67b042c2017-09-13 10:31:10 +0000476 for (Record *RWDef : RWDefs) {
477 if (RWDef->isSubClassOf("SchedWrite"))
478 WriteDefs.push_back(RWDef);
Andrew Trick76686492012-09-15 00:19:57 +0000479 else {
Javed Absar67b042c2017-09-13 10:31:10 +0000480 assert(RWDef->isSubClassOf("SchedRead") && "unknown SchedReadWrite");
481 ReadDefs.push_back(RWDef);
Andrew Trick76686492012-09-15 00:19:57 +0000482 }
483 }
484}
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +0000485
Andrew Trick76686492012-09-15 00:19:57 +0000486// Split the SchedReadWrites defs and call findRWs for each list.
487void CodeGenSchedModels::findRWs(const RecVec &RWDefs,
488 IdxVec &Writes, IdxVec &Reads) const {
489 RecVec WriteDefs;
490 RecVec ReadDefs;
491 splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs);
492 findRWs(WriteDefs, Writes, false);
493 findRWs(ReadDefs, Reads, true);
494}
495
496// Call getSchedRWIdx for all elements in a sequence of SchedRW defs.
497void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs,
498 bool IsRead) const {
Javed Absar67b042c2017-09-13 10:31:10 +0000499 for (Record *RWDef : RWDefs) {
500 unsigned Idx = getSchedRWIdx(RWDef, IsRead);
Andrew Trick76686492012-09-15 00:19:57 +0000501 assert(Idx && "failed to collect SchedReadWrite");
502 RWs.push_back(Idx);
503 }
504}
505
Andrew Trick33401e82012-09-15 00:19:59 +0000506void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq,
507 bool IsRead) const {
508 const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);
509 if (!SchedRW.IsSequence) {
510 RWSeq.push_back(RWIdx);
511 return;
512 }
513 int Repeat =
514 SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1;
515 for (int i = 0; i < Repeat; ++i) {
Javed Absar67b042c2017-09-13 10:31:10 +0000516 for (unsigned I : SchedRW.Sequence) {
517 expandRWSequence(I, RWSeq, IsRead);
Andrew Trick33401e82012-09-15 00:19:59 +0000518 }
519 }
520}
521
Andrew Trickda984b12012-10-03 23:06:28 +0000522// Expand a SchedWrite as a sequence following any aliases that coincide with
523// the given processor model.
524void CodeGenSchedModels::expandRWSeqForProc(
525 unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
526 const CodeGenProcModel &ProcModel) const {
527
528 const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead);
Craig Topper24064772014-04-15 07:20:03 +0000529 Record *AliasDef = nullptr;
Andrew Trickda984b12012-10-03 23:06:28 +0000530 for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end();
531 AI != AE; ++AI) {
532 const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW"));
533 if ((*AI)->getValueInit("SchedModel")->isComplete()) {
534 Record *ModelDef = (*AI)->getValueAsDef("SchedModel");
535 if (&getProcModel(ModelDef) != &ProcModel)
536 continue;
537 }
538 if (AliasDef)
Joerg Sonnenberger635debe2012-10-25 20:33:17 +0000539 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
540 "defined for processor " + ProcModel.ModelName +
541 " Ensure only one SchedAlias exists per RW.");
Andrew Trickda984b12012-10-03 23:06:28 +0000542 AliasDef = AliasRW.TheDef;
543 }
544 if (AliasDef) {
545 expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead),
546 RWSeq, IsRead,ProcModel);
547 return;
548 }
549 if (!SchedWrite.IsSequence) {
550 RWSeq.push_back(RWIdx);
551 return;
552 }
553 int Repeat =
554 SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1;
555 for (int i = 0; i < Repeat; ++i) {
Javed Absar67b042c2017-09-13 10:31:10 +0000556 for (unsigned I : SchedWrite.Sequence) {
557 expandRWSeqForProc(I, RWSeq, IsRead, ProcModel);
Andrew Trickda984b12012-10-03 23:06:28 +0000558 }
559 }
560}
561
Andrew Trick33401e82012-09-15 00:19:59 +0000562// Find the existing SchedWrite that models this sequence of writes.
Benjamin Kramere1761952015-10-24 12:46:49 +0000563unsigned CodeGenSchedModels::findRWForSequence(ArrayRef<unsigned> Seq,
Andrew Trick33401e82012-09-15 00:19:59 +0000564 bool IsRead) {
565 std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
566
567 for (std::vector<CodeGenSchedRW>::iterator I = RWVec.begin(), E = RWVec.end();
568 I != E; ++I) {
Benjamin Kramere1761952015-10-24 12:46:49 +0000569 if (makeArrayRef(I->Sequence) == Seq)
Andrew Trick33401e82012-09-15 00:19:59 +0000570 return I - RWVec.begin();
571 }
572 // Index zero reserved for invalid RW.
573 return 0;
574}
575
576/// Add this ReadWrite if it doesn't already exist.
577unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq,
578 bool IsRead) {
579 assert(!Seq.empty() && "cannot insert empty sequence");
580 if (Seq.size() == 1)
581 return Seq.back();
582
583 unsigned Idx = findRWForSequence(Seq, IsRead);
584 if (Idx)
585 return Idx;
586
Andrew Trickda984b12012-10-03 23:06:28 +0000587 unsigned RWIdx = IsRead ? SchedReads.size() : SchedWrites.size();
588 CodeGenSchedRW SchedRW(RWIdx, IsRead, Seq, genRWName(Seq, IsRead));
589 if (IsRead)
Andrew Trick33401e82012-09-15 00:19:59 +0000590 SchedReads.push_back(SchedRW);
Andrew Trickda984b12012-10-03 23:06:28 +0000591 else
592 SchedWrites.push_back(SchedRW);
593 return RWIdx;
Andrew Trick33401e82012-09-15 00:19:59 +0000594}
595
Andrew Trick76686492012-09-15 00:19:57 +0000596/// Visit all the instruction definitions for this target to gather and
597/// enumerate the itinerary classes. These are the explicitly specified
598/// SchedClasses. More SchedClasses may be inferred.
599void CodeGenSchedModels::collectSchedClasses() {
600
601 // NoItinerary is always the first class at Idx=0
Craig Topper281a19c2018-03-22 06:15:08 +0000602 assert(SchedClasses.empty() && "Expected empty sched class");
603 SchedClasses.emplace_back(0, "NoInstrModel",
604 Records.getDef("NoItinerary"));
Andrew Trick76686492012-09-15 00:19:57 +0000605 SchedClasses.back().ProcIndices.push_back(0);
Andrew Trick87255e32012-07-07 04:00:00 +0000606
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000607 // Create a SchedClass for each unique combination of itinerary class and
608 // SchedRW list.
Craig Topper8cc904d2016-01-17 20:38:18 +0000609 for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
Craig Topper8a417c12014-12-09 08:05:51 +0000610 Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary");
Andrew Trick76686492012-09-15 00:19:57 +0000611 IdxVec Writes, Reads;
Craig Topper8a417c12014-12-09 08:05:51 +0000612 if (!Inst->TheDef->isValueUnset("SchedRW"))
613 findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000614
Andrew Trick76686492012-09-15 00:19:57 +0000615 // ProcIdx == 0 indicates the class applies to all processors.
Craig Topper281a19c2018-03-22 06:15:08 +0000616 unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/{0});
Craig Topper8a417c12014-12-09 08:05:51 +0000617 InstrClassMap[Inst->TheDef] = SCIdx;
Andrew Trick76686492012-09-15 00:19:57 +0000618 }
Andrew Trick9257b8f2012-09-22 02:24:21 +0000619 // Create classes for InstRW defs.
Andrew Trick76686492012-09-15 00:19:57 +0000620 RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +0000621 llvm::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord());
Joel Jones80372332017-06-28 00:06:40 +0000622 DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n");
Javed Absar67b042c2017-09-13 10:31:10 +0000623 for (Record *RWDef : InstRWDefs)
624 createInstRWClass(RWDef);
Andrew Trick87255e32012-07-07 04:00:00 +0000625
Andrew Trick76686492012-09-15 00:19:57 +0000626 NumInstrSchedClasses = SchedClasses.size();
Andrew Trick87255e32012-07-07 04:00:00 +0000627
Andrew Trick76686492012-09-15 00:19:57 +0000628 bool EnableDump = false;
629 DEBUG(EnableDump = true);
630 if (!EnableDump)
Andrew Trick87255e32012-07-07 04:00:00 +0000631 return;
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000632
Joel Jones80372332017-06-28 00:06:40 +0000633 dbgs() << "\n+++ ITINERARIES and/or MACHINE MODELS (collectSchedClasses) +++\n";
Craig Topper8cc904d2016-01-17 20:38:18 +0000634 for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
Craig Topperbcd3c372017-05-31 21:12:46 +0000635 StringRef InstName = Inst->TheDef->getName();
Simon Pilgrim949437e2018-03-21 18:09:34 +0000636 unsigned SCIdx = getSchedClassIdx(*Inst);
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000637 if (!SCIdx) {
Matthias Braun8e0a7342016-03-01 20:03:11 +0000638 if (!Inst->hasNoSchedulingInfo)
639 dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n';
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000640 continue;
641 }
642 CodeGenSchedClass &SC = getSchedClass(SCIdx);
643 if (SC.ProcIndices[0] != 0)
Craig Topper8a417c12014-12-09 08:05:51 +0000644 PrintFatalError(Inst->TheDef->getLoc(), "Instruction's sched class "
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000645 "must not be subtarget specific.");
646
647 IdxVec ProcIndices;
648 if (SC.ItinClassDef->getName() != "NoItinerary") {
649 ProcIndices.push_back(0);
650 dbgs() << "Itinerary for " << InstName << ": "
651 << SC.ItinClassDef->getName() << '\n';
652 }
653 if (!SC.Writes.empty()) {
654 ProcIndices.push_back(0);
655 dbgs() << "SchedRW machine model for " << InstName;
656 for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; ++WI)
657 dbgs() << " " << SchedWrites[*WI].Name;
658 for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI)
659 dbgs() << " " << SchedReads[*RI].Name;
660 dbgs() << '\n';
661 }
662 const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
Javed Absar67b042c2017-09-13 10:31:10 +0000663 for (Record *RWDef : RWDefs) {
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000664 const CodeGenProcModel &ProcModel =
Javed Absar67b042c2017-09-13 10:31:10 +0000665 getProcModel(RWDef->getValueAsDef("SchedModel"));
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000666 ProcIndices.push_back(ProcModel.Index);
667 dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName;
Andrew Trick76686492012-09-15 00:19:57 +0000668 IdxVec Writes;
669 IdxVec Reads;
Javed Absar67b042c2017-09-13 10:31:10 +0000670 findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000671 Writes, Reads);
Javed Absar67b042c2017-09-13 10:31:10 +0000672 for (unsigned WIdx : Writes)
673 dbgs() << " " << SchedWrites[WIdx].Name;
674 for (unsigned RIdx : Reads)
675 dbgs() << " " << SchedReads[RIdx].Name;
Andrew Trick76686492012-09-15 00:19:57 +0000676 dbgs() << '\n';
677 }
Andrew Trickf9df92c92016-10-18 04:17:44 +0000678 // If ProcIndices contains zero, the class applies to all processors.
679 if (!std::count(ProcIndices.begin(), ProcIndices.end(), 0)) {
Javed Absar21c75912017-10-09 16:21:25 +0000680 for (const CodeGenProcModel &PM : ProcModels) {
Javed Absarfc500042017-10-05 13:27:43 +0000681 if (!std::count(ProcIndices.begin(), ProcIndices.end(), PM.Index))
Andrew Trickf9df92c92016-10-18 04:17:44 +0000682 dbgs() << "No machine model for " << Inst->TheDef->getName()
Javed Absarfc500042017-10-05 13:27:43 +0000683 << " on processor " << PM.ModelName << '\n';
Andrew Trickf9df92c92016-10-18 04:17:44 +0000684 }
Andrew Trick87255e32012-07-07 04:00:00 +0000685 }
686 }
Andrew Trick76686492012-09-15 00:19:57 +0000687}
688
Andrew Trick76686492012-09-15 00:19:57 +0000689/// Find an SchedClass that has been inferred from a per-operand list of
690/// SchedWrites and SchedReads.
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000691unsigned CodeGenSchedModels::findSchedClassIdx(Record *ItinClassDef,
Benjamin Kramere1761952015-10-24 12:46:49 +0000692 ArrayRef<unsigned> Writes,
693 ArrayRef<unsigned> Reads) const {
Simon Pilgrim4cca3b12018-03-21 17:57:21 +0000694 for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I)
695 if (I->isKeyEqual(ItinClassDef, Writes, Reads))
Andrew Trick76686492012-09-15 00:19:57 +0000696 return I - schedClassBegin();
Andrew Trick76686492012-09-15 00:19:57 +0000697 return 0;
698}
Andrew Trick87255e32012-07-07 04:00:00 +0000699
Andrew Trick76686492012-09-15 00:19:57 +0000700// Get the SchedClass index for an instruction.
701unsigned CodeGenSchedModels::getSchedClassIdx(
702 const CodeGenInstruction &Inst) const {
Andrew Trick87255e32012-07-07 04:00:00 +0000703
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000704 return InstrClassMap.lookup(Inst.TheDef);
Andrew Trick76686492012-09-15 00:19:57 +0000705}
706
Benjamin Kramere1761952015-10-24 12:46:49 +0000707std::string
708CodeGenSchedModels::createSchedClassName(Record *ItinClassDef,
709 ArrayRef<unsigned> OperWrites,
710 ArrayRef<unsigned> OperReads) {
Andrew Trick76686492012-09-15 00:19:57 +0000711
712 std::string Name;
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000713 if (ItinClassDef && ItinClassDef->getName() != "NoItinerary")
714 Name = ItinClassDef->getName();
Benjamin Kramere1761952015-10-24 12:46:49 +0000715 for (unsigned Idx : OperWrites) {
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000716 if (!Name.empty())
Andrew Trick76686492012-09-15 00:19:57 +0000717 Name += '_';
Benjamin Kramere1761952015-10-24 12:46:49 +0000718 Name += SchedWrites[Idx].Name;
Andrew Trick76686492012-09-15 00:19:57 +0000719 }
Benjamin Kramere1761952015-10-24 12:46:49 +0000720 for (unsigned Idx : OperReads) {
Andrew Trick76686492012-09-15 00:19:57 +0000721 Name += '_';
Benjamin Kramere1761952015-10-24 12:46:49 +0000722 Name += SchedReads[Idx].Name;
Andrew Trick76686492012-09-15 00:19:57 +0000723 }
724 return Name;
725}
726
727std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) {
728
729 std::string Name;
730 for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) {
731 if (I != InstDefs.begin())
732 Name += '_';
733 Name += (*I)->getName();
734 }
735 return Name;
736}
737
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000738/// Add an inferred sched class from an itinerary class and per-operand list of
739/// SchedWrites and SchedReads. ProcIndices contains the set of IDs of
740/// processors that may utilize this class.
741unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef,
Benjamin Kramere1761952015-10-24 12:46:49 +0000742 ArrayRef<unsigned> OperWrites,
743 ArrayRef<unsigned> OperReads,
744 ArrayRef<unsigned> ProcIndices) {
Andrew Trick76686492012-09-15 00:19:57 +0000745 assert(!ProcIndices.empty() && "expect at least one ProcIdx");
746
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000747 unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads);
748 if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) {
Andrew Trick76686492012-09-15 00:19:57 +0000749 IdxVec PI;
750 std::set_union(SchedClasses[Idx].ProcIndices.begin(),
751 SchedClasses[Idx].ProcIndices.end(),
752 ProcIndices.begin(), ProcIndices.end(),
753 std::back_inserter(PI));
Craig Topper59d13772018-03-24 22:58:00 +0000754 SchedClasses[Idx].ProcIndices = std::move(PI);
Andrew Trick76686492012-09-15 00:19:57 +0000755 return Idx;
756 }
757 Idx = SchedClasses.size();
Craig Topper281a19c2018-03-22 06:15:08 +0000758 SchedClasses.emplace_back(Idx,
759 createSchedClassName(ItinClassDef, OperWrites,
760 OperReads),
761 ItinClassDef);
Andrew Trick76686492012-09-15 00:19:57 +0000762 CodeGenSchedClass &SC = SchedClasses.back();
Andrew Trick76686492012-09-15 00:19:57 +0000763 SC.Writes = OperWrites;
764 SC.Reads = OperReads;
765 SC.ProcIndices = ProcIndices;
766
767 return Idx;
768}
769
770// Create classes for each set of opcodes that are in the same InstReadWrite
771// definition across all processors.
772void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
773 // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that
774 // intersects with an existing class via a previous InstRWDef. Instrs that do
775 // not intersect with an existing class refer back to their former class as
776 // determined from ItinDef or SchedRW.
Craig Topperf19eacf2018-03-21 02:48:34 +0000777 SmallMapVector<unsigned, SmallVector<Record *, 8>, 4> ClassInstrs;
Andrew Trick76686492012-09-15 00:19:57 +0000778 // Sort Instrs into sets.
Andrew Trick9e1deb62012-10-03 23:06:32 +0000779 const RecVec *InstDefs = Sets.expand(InstRWDef);
780 if (InstDefs->empty())
Joerg Sonnenberger635debe2012-10-25 20:33:17 +0000781 PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes");
Andrew Trick9e1deb62012-10-03 23:06:32 +0000782
Craig Topper93dd77d2018-03-18 08:38:03 +0000783 for (Record *InstDef : *InstDefs) {
Javed Absarfc500042017-10-05 13:27:43 +0000784 InstClassMapTy::const_iterator Pos = InstrClassMap.find(InstDef);
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000785 if (Pos == InstrClassMap.end())
Javed Absarfc500042017-10-05 13:27:43 +0000786 PrintFatalError(InstDef->getLoc(), "No sched class for instruction.");
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000787 unsigned SCIdx = Pos->second;
Craig Topperf19eacf2018-03-21 02:48:34 +0000788 ClassInstrs[SCIdx].push_back(InstDef);
Andrew Trick76686492012-09-15 00:19:57 +0000789 }
790 // For each set of Instrs, create a new class if necessary, and map or remap
791 // the Instrs to it.
Craig Topperf19eacf2018-03-21 02:48:34 +0000792 for (auto &Entry : ClassInstrs) {
793 unsigned OldSCIdx = Entry.first;
794 ArrayRef<Record*> InstDefs = Entry.second;
Andrew Trick76686492012-09-15 00:19:57 +0000795 // If the all instrs in the current class are accounted for, then leave
796 // them mapped to their old class.
Andrew Trick78a08512013-06-05 06:55:20 +0000797 if (OldSCIdx) {
798 const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs;
799 if (!RWDefs.empty()) {
800 const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]);
Craig Topper06d78372018-03-21 19:30:30 +0000801 unsigned OrigNumInstrs =
802 count_if(*OrigInstDefs, [&](Record *OIDef) {
803 return InstrClassMap[OIDef] == OldSCIdx;
804 });
Andrew Trick78a08512013-06-05 06:55:20 +0000805 if (OrigNumInstrs == InstDefs.size()) {
806 assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
807 "expected a generic SchedClass");
Craig Toppere1d6a4d2018-03-18 19:56:15 +0000808 Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel");
809 // Make sure we didn't already have a InstRW containing this
810 // instruction on this model.
811 for (Record *RWD : RWDefs) {
812 if (RWD->getValueAsDef("SchedModel") == RWModelDef &&
813 RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) {
814 for (Record *Inst : InstDefs) {
815 PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " +
816 Inst->getName() + " also matches " +
817 RWD->getValue("Instrs")->getValue()->getAsString());
818 }
819 }
820 }
Andrew Trick78a08512013-06-05 06:55:20 +0000821 DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":"
822 << SchedClasses[OldSCIdx].Name << " on "
Craig Toppere1d6a4d2018-03-18 19:56:15 +0000823 << RWModelDef->getName() << "\n");
Andrew Trick78a08512013-06-05 06:55:20 +0000824 SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef);
825 continue;
826 }
827 }
Andrew Trick76686492012-09-15 00:19:57 +0000828 }
829 unsigned SCIdx = SchedClasses.size();
Craig Topper281a19c2018-03-22 06:15:08 +0000830 SchedClasses.emplace_back(SCIdx, createSchedClassName(InstDefs), nullptr);
Andrew Trick76686492012-09-15 00:19:57 +0000831 CodeGenSchedClass &SC = SchedClasses.back();
Andrew Trick78a08512013-06-05 06:55:20 +0000832 DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on "
833 << InstRWDef->getValueAsDef("SchedModel")->getName() << "\n");
834
Andrew Trick76686492012-09-15 00:19:57 +0000835 // Preserve ItinDef and Writes/Reads for processors without an InstRW entry.
836 SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef;
837 SC.Writes = SchedClasses[OldSCIdx].Writes;
838 SC.Reads = SchedClasses[OldSCIdx].Reads;
839 SC.ProcIndices.push_back(0);
Craig Topper989d94d2018-03-21 19:52:13 +0000840 // If we had an old class, copy it's InstRWs to this new class.
841 if (OldSCIdx) {
842 Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel");
843 for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) {
844 if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) {
845 for (Record *InstDef : InstDefs) {
Craig Topper9fbbe5d2018-03-21 19:30:31 +0000846 PrintFatalError(OldRWDef->getLoc(), "Overlapping InstRW def " +
847 InstDef->getName() + " also matches " +
848 OldRWDef->getValue("Instrs")->getValue()->getAsString());
Andrew Trick9e1deb62012-10-03 23:06:32 +0000849 }
Andrew Trick9e1deb62012-10-03 23:06:32 +0000850 }
Craig Topper989d94d2018-03-21 19:52:13 +0000851 assert(OldRWDef != InstRWDef &&
852 "SchedClass has duplicate InstRW def");
853 SC.InstRWs.push_back(OldRWDef);
Andrew Trick76686492012-09-15 00:19:57 +0000854 }
Andrew Trick76686492012-09-15 00:19:57 +0000855 }
Craig Topper989d94d2018-03-21 19:52:13 +0000856 // Map each Instr to this new class.
857 for (Record *InstDef : InstDefs)
858 InstrClassMap[InstDef] = SCIdx;
Andrew Trick76686492012-09-15 00:19:57 +0000859 SC.InstRWs.push_back(InstRWDef);
860 }
Andrew Trick87255e32012-07-07 04:00:00 +0000861}
862
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000863// True if collectProcItins found anything.
864bool CodeGenSchedModels::hasItineraries() const {
Javed Absar67b042c2017-09-13 10:31:10 +0000865 for (const CodeGenProcModel &PM : make_range(procModelBegin(),procModelEnd())) {
866 if (PM.hasItineraries())
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000867 return true;
868 }
869 return false;
870}
871
Andrew Trick87255e32012-07-07 04:00:00 +0000872// Gather the processor itineraries.
Andrew Trick76686492012-09-15 00:19:57 +0000873void CodeGenSchedModels::collectProcItins() {
Joel Jones80372332017-06-28 00:06:40 +0000874 DEBUG(dbgs() << "\n+++ PROBLEM ITINERARIES (collectProcItins) +++\n");
Craig Topper8a417c12014-12-09 08:05:51 +0000875 for (CodeGenProcModel &ProcModel : ProcModels) {
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000876 if (!ProcModel.hasItineraries())
Andrew Trick87255e32012-07-07 04:00:00 +0000877 continue;
Andrew Trick76686492012-09-15 00:19:57 +0000878
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000879 RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID");
880 assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect");
881
882 // Populate ItinDefList with Itinerary records.
883 ProcModel.ItinDefList.resize(NumInstrSchedClasses);
Andrew Trick76686492012-09-15 00:19:57 +0000884
885 // Insert each itinerary data record in the correct position within
886 // the processor model's ItinDefList.
Javed Absarfc500042017-10-05 13:27:43 +0000887 for (Record *ItinData : ItinRecords) {
Andrew Trick76686492012-09-15 00:19:57 +0000888 Record *ItinDef = ItinData->getValueAsDef("TheClass");
Andrew Tricke7bac5f2013-03-18 20:42:25 +0000889 bool FoundClass = false;
890 for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();
891 SCI != SCE; ++SCI) {
892 // Multiple SchedClasses may share an itinerary. Update all of them.
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000893 if (SCI->ItinClassDef == ItinDef) {
894 ProcModel.ItinDefList[SCI->Index] = ItinData;
Andrew Tricke7bac5f2013-03-18 20:42:25 +0000895 FoundClass = true;
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000896 }
Andrew Trick76686492012-09-15 00:19:57 +0000897 }
Andrew Tricke7bac5f2013-03-18 20:42:25 +0000898 if (!FoundClass) {
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000899 DEBUG(dbgs() << ProcModel.ItinsDef->getName()
900 << " missing class for itinerary " << ItinDef->getName() << '\n');
901 }
Andrew Trick87255e32012-07-07 04:00:00 +0000902 }
Andrew Trick76686492012-09-15 00:19:57 +0000903 // Check for missing itinerary entries.
904 assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec");
905 DEBUG(
906 for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) {
907 if (!ProcModel.ItinDefList[i])
908 dbgs() << ProcModel.ItinsDef->getName()
909 << " missing itinerary for class "
910 << SchedClasses[i].Name << '\n';
911 });
Andrew Trick87255e32012-07-07 04:00:00 +0000912 }
Andrew Trick87255e32012-07-07 04:00:00 +0000913}
Andrew Trick76686492012-09-15 00:19:57 +0000914
915// Gather the read/write types for each itinerary class.
916void CodeGenSchedModels::collectProcItinRW() {
917 RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +0000918 llvm::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord());
Javed Absar21c75912017-10-09 16:21:25 +0000919 for (Record *RWDef : ItinRWDefs) {
Javed Absarf45d0b92017-10-08 17:23:30 +0000920 if (!RWDef->getValueInit("SchedModel")->isComplete())
921 PrintFatalError(RWDef->getLoc(), "SchedModel is undefined");
922 Record *ModelDef = RWDef->getValueAsDef("SchedModel");
Andrew Trick76686492012-09-15 00:19:57 +0000923 ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
924 if (I == ProcModelMap.end()) {
Javed Absarf45d0b92017-10-08 17:23:30 +0000925 PrintFatalError(RWDef->getLoc(), "Undefined SchedMachineModel "
Andrew Trick76686492012-09-15 00:19:57 +0000926 + ModelDef->getName());
927 }
Javed Absarf45d0b92017-10-08 17:23:30 +0000928 ProcModels[I->second].ItinRWDefs.push_back(RWDef);
Andrew Trick76686492012-09-15 00:19:57 +0000929 }
930}
931
Simon Dardis5f95c9a2016-06-24 08:43:27 +0000932// Gather the unsupported features for processor models.
933void CodeGenSchedModels::collectProcUnsupportedFeatures() {
934 for (CodeGenProcModel &ProcModel : ProcModels) {
935 for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) {
936 ProcModel.UnsupportedFeaturesDefs.push_back(Pred);
937 }
938 }
939}
940
Andrew Trick33401e82012-09-15 00:19:59 +0000941/// Infer new classes from existing classes. In the process, this may create new
942/// SchedWrites from sequences of existing SchedWrites.
943void CodeGenSchedModels::inferSchedClasses() {
Joel Jones80372332017-06-28 00:06:40 +0000944 DEBUG(dbgs() << "\n+++ INFERRING SCHED CLASSES (inferSchedClasses) +++\n");
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000945 DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n");
946
Andrew Trick33401e82012-09-15 00:19:59 +0000947 // Visit all existing classes and newly created classes.
948 for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) {
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000949 assert(SchedClasses[Idx].Index == Idx && "bad SCIdx");
950
Andrew Trick33401e82012-09-15 00:19:59 +0000951 if (SchedClasses[Idx].ItinClassDef)
952 inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx);
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000953 if (!SchedClasses[Idx].InstRWs.empty())
Andrew Trick33401e82012-09-15 00:19:59 +0000954 inferFromInstRWs(Idx);
Andrew Trickbf8a28d2013-03-16 18:58:55 +0000955 if (!SchedClasses[Idx].Writes.empty()) {
Andrew Trick33401e82012-09-15 00:19:59 +0000956 inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,
957 Idx, SchedClasses[Idx].ProcIndices);
958 }
959 assert(SchedClasses.size() < (NumInstrSchedClasses*6) &&
960 "too many SchedVariants");
961 }
962}
963
964/// Infer classes from per-processor itinerary resources.
965void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef,
966 unsigned FromClassIdx) {
967 for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {
968 const CodeGenProcModel &PM = ProcModels[PIdx];
969 // For all ItinRW entries.
970 bool HasMatch = false;
971 for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();
972 II != IE; ++II) {
973 RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
974 if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))
975 continue;
976 if (HasMatch)
Joerg Sonnenberger635debe2012-10-25 20:33:17 +0000977 PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "
Andrew Trick33401e82012-09-15 00:19:59 +0000978 + ItinClassDef->getName()
979 + " in ItinResources for " + PM.ModelName);
980 HasMatch = true;
981 IdxVec Writes, Reads;
982 findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
Craig Topper9f3293a2018-03-24 21:57:35 +0000983 inferFromRW(Writes, Reads, FromClassIdx, PIdx);
Andrew Trick33401e82012-09-15 00:19:59 +0000984 }
985 }
986}
987
988/// Infer classes from per-processor InstReadWrite definitions.
989void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) {
Benjamin Kramer58bd79c2013-06-09 15:20:23 +0000990 for (unsigned I = 0, E = SchedClasses[SCIdx].InstRWs.size(); I != E; ++I) {
Benjamin Kramerb22643a2013-06-10 20:19:35 +0000991 assert(SchedClasses[SCIdx].InstRWs.size() == E && "InstrRWs was mutated!");
Benjamin Kramer58bd79c2013-06-09 15:20:23 +0000992 Record *Rec = SchedClasses[SCIdx].InstRWs[I];
993 const RecVec *InstDefs = Sets.expand(Rec);
Andrew Trick9e1deb62012-10-03 23:06:32 +0000994 RecIter II = InstDefs->begin(), IE = InstDefs->end();
Andrew Trick33401e82012-09-15 00:19:59 +0000995 for (; II != IE; ++II) {
996 if (InstrClassMap[*II] == SCIdx)
997 break;
998 }
999 // If this class no longer has any instructions mapped to it, it has become
1000 // irrelevant.
1001 if (II == IE)
1002 continue;
1003 IdxVec Writes, Reads;
Benjamin Kramer58bd79c2013-06-09 15:20:23 +00001004 findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
1005 unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index;
Craig Topper9f3293a2018-03-24 21:57:35 +00001006 inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses.
Andrew Trick33401e82012-09-15 00:19:59 +00001007 }
1008}
1009
1010namespace {
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001011
Andrew Trick9257b8f2012-09-22 02:24:21 +00001012// Helper for substituteVariantOperand.
1013struct TransVariant {
Andrew Trickda984b12012-10-03 23:06:28 +00001014 Record *VarOrSeqDef; // Variant or sequence.
1015 unsigned RWIdx; // Index of this variant or sequence's matched type.
Andrew Trick9257b8f2012-09-22 02:24:21 +00001016 unsigned ProcIdx; // Processor model index or zero for any.
1017 unsigned TransVecIdx; // Index into PredTransitions::TransVec.
1018
1019 TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti):
Andrew Trickda984b12012-10-03 23:06:28 +00001020 VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {}
Andrew Trick9257b8f2012-09-22 02:24:21 +00001021};
1022
Andrew Trick33401e82012-09-15 00:19:59 +00001023// Associate a predicate with the SchedReadWrite that it guards.
1024// RWIdx is the index of the read/write variant.
1025struct PredCheck {
1026 bool IsRead;
1027 unsigned RWIdx;
1028 Record *Predicate;
1029
1030 PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {}
1031};
1032
1033// A Predicate transition is a list of RW sequences guarded by a PredTerm.
1034struct PredTransition {
1035 // A predicate term is a conjunction of PredChecks.
1036 SmallVector<PredCheck, 4> PredTerm;
1037 SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;
1038 SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;
Andrew Trick9257b8f2012-09-22 02:24:21 +00001039 SmallVector<unsigned, 4> ProcIndices;
Andrew Trick33401e82012-09-15 00:19:59 +00001040};
1041
1042// Encapsulate a set of partially constructed transitions.
1043// The results are built by repeated calls to substituteVariants.
1044class PredTransitions {
1045 CodeGenSchedModels &SchedModels;
1046
1047public:
1048 std::vector<PredTransition> TransVec;
1049
1050 PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {}
1051
1052 void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,
1053 bool IsRead, unsigned StartIdx);
1054
1055 void substituteVariants(const PredTransition &Trans);
1056
1057#ifndef NDEBUG
1058 void dump() const;
1059#endif
1060
1061private:
1062 bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term);
Andrew Trickda984b12012-10-03 23:06:28 +00001063 void getIntersectingVariants(
1064 const CodeGenSchedRW &SchedRW, unsigned TransIdx,
1065 std::vector<TransVariant> &IntersectingVariants);
Andrew Trick9257b8f2012-09-22 02:24:21 +00001066 void pushVariant(const TransVariant &VInfo, bool IsRead);
Andrew Trick33401e82012-09-15 00:19:59 +00001067};
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001068
1069} // end anonymous namespace
Andrew Trick33401e82012-09-15 00:19:59 +00001070
1071// Return true if this predicate is mutually exclusive with a PredTerm. This
1072// degenerates into checking if the predicate is mutually exclusive with any
1073// predicate in the Term's conjunction.
1074//
1075// All predicates associated with a given SchedRW are considered mutually
1076// exclusive. This should work even if the conditions expressed by the
1077// predicates are not exclusive because the predicates for a given SchedWrite
1078// are always checked in the order they are defined in the .td file. Later
1079// conditions implicitly negate any prior condition.
1080bool PredTransitions::mutuallyExclusive(Record *PredDef,
1081 ArrayRef<PredCheck> Term) {
Javed Absar21c75912017-10-09 16:21:25 +00001082 for (const PredCheck &PC: Term) {
Javed Absarfc500042017-10-05 13:27:43 +00001083 if (PC.Predicate == PredDef)
Andrew Trick33401e82012-09-15 00:19:59 +00001084 return false;
1085
Javed Absarfc500042017-10-05 13:27:43 +00001086 const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(PC.RWIdx, PC.IsRead);
Andrew Trick33401e82012-09-15 00:19:59 +00001087 assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant");
1088 RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
1089 for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) {
1090 if ((*VI)->getValueAsDef("Predicate") == PredDef)
1091 return true;
1092 }
1093 }
1094 return false;
1095}
1096
Andrew Trickda984b12012-10-03 23:06:28 +00001097static bool hasAliasedVariants(const CodeGenSchedRW &RW,
1098 CodeGenSchedModels &SchedModels) {
1099 if (RW.HasVariants)
1100 return true;
1101
Javed Absar21c75912017-10-09 16:21:25 +00001102 for (Record *Alias : RW.Aliases) {
Andrew Trickda984b12012-10-03 23:06:28 +00001103 const CodeGenSchedRW &AliasRW =
Javed Absarfc500042017-10-05 13:27:43 +00001104 SchedModels.getSchedRW(Alias->getValueAsDef("AliasRW"));
Andrew Trickda984b12012-10-03 23:06:28 +00001105 if (AliasRW.HasVariants)
1106 return true;
1107 if (AliasRW.IsSequence) {
1108 IdxVec ExpandedRWs;
1109 SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead);
1110 for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end();
1111 SI != SE; ++SI) {
1112 if (hasAliasedVariants(SchedModels.getSchedRW(*SI, AliasRW.IsRead),
1113 SchedModels)) {
1114 return true;
1115 }
1116 }
1117 }
1118 }
1119 return false;
1120}
1121
1122static bool hasVariant(ArrayRef<PredTransition> Transitions,
1123 CodeGenSchedModels &SchedModels) {
1124 for (ArrayRef<PredTransition>::iterator
1125 PTI = Transitions.begin(), PTE = Transitions.end();
1126 PTI != PTE; ++PTI) {
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001127 for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
Andrew Trickda984b12012-10-03 23:06:28 +00001128 WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end();
1129 WSI != WSE; ++WSI) {
1130 for (SmallVectorImpl<unsigned>::const_iterator
1131 WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) {
1132 if (hasAliasedVariants(SchedModels.getSchedWrite(*WI), SchedModels))
1133 return true;
1134 }
1135 }
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001136 for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
Andrew Trickda984b12012-10-03 23:06:28 +00001137 RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end();
1138 RSI != RSE; ++RSI) {
1139 for (SmallVectorImpl<unsigned>::const_iterator
1140 RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) {
1141 if (hasAliasedVariants(SchedModels.getSchedRead(*RI), SchedModels))
1142 return true;
1143 }
1144 }
1145 }
1146 return false;
1147}
1148
1149// Populate IntersectingVariants with any variants or aliased sequences of the
1150// given SchedRW whose processor indices and predicates are not mutually
Andrew Trickd97ff1f2013-03-29 19:08:31 +00001151// exclusive with the given transition.
Andrew Trickda984b12012-10-03 23:06:28 +00001152void PredTransitions::getIntersectingVariants(
1153 const CodeGenSchedRW &SchedRW, unsigned TransIdx,
1154 std::vector<TransVariant> &IntersectingVariants) {
1155
Andrew Trickd97ff1f2013-03-29 19:08:31 +00001156 bool GenericRW = false;
1157
Andrew Trickda984b12012-10-03 23:06:28 +00001158 std::vector<TransVariant> Variants;
1159 if (SchedRW.HasVariants) {
1160 unsigned VarProcIdx = 0;
1161 if (SchedRW.TheDef->getValueInit("SchedModel")->isComplete()) {
1162 Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel");
1163 VarProcIdx = SchedModels.getProcModel(ModelDef).Index;
1164 }
1165 // Push each variant. Assign TransVecIdx later.
1166 const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants");
Javed Absarf45d0b92017-10-08 17:23:30 +00001167 for (Record *VarDef : VarDefs)
1168 Variants.push_back(TransVariant(VarDef, SchedRW.Index, VarProcIdx, 0));
Andrew Trickd97ff1f2013-03-29 19:08:31 +00001169 if (VarProcIdx == 0)
1170 GenericRW = true;
Andrew Trickda984b12012-10-03 23:06:28 +00001171 }
1172 for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
1173 AI != AE; ++AI) {
1174 // If either the SchedAlias itself or the SchedReadWrite that it aliases
1175 // to is defined within a processor model, constrain all variants to
1176 // that processor.
1177 unsigned AliasProcIdx = 0;
1178 if ((*AI)->getValueInit("SchedModel")->isComplete()) {
1179 Record *ModelDef = (*AI)->getValueAsDef("SchedModel");
1180 AliasProcIdx = SchedModels.getProcModel(ModelDef).Index;
1181 }
1182 const CodeGenSchedRW &AliasRW =
1183 SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
1184
1185 if (AliasRW.HasVariants) {
1186 const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants");
Javed Absar9003dd72017-10-10 15:58:45 +00001187 for (Record *VD : VarDefs)
1188 Variants.push_back(TransVariant(VD, AliasRW.Index, AliasProcIdx, 0));
Andrew Trickda984b12012-10-03 23:06:28 +00001189 }
1190 if (AliasRW.IsSequence) {
1191 Variants.push_back(
1192 TransVariant(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0));
1193 }
Andrew Trickd97ff1f2013-03-29 19:08:31 +00001194 if (AliasProcIdx == 0)
1195 GenericRW = true;
Andrew Trickda984b12012-10-03 23:06:28 +00001196 }
Javed Absarf45d0b92017-10-08 17:23:30 +00001197 for (TransVariant &Variant : Variants) {
Andrew Trickda984b12012-10-03 23:06:28 +00001198 // Don't expand variants if the processor models don't intersect.
1199 // A zero processor index means any processor.
Craig Topperb94011f2013-07-14 04:42:23 +00001200 SmallVectorImpl<unsigned> &ProcIndices = TransVec[TransIdx].ProcIndices;
Javed Absarf45d0b92017-10-08 17:23:30 +00001201 if (ProcIndices[0] && Variant.ProcIdx) {
Andrew Trickda984b12012-10-03 23:06:28 +00001202 unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(),
1203 Variant.ProcIdx);
1204 if (!Cnt)
1205 continue;
1206 if (Cnt > 1) {
1207 const CodeGenProcModel &PM =
1208 *(SchedModels.procModelBegin() + Variant.ProcIdx);
Joerg Sonnenberger635debe2012-10-25 20:33:17 +00001209 PrintFatalError(Variant.VarOrSeqDef->getLoc(),
1210 "Multiple variants defined for processor " +
1211 PM.ModelName +
1212 " Ensure only one SchedAlias exists per RW.");
Andrew Trickda984b12012-10-03 23:06:28 +00001213 }
1214 }
1215 if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) {
1216 Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate");
1217 if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm))
1218 continue;
1219 }
1220 if (IntersectingVariants.empty()) {
1221 // The first variant builds on the existing transition.
1222 Variant.TransVecIdx = TransIdx;
1223 IntersectingVariants.push_back(Variant);
1224 }
1225 else {
1226 // Push another copy of the current transition for more variants.
1227 Variant.TransVecIdx = TransVec.size();
1228 IntersectingVariants.push_back(Variant);
Dan Gohmanf6169d02013-03-29 00:13:08 +00001229 TransVec.push_back(TransVec[TransIdx]);
Andrew Trickda984b12012-10-03 23:06:28 +00001230 }
1231 }
Andrew Trickd97ff1f2013-03-29 19:08:31 +00001232 if (GenericRW && IntersectingVariants.empty()) {
1233 PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has "
1234 "a matching predicate on any processor");
1235 }
Andrew Trickda984b12012-10-03 23:06:28 +00001236}
1237
Andrew Trick9257b8f2012-09-22 02:24:21 +00001238// Push the Reads/Writes selected by this variant onto the PredTransition
1239// specified by VInfo.
1240void PredTransitions::
1241pushVariant(const TransVariant &VInfo, bool IsRead) {
Andrew Trick9257b8f2012-09-22 02:24:21 +00001242 PredTransition &Trans = TransVec[VInfo.TransVecIdx];
1243
Andrew Trick9257b8f2012-09-22 02:24:21 +00001244 // If this operand transition is reached through a processor-specific alias,
1245 // then the whole transition is specific to this processor.
1246 if (VInfo.ProcIdx != 0)
1247 Trans.ProcIndices.assign(1, VInfo.ProcIdx);
1248
Andrew Trick33401e82012-09-15 00:19:59 +00001249 IdxVec SelectedRWs;
Andrew Trickda984b12012-10-03 23:06:28 +00001250 if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) {
1251 Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate");
1252 Trans.PredTerm.push_back(PredCheck(IsRead, VInfo.RWIdx,PredDef));
1253 RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected");
1254 SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead);
1255 }
1256 else {
1257 assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") &&
1258 "variant must be a SchedVariant or aliased WriteSequence");
1259 SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead));
1260 }
Andrew Trick33401e82012-09-15 00:19:59 +00001261
Andrew Trick9257b8f2012-09-22 02:24:21 +00001262 const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead);
Andrew Trick33401e82012-09-15 00:19:59 +00001263
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001264 SmallVectorImpl<SmallVector<unsigned,4>> &RWSequences = IsRead
Andrew Trick33401e82012-09-15 00:19:59 +00001265 ? Trans.ReadSequences : Trans.WriteSequences;
1266 if (SchedRW.IsVariadic) {
1267 unsigned OperIdx = RWSequences.size()-1;
1268 // Make N-1 copies of this transition's last sequence.
1269 for (unsigned i = 1, e = SelectedRWs.size(); i != e; ++i) {
Arnold Schwaighofer3bd25242013-06-06 23:23:14 +00001270 // Create a temporary copy the vector could reallocate.
Arnold Schwaighoferf84a03a2013-06-07 00:04:30 +00001271 RWSequences.reserve(RWSequences.size() + 1);
1272 RWSequences.push_back(RWSequences[OperIdx]);
Andrew Trick33401e82012-09-15 00:19:59 +00001273 }
1274 // Push each of the N elements of the SelectedRWs onto a copy of the last
1275 // sequence (split the current operand into N operands).
1276 // Note that write sequences should be expanded within this loop--the entire
1277 // sequence belongs to a single operand.
1278 for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();
1279 RWI != RWE; ++RWI, ++OperIdx) {
1280 IdxVec ExpandedRWs;
1281 if (IsRead)
1282 ExpandedRWs.push_back(*RWI);
1283 else
1284 SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
1285 RWSequences[OperIdx].insert(RWSequences[OperIdx].end(),
1286 ExpandedRWs.begin(), ExpandedRWs.end());
1287 }
1288 assert(OperIdx == RWSequences.size() && "missed a sequence");
1289 }
1290 else {
1291 // Push this transition's expanded sequence onto this transition's last
1292 // sequence (add to the current operand's sequence).
1293 SmallVectorImpl<unsigned> &Seq = RWSequences.back();
1294 IdxVec ExpandedRWs;
1295 for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();
1296 RWI != RWE; ++RWI) {
1297 if (IsRead)
1298 ExpandedRWs.push_back(*RWI);
1299 else
1300 SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
1301 }
1302 Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end());
1303 }
1304}
1305
1306// RWSeq is a sequence of all Reads or all Writes for the next read or write
1307// operand. StartIdx is an index into TransVec where partial results
Andrew Trick9257b8f2012-09-22 02:24:21 +00001308// starts. RWSeq must be applied to all transitions between StartIdx and the end
Andrew Trick33401e82012-09-15 00:19:59 +00001309// of TransVec.
1310void PredTransitions::substituteVariantOperand(
1311 const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {
1312
1313 // Visit each original RW within the current sequence.
1314 for (SmallVectorImpl<unsigned>::const_iterator
1315 RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) {
1316 const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(*RWI, IsRead);
1317 // Push this RW on all partial PredTransitions or distribute variants.
1318 // New PredTransitions may be pushed within this loop which should not be
1319 // revisited (TransEnd must be loop invariant).
1320 for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size();
1321 TransIdx != TransEnd; ++TransIdx) {
1322 // In the common case, push RW onto the current operand's sequence.
Andrew Trick9257b8f2012-09-22 02:24:21 +00001323 if (!hasAliasedVariants(SchedRW, SchedModels)) {
Andrew Trick33401e82012-09-15 00:19:59 +00001324 if (IsRead)
1325 TransVec[TransIdx].ReadSequences.back().push_back(*RWI);
1326 else
1327 TransVec[TransIdx].WriteSequences.back().push_back(*RWI);
1328 continue;
1329 }
1330 // Distribute this partial PredTransition across intersecting variants.
Andrew Trickda984b12012-10-03 23:06:28 +00001331 // This will push a copies of TransVec[TransIdx] on the back of TransVec.
Andrew Trick9257b8f2012-09-22 02:24:21 +00001332 std::vector<TransVariant> IntersectingVariants;
Andrew Trickda984b12012-10-03 23:06:28 +00001333 getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants);
Andrew Trick33401e82012-09-15 00:19:59 +00001334 // Now expand each variant on top of its copy of the transition.
Andrew Trick9257b8f2012-09-22 02:24:21 +00001335 for (std::vector<TransVariant>::const_iterator
Andrew Trick33401e82012-09-15 00:19:59 +00001336 IVI = IntersectingVariants.begin(),
1337 IVE = IntersectingVariants.end();
Andrew Trick9257b8f2012-09-22 02:24:21 +00001338 IVI != IVE; ++IVI) {
1339 pushVariant(*IVI, IsRead);
1340 }
Andrew Trick33401e82012-09-15 00:19:59 +00001341 }
1342 }
1343}
1344
1345// For each variant of a Read/Write in Trans, substitute the sequence of
1346// Read/Writes guarded by the variant. This is exponential in the number of
1347// variant Read/Writes, but in practice detection of mutually exclusive
1348// predicates should result in linear growth in the total number variants.
1349//
1350// This is one step in a breadth-first search of nested variants.
1351void PredTransitions::substituteVariants(const PredTransition &Trans) {
1352 // Build up a set of partial results starting at the back of
1353 // PredTransitions. Remember the first new transition.
1354 unsigned StartIdx = TransVec.size();
Craig Topper195aaaf2018-03-22 06:15:10 +00001355 TransVec.emplace_back();
Andrew Trick33401e82012-09-15 00:19:59 +00001356 TransVec.back().PredTerm = Trans.PredTerm;
Andrew Trick9257b8f2012-09-22 02:24:21 +00001357 TransVec.back().ProcIndices = Trans.ProcIndices;
Andrew Trick33401e82012-09-15 00:19:59 +00001358
1359 // Visit each original write sequence.
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001360 for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
Andrew Trick33401e82012-09-15 00:19:59 +00001361 WSI = Trans.WriteSequences.begin(), WSE = Trans.WriteSequences.end();
1362 WSI != WSE; ++WSI) {
1363 // Push a new (empty) write sequence onto all partial Transitions.
1364 for (std::vector<PredTransition>::iterator I =
1365 TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
Craig Topper195aaaf2018-03-22 06:15:10 +00001366 I->WriteSequences.emplace_back();
Andrew Trick33401e82012-09-15 00:19:59 +00001367 }
1368 substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx);
1369 }
1370 // Visit each original read sequence.
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001371 for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
Andrew Trick33401e82012-09-15 00:19:59 +00001372 RSI = Trans.ReadSequences.begin(), RSE = Trans.ReadSequences.end();
1373 RSI != RSE; ++RSI) {
1374 // Push a new (empty) read sequence onto all partial Transitions.
1375 for (std::vector<PredTransition>::iterator I =
1376 TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
Craig Topper195aaaf2018-03-22 06:15:10 +00001377 I->ReadSequences.emplace_back();
Andrew Trick33401e82012-09-15 00:19:59 +00001378 }
1379 substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx);
1380 }
1381}
1382
Andrew Trick33401e82012-09-15 00:19:59 +00001383// Create a new SchedClass for each variant found by inferFromRW. Pass
Andrew Trick33401e82012-09-15 00:19:59 +00001384static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
Andrew Trick9257b8f2012-09-22 02:24:21 +00001385 unsigned FromClassIdx,
Andrew Trick33401e82012-09-15 00:19:59 +00001386 CodeGenSchedModels &SchedModels) {
1387 // For each PredTransition, create a new CodeGenSchedTransition, which usually
1388 // requires creating a new SchedClass.
1389 for (ArrayRef<PredTransition>::iterator
1390 I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) {
1391 IdxVec OperWritesVariant;
Craig Topper1970e952018-03-20 20:24:12 +00001392 transform(I->WriteSequences, std::back_inserter(OperWritesVariant),
1393 [&SchedModels](ArrayRef<unsigned> WS) {
1394 return SchedModels.findOrInsertRW(WS, /*IsRead=*/false);
1395 });
Andrew Trick33401e82012-09-15 00:19:59 +00001396 IdxVec OperReadsVariant;
Craig Topper1970e952018-03-20 20:24:12 +00001397 transform(I->ReadSequences, std::back_inserter(OperReadsVariant),
1398 [&SchedModels](ArrayRef<unsigned> RS) {
1399 return SchedModels.findOrInsertRW(RS, /*IsRead=*/true);
1400 });
Andrew Trick33401e82012-09-15 00:19:59 +00001401 CodeGenSchedTransition SCTrans;
1402 SCTrans.ToClassIdx =
Craig Topper24064772014-04-15 07:20:03 +00001403 SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant,
Craig Topper2ed54072018-03-24 22:58:03 +00001404 OperReadsVariant, I->ProcIndices);
1405 SCTrans.ProcIndices.assign(I->ProcIndices.begin(), I->ProcIndices.end());
Andrew Trick33401e82012-09-15 00:19:59 +00001406 // The final PredTerm is unique set of predicates guarding the transition.
1407 RecVec Preds;
Craig Topper1970e952018-03-20 20:24:12 +00001408 transform(I->PredTerm, std::back_inserter(Preds),
1409 [](const PredCheck &P) {
1410 return P.Predicate;
1411 });
Craig Topperb5ed2752018-03-20 20:24:10 +00001412 Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end());
Craig Topper18cfa2c2018-03-24 22:58:02 +00001413 SCTrans.PredTerm = std::move(Preds);
1414 SchedModels.getSchedClass(FromClassIdx)
1415 .Transitions.push_back(std::move(SCTrans));
Andrew Trick33401e82012-09-15 00:19:59 +00001416 }
1417}
1418
Andrew Trick9257b8f2012-09-22 02:24:21 +00001419// Create new SchedClasses for the given ReadWrite list. If any of the
1420// ReadWrites refers to a SchedVariant, create a new SchedClass for each variant
1421// of the ReadWrite list, following Aliases if necessary.
Benjamin Kramere1761952015-10-24 12:46:49 +00001422void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites,
1423 ArrayRef<unsigned> OperReads,
Andrew Trick33401e82012-09-15 00:19:59 +00001424 unsigned FromClassIdx,
Benjamin Kramere1761952015-10-24 12:46:49 +00001425 ArrayRef<unsigned> ProcIndices) {
Andrew Tricke97978f2013-03-26 21:36:39 +00001426 DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); dbgs() << ") ");
Andrew Trick33401e82012-09-15 00:19:59 +00001427
1428 // Create a seed transition with an empty PredTerm and the expanded sequences
1429 // of SchedWrites for the current SchedClass.
1430 std::vector<PredTransition> LastTransitions;
Craig Topper195aaaf2018-03-22 06:15:10 +00001431 LastTransitions.emplace_back();
Andrew Trick9257b8f2012-09-22 02:24:21 +00001432 LastTransitions.back().ProcIndices.append(ProcIndices.begin(),
1433 ProcIndices.end());
1434
Benjamin Kramere1761952015-10-24 12:46:49 +00001435 for (unsigned WriteIdx : OperWrites) {
Andrew Trick33401e82012-09-15 00:19:59 +00001436 IdxVec WriteSeq;
Benjamin Kramere1761952015-10-24 12:46:49 +00001437 expandRWSequence(WriteIdx, WriteSeq, /*IsRead=*/false);
Craig Topper195aaaf2018-03-22 06:15:10 +00001438 LastTransitions[0].WriteSequences.emplace_back();
1439 SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences.back();
Craig Topper1f57456c2018-03-20 20:24:14 +00001440 Seq.append(WriteSeq.begin(), WriteSeq.end());
Andrew Trick33401e82012-09-15 00:19:59 +00001441 DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");
1442 }
1443 DEBUG(dbgs() << " Reads: ");
Benjamin Kramere1761952015-10-24 12:46:49 +00001444 for (unsigned ReadIdx : OperReads) {
Andrew Trick33401e82012-09-15 00:19:59 +00001445 IdxVec ReadSeq;
Benjamin Kramere1761952015-10-24 12:46:49 +00001446 expandRWSequence(ReadIdx, ReadSeq, /*IsRead=*/true);
Craig Topper195aaaf2018-03-22 06:15:10 +00001447 LastTransitions[0].ReadSequences.emplace_back();
1448 SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences.back();
Craig Topper1f57456c2018-03-20 20:24:14 +00001449 Seq.append(ReadSeq.begin(), ReadSeq.end());
Andrew Trick33401e82012-09-15 00:19:59 +00001450 DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");
1451 }
1452 DEBUG(dbgs() << '\n');
1453
1454 // Collect all PredTransitions for individual operands.
1455 // Iterate until no variant writes remain.
1456 while (hasVariant(LastTransitions, *this)) {
1457 PredTransitions Transitions(*this);
Craig Topperf6114252018-03-20 20:24:16 +00001458 for (const PredTransition &Trans : LastTransitions)
1459 Transitions.substituteVariants(Trans);
Andrew Trick33401e82012-09-15 00:19:59 +00001460 DEBUG(Transitions.dump());
1461 LastTransitions.swap(Transitions.TransVec);
1462 }
1463 // If the first transition has no variants, nothing to do.
1464 if (LastTransitions[0].PredTerm.empty())
1465 return;
1466
1467 // WARNING: We are about to mutate the SchedClasses vector. Do not refer to
1468 // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions.
Andrew Trick9257b8f2012-09-22 02:24:21 +00001469 inferFromTransitions(LastTransitions, FromClassIdx, *this);
Andrew Trick33401e82012-09-15 00:19:59 +00001470}
1471
Andrew Trickcf398b22013-04-23 23:45:14 +00001472// Check if any processor resource group contains all resource records in
1473// SubUnits.
1474bool CodeGenSchedModels::hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM) {
1475 for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) {
1476 if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup"))
1477 continue;
1478 RecVec SuperUnits =
1479 PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources");
1480 RecIter RI = SubUnits.begin(), RE = SubUnits.end();
1481 for ( ; RI != RE; ++RI) {
David Majnemer0d955d02016-08-11 22:21:41 +00001482 if (!is_contained(SuperUnits, *RI)) {
Andrew Trickcf398b22013-04-23 23:45:14 +00001483 break;
1484 }
1485 }
1486 if (RI == RE)
1487 return true;
1488 }
1489 return false;
1490}
1491
1492// Verify that overlapping groups have a common supergroup.
1493void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) {
1494 for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) {
1495 if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup"))
1496 continue;
1497 RecVec CheckUnits =
1498 PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources");
1499 for (unsigned j = i+1; j < e; ++j) {
1500 if (!PM.ProcResourceDefs[j]->isSubClassOf("ProcResGroup"))
1501 continue;
1502 RecVec OtherUnits =
1503 PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources");
1504 if (std::find_first_of(CheckUnits.begin(), CheckUnits.end(),
1505 OtherUnits.begin(), OtherUnits.end())
1506 != CheckUnits.end()) {
1507 // CheckUnits and OtherUnits overlap
1508 OtherUnits.insert(OtherUnits.end(), CheckUnits.begin(),
1509 CheckUnits.end());
1510 if (!hasSuperGroup(OtherUnits, PM)) {
1511 PrintFatalError((PM.ProcResourceDefs[i])->getLoc(),
1512 "proc resource group overlaps with "
1513 + PM.ProcResourceDefs[j]->getName()
1514 + " but no supergroup contains both.");
1515 }
1516 }
1517 }
1518 }
1519}
1520
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +00001521// Collect all the RegisterFile definitions available in this target.
1522void CodeGenSchedModels::collectRegisterFiles() {
1523 RecVec RegisterFileDefs = Records.getAllDerivedDefinitions("RegisterFile");
1524
1525 // RegisterFiles is the vector of CodeGenRegisterFile.
1526 for (Record *RF : RegisterFileDefs) {
1527 // For each register file definition, construct a CodeGenRegisterFile object
1528 // and add it to the appropriate scheduling model.
1529 CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel"));
1530 PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(),RF));
1531 CodeGenRegisterFile &CGRF = PM.RegisterFiles.back();
1532
1533 // Now set the number of physical registers as well as the cost of registers
1534 // in each register class.
1535 CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs");
1536 RecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses");
1537 std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts");
1538 for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) {
1539 int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1;
1540 CGRF.Costs.emplace_back(RegisterClasses[I], Cost);
1541 }
1542 }
1543}
1544
Clement Courbetb4493792018-04-10 08:16:37 +00001545// Collect all the RegisterFile definitions available in this target.
1546void CodeGenSchedModels::collectPfmCounters() {
1547 for (Record *Def : Records.getAllDerivedDefinitions("PfmIssueCounter")) {
1548 CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel"));
1549 PM.PfmIssueCounterDefs.emplace_back(Def);
1550 }
1551 for (Record *Def : Records.getAllDerivedDefinitions("PfmCycleCounter")) {
1552 CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel"));
1553 if (PM.PfmCycleCounterDef) {
1554 PrintFatalError(Def->getLoc(),
1555 "multiple cycle counters for " +
1556 Def->getValueAsDef("SchedModel")->getName());
1557 }
1558 PM.PfmCycleCounterDef = Def;
1559 }
1560}
1561
Andrew Trick1e46d482012-09-15 00:20:02 +00001562// Collect and sort WriteRes, ReadAdvance, and ProcResources.
1563void CodeGenSchedModels::collectProcResources() {
Matthias Braun6b1fd9a2016-06-21 03:24:03 +00001564 ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits");
1565 ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
1566
Andrew Trick1e46d482012-09-15 00:20:02 +00001567 // Add any subtarget-specific SchedReadWrites that are directly associated
1568 // with processor resources. Refer to the parent SchedClass's ProcIndices to
1569 // determine which processors they apply to.
1570 for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();
1571 SCI != SCE; ++SCI) {
1572 if (SCI->ItinClassDef)
1573 collectItinProcResources(SCI->ItinClassDef);
Andrew Trick4fe440d2013-02-01 03:19:54 +00001574 else {
1575 // This class may have a default ReadWrite list which can be overriden by
1576 // InstRW definitions.
1577 if (!SCI->InstRWs.empty()) {
1578 for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();
1579 RWI != RWE; ++RWI) {
1580 Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");
Craig Topper9f3293a2018-03-24 21:57:35 +00001581 unsigned PIdx = getProcModel(RWModelDef).Index;
Andrew Trick4fe440d2013-02-01 03:19:54 +00001582 IdxVec Writes, Reads;
1583 findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
1584 Writes, Reads);
Craig Topper9f3293a2018-03-24 21:57:35 +00001585 collectRWResources(Writes, Reads, PIdx);
Andrew Trick4fe440d2013-02-01 03:19:54 +00001586 }
1587 }
Andrew Trick1e46d482012-09-15 00:20:02 +00001588 collectRWResources(SCI->Writes, SCI->Reads, SCI->ProcIndices);
Andrew Trick4fe440d2013-02-01 03:19:54 +00001589 }
Andrew Trick1e46d482012-09-15 00:20:02 +00001590 }
1591 // Add resources separately defined by each subtarget.
1592 RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes");
Javed Absar2c9570c2017-10-11 09:33:23 +00001593 for (Record *WR : WRDefs) {
1594 Record *ModelDef = WR->getValueAsDef("SchedModel");
1595 addWriteRes(WR, getProcModel(ModelDef).Index);
Andrew Trick1e46d482012-09-15 00:20:02 +00001596 }
Andrew Trickdca870b2014-03-13 03:49:20 +00001597 RecVec SWRDefs = Records.getAllDerivedDefinitions("SchedWriteRes");
Javed Absar2c9570c2017-10-11 09:33:23 +00001598 for (Record *SWR : SWRDefs) {
1599 Record *ModelDef = SWR->getValueAsDef("SchedModel");
1600 addWriteRes(SWR, getProcModel(ModelDef).Index);
Andrew Trickdca870b2014-03-13 03:49:20 +00001601 }
Andrew Trick1e46d482012-09-15 00:20:02 +00001602 RecVec RADefs = Records.getAllDerivedDefinitions("ReadAdvance");
Javed Absar2c9570c2017-10-11 09:33:23 +00001603 for (Record *RA : RADefs) {
1604 Record *ModelDef = RA->getValueAsDef("SchedModel");
1605 addReadAdvance(RA, getProcModel(ModelDef).Index);
Andrew Trick1e46d482012-09-15 00:20:02 +00001606 }
Andrew Trickdca870b2014-03-13 03:49:20 +00001607 RecVec SRADefs = Records.getAllDerivedDefinitions("SchedReadAdvance");
Javed Absar2c9570c2017-10-11 09:33:23 +00001608 for (Record *SRA : SRADefs) {
1609 if (SRA->getValueInit("SchedModel")->isComplete()) {
1610 Record *ModelDef = SRA->getValueAsDef("SchedModel");
1611 addReadAdvance(SRA, getProcModel(ModelDef).Index);
Andrew Trickdca870b2014-03-13 03:49:20 +00001612 }
1613 }
Andrew Trick40c4f382013-06-15 04:50:06 +00001614 // Add ProcResGroups that are defined within this processor model, which may
1615 // not be directly referenced but may directly specify a buffer size.
1616 RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
Javed Absar21c75912017-10-09 16:21:25 +00001617 for (Record *PRG : ProcResGroups) {
Javed Absarfc500042017-10-05 13:27:43 +00001618 if (!PRG->getValueInit("SchedModel")->isComplete())
Andrew Trick40c4f382013-06-15 04:50:06 +00001619 continue;
Javed Absarfc500042017-10-05 13:27:43 +00001620 CodeGenProcModel &PM = getProcModel(PRG->getValueAsDef("SchedModel"));
1621 if (!is_contained(PM.ProcResourceDefs, PRG))
1622 PM.ProcResourceDefs.push_back(PRG);
Andrew Trick40c4f382013-06-15 04:50:06 +00001623 }
Clement Courbeteb4f5d22018-02-05 12:23:51 +00001624 // Add ProcResourceUnits unconditionally.
1625 for (Record *PRU : Records.getAllDerivedDefinitions("ProcResourceUnits")) {
1626 if (!PRU->getValueInit("SchedModel")->isComplete())
1627 continue;
1628 CodeGenProcModel &PM = getProcModel(PRU->getValueAsDef("SchedModel"));
1629 if (!is_contained(PM.ProcResourceDefs, PRU))
1630 PM.ProcResourceDefs.push_back(PRU);
1631 }
Andrew Trick1e46d482012-09-15 00:20:02 +00001632 // Finalize each ProcModel by sorting the record arrays.
Craig Topper8a417c12014-12-09 08:05:51 +00001633 for (CodeGenProcModel &PM : ProcModels) {
Mandeep Singh Grang1b0e2f22018-04-06 20:18:05 +00001634 llvm::sort(PM.WriteResDefs.begin(), PM.WriteResDefs.end(),
1635 LessRecord());
1636 llvm::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(),
1637 LessRecord());
1638 llvm::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(),
1639 LessRecord());
Andrew Trick1e46d482012-09-15 00:20:02 +00001640 DEBUG(
1641 PM.dump();
1642 dbgs() << "WriteResDefs: ";
1643 for (RecIter RI = PM.WriteResDefs.begin(),
1644 RE = PM.WriteResDefs.end(); RI != RE; ++RI) {
1645 if ((*RI)->isSubClassOf("WriteRes"))
1646 dbgs() << (*RI)->getValueAsDef("WriteType")->getName() << " ";
1647 else
1648 dbgs() << (*RI)->getName() << " ";
1649 }
1650 dbgs() << "\nReadAdvanceDefs: ";
1651 for (RecIter RI = PM.ReadAdvanceDefs.begin(),
1652 RE = PM.ReadAdvanceDefs.end(); RI != RE; ++RI) {
1653 if ((*RI)->isSubClassOf("ReadAdvance"))
1654 dbgs() << (*RI)->getValueAsDef("ReadType")->getName() << " ";
1655 else
1656 dbgs() << (*RI)->getName() << " ";
1657 }
1658 dbgs() << "\nProcResourceDefs: ";
1659 for (RecIter RI = PM.ProcResourceDefs.begin(),
1660 RE = PM.ProcResourceDefs.end(); RI != RE; ++RI) {
1661 dbgs() << (*RI)->getName() << " ";
1662 }
1663 dbgs() << '\n');
Andrew Trickcf398b22013-04-23 23:45:14 +00001664 verifyProcResourceGroups(PM);
Andrew Trick1e46d482012-09-15 00:20:02 +00001665 }
Matthias Braun6b1fd9a2016-06-21 03:24:03 +00001666
1667 ProcResourceDefs.clear();
1668 ProcResGroups.clear();
Andrew Trick1e46d482012-09-15 00:20:02 +00001669}
1670
Matthias Braun17cb5792016-03-01 20:03:21 +00001671void CodeGenSchedModels::checkCompleteness() {
1672 bool Complete = true;
1673 bool HadCompleteModel = false;
1674 for (const CodeGenProcModel &ProcModel : procModels()) {
Simon Pilgrim1d793b82018-04-05 13:11:36 +00001675 const bool HasItineraries = ProcModel.hasItineraries();
Matthias Braun17cb5792016-03-01 20:03:21 +00001676 if (!ProcModel.ModelDef->getValueAsBit("CompleteModel"))
1677 continue;
1678 for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
1679 if (Inst->hasNoSchedulingInfo)
1680 continue;
Simon Dardis5f95c9a2016-06-24 08:43:27 +00001681 if (ProcModel.isUnsupported(*Inst))
1682 continue;
Matthias Braun17cb5792016-03-01 20:03:21 +00001683 unsigned SCIdx = getSchedClassIdx(*Inst);
1684 if (!SCIdx) {
1685 if (Inst->TheDef->isValueUnset("SchedRW") && !HadCompleteModel) {
1686 PrintError("No schedule information for instruction '"
1687 + Inst->TheDef->getName() + "'");
1688 Complete = false;
1689 }
1690 continue;
1691 }
1692
1693 const CodeGenSchedClass &SC = getSchedClass(SCIdx);
1694 if (!SC.Writes.empty())
1695 continue;
Simon Pilgrim1d793b82018-04-05 13:11:36 +00001696 if (HasItineraries && SC.ItinClassDef != nullptr &&
Ulrich Weigand75cda2f2016-10-31 18:59:52 +00001697 SC.ItinClassDef->getName() != "NoItinerary")
Matthias Braun42d9ad92016-03-03 00:04:59 +00001698 continue;
Matthias Braun17cb5792016-03-01 20:03:21 +00001699
1700 const RecVec &InstRWs = SC.InstRWs;
David Majnemer562e8292016-08-12 00:18:03 +00001701 auto I = find_if(InstRWs, [&ProcModel](const Record *R) {
1702 return R->getValueAsDef("SchedModel") == ProcModel.ModelDef;
1703 });
Matthias Braun17cb5792016-03-01 20:03:21 +00001704 if (I == InstRWs.end()) {
1705 PrintError("'" + ProcModel.ModelName + "' lacks information for '" +
1706 Inst->TheDef->getName() + "'");
1707 Complete = false;
1708 }
1709 }
1710 HadCompleteModel = true;
1711 }
Matthias Brauna939bd02016-03-01 21:36:12 +00001712 if (!Complete) {
1713 errs() << "\n\nIncomplete schedule models found.\n"
1714 << "- Consider setting 'CompleteModel = 0' while developing new models.\n"
1715 << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n"
1716 << "- Instructions should usually have Sched<[...]> as a superclass, "
Simon Dardis5f95c9a2016-06-24 08:43:27 +00001717 "you may temporarily use an empty list.\n"
1718 << "- Instructions related to unsupported features can be excluded with "
1719 "list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the "
1720 "processor model.\n\n";
Matthias Braun17cb5792016-03-01 20:03:21 +00001721 PrintFatalError("Incomplete schedule model");
Matthias Brauna939bd02016-03-01 21:36:12 +00001722 }
Matthias Braun17cb5792016-03-01 20:03:21 +00001723}
1724
Andrew Trick1e46d482012-09-15 00:20:02 +00001725// Collect itinerary class resources for each processor.
1726void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) {
1727 for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {
1728 const CodeGenProcModel &PM = ProcModels[PIdx];
1729 // For all ItinRW entries.
1730 bool HasMatch = false;
1731 for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();
1732 II != IE; ++II) {
1733 RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
1734 if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))
1735 continue;
1736 if (HasMatch)
Joerg Sonnenberger635debe2012-10-25 20:33:17 +00001737 PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "
1738 + ItinClassDef->getName()
1739 + " in ItinResources for " + PM.ModelName);
Andrew Trick1e46d482012-09-15 00:20:02 +00001740 HasMatch = true;
1741 IdxVec Writes, Reads;
1742 findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
Craig Topper9f3293a2018-03-24 21:57:35 +00001743 collectRWResources(Writes, Reads, PIdx);
Andrew Trick1e46d482012-09-15 00:20:02 +00001744 }
1745 }
1746}
1747
Andrew Trickd0b9c442012-10-10 05:43:13 +00001748void CodeGenSchedModels::collectRWResources(unsigned RWIdx, bool IsRead,
Benjamin Kramere1761952015-10-24 12:46:49 +00001749 ArrayRef<unsigned> ProcIndices) {
Andrew Trickd0b9c442012-10-10 05:43:13 +00001750 const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);
1751 if (SchedRW.TheDef) {
1752 if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) {
Benjamin Kramere1761952015-10-24 12:46:49 +00001753 for (unsigned Idx : ProcIndices)
1754 addWriteRes(SchedRW.TheDef, Idx);
Andrew Trickd0b9c442012-10-10 05:43:13 +00001755 }
1756 else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) {
Benjamin Kramere1761952015-10-24 12:46:49 +00001757 for (unsigned Idx : ProcIndices)
1758 addReadAdvance(SchedRW.TheDef, Idx);
Andrew Trickd0b9c442012-10-10 05:43:13 +00001759 }
1760 }
1761 for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
1762 AI != AE; ++AI) {
1763 IdxVec AliasProcIndices;
1764 if ((*AI)->getValueInit("SchedModel")->isComplete()) {
1765 AliasProcIndices.push_back(
1766 getProcModel((*AI)->getValueAsDef("SchedModel")).Index);
1767 }
1768 else
1769 AliasProcIndices = ProcIndices;
1770 const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW"));
1771 assert(AliasRW.IsRead == IsRead && "cannot alias reads to writes");
1772
1773 IdxVec ExpandedRWs;
1774 expandRWSequence(AliasRW.Index, ExpandedRWs, IsRead);
1775 for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end();
1776 SI != SE; ++SI) {
1777 collectRWResources(*SI, IsRead, AliasProcIndices);
1778 }
1779 }
1780}
Andrew Trick1e46d482012-09-15 00:20:02 +00001781
1782// Collect resources for a set of read/write types and processor indices.
Benjamin Kramere1761952015-10-24 12:46:49 +00001783void CodeGenSchedModels::collectRWResources(ArrayRef<unsigned> Writes,
1784 ArrayRef<unsigned> Reads,
1785 ArrayRef<unsigned> ProcIndices) {
Benjamin Kramere1761952015-10-24 12:46:49 +00001786 for (unsigned Idx : Writes)
1787 collectRWResources(Idx, /*IsRead=*/false, ProcIndices);
Andrew Trickd0b9c442012-10-10 05:43:13 +00001788
Benjamin Kramere1761952015-10-24 12:46:49 +00001789 for (unsigned Idx : Reads)
1790 collectRWResources(Idx, /*IsRead=*/true, ProcIndices);
Andrew Trick1e46d482012-09-15 00:20:02 +00001791}
1792
1793// Find the processor's resource units for this kind of resource.
1794Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind,
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001795 const CodeGenProcModel &PM,
1796 ArrayRef<SMLoc> Loc) const {
Andrew Trick1e46d482012-09-15 00:20:02 +00001797 if (ProcResKind->isSubClassOf("ProcResourceUnits"))
1798 return ProcResKind;
1799
Craig Topper24064772014-04-15 07:20:03 +00001800 Record *ProcUnitDef = nullptr;
Matthias Braun6b1fd9a2016-06-21 03:24:03 +00001801 assert(!ProcResourceDefs.empty());
1802 assert(!ProcResGroups.empty());
Andrew Trick1e46d482012-09-15 00:20:02 +00001803
Javed Absar67b042c2017-09-13 10:31:10 +00001804 for (Record *ProcResDef : ProcResourceDefs) {
1805 if (ProcResDef->getValueAsDef("Kind") == ProcResKind
1806 && ProcResDef->getValueAsDef("SchedModel") == PM.ModelDef) {
Andrew Trick1e46d482012-09-15 00:20:02 +00001807 if (ProcUnitDef) {
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001808 PrintFatalError(Loc,
Joerg Sonnenberger635debe2012-10-25 20:33:17 +00001809 "Multiple ProcessorResourceUnits associated with "
1810 + ProcResKind->getName());
Andrew Trick1e46d482012-09-15 00:20:02 +00001811 }
Javed Absar67b042c2017-09-13 10:31:10 +00001812 ProcUnitDef = ProcResDef;
Andrew Trick1e46d482012-09-15 00:20:02 +00001813 }
1814 }
Javed Absar67b042c2017-09-13 10:31:10 +00001815 for (Record *ProcResGroup : ProcResGroups) {
1816 if (ProcResGroup == ProcResKind
1817 && ProcResGroup->getValueAsDef("SchedModel") == PM.ModelDef) {
Andrew Trick4e67cba2013-03-14 21:21:50 +00001818 if (ProcUnitDef) {
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001819 PrintFatalError(Loc,
Andrew Trick4e67cba2013-03-14 21:21:50 +00001820 "Multiple ProcessorResourceUnits associated with "
1821 + ProcResKind->getName());
1822 }
Javed Absar67b042c2017-09-13 10:31:10 +00001823 ProcUnitDef = ProcResGroup;
Andrew Trick4e67cba2013-03-14 21:21:50 +00001824 }
1825 }
Andrew Trick1e46d482012-09-15 00:20:02 +00001826 if (!ProcUnitDef) {
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001827 PrintFatalError(Loc,
Joerg Sonnenberger635debe2012-10-25 20:33:17 +00001828 "No ProcessorResources associated with "
1829 + ProcResKind->getName());
Andrew Trick1e46d482012-09-15 00:20:02 +00001830 }
1831 return ProcUnitDef;
1832}
1833
1834// Iteratively add a resource and its super resources.
1835void CodeGenSchedModels::addProcResource(Record *ProcResKind,
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001836 CodeGenProcModel &PM,
1837 ArrayRef<SMLoc> Loc) {
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001838 while (true) {
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001839 Record *ProcResUnits = findProcResUnits(ProcResKind, PM, Loc);
Andrew Trick1e46d482012-09-15 00:20:02 +00001840
1841 // See if this ProcResource is already associated with this processor.
David Majnemer42531262016-08-12 03:55:06 +00001842 if (is_contained(PM.ProcResourceDefs, ProcResUnits))
Andrew Trick1e46d482012-09-15 00:20:02 +00001843 return;
1844
1845 PM.ProcResourceDefs.push_back(ProcResUnits);
Andrew Trick4e67cba2013-03-14 21:21:50 +00001846 if (ProcResUnits->isSubClassOf("ProcResGroup"))
1847 return;
1848
Andrew Trick1e46d482012-09-15 00:20:02 +00001849 if (!ProcResUnits->getValueInit("Super")->isComplete())
1850 return;
1851
1852 ProcResKind = ProcResUnits->getValueAsDef("Super");
1853 }
1854}
1855
1856// Add resources for a SchedWrite to this processor if they don't exist.
1857void CodeGenSchedModels::addWriteRes(Record *ProcWriteResDef, unsigned PIdx) {
Andrew Trick9257b8f2012-09-22 02:24:21 +00001858 assert(PIdx && "don't add resources to an invalid Processor model");
1859
Andrew Trick1e46d482012-09-15 00:20:02 +00001860 RecVec &WRDefs = ProcModels[PIdx].WriteResDefs;
David Majnemer42531262016-08-12 03:55:06 +00001861 if (is_contained(WRDefs, ProcWriteResDef))
Andrew Trick1e46d482012-09-15 00:20:02 +00001862 return;
1863 WRDefs.push_back(ProcWriteResDef);
1864
1865 // Visit ProcResourceKinds referenced by the newly discovered WriteRes.
1866 RecVec ProcResDefs = ProcWriteResDef->getValueAsListOfDefs("ProcResources");
1867 for (RecIter WritePRI = ProcResDefs.begin(), WritePRE = ProcResDefs.end();
1868 WritePRI != WritePRE; ++WritePRI) {
Evandro Menezes9dc54e22017-11-21 21:33:52 +00001869 addProcResource(*WritePRI, ProcModels[PIdx], ProcWriteResDef->getLoc());
Andrew Trick1e46d482012-09-15 00:20:02 +00001870 }
1871}
1872
1873// Add resources for a ReadAdvance to this processor if they don't exist.
1874void CodeGenSchedModels::addReadAdvance(Record *ProcReadAdvanceDef,
1875 unsigned PIdx) {
1876 RecVec &RADefs = ProcModels[PIdx].ReadAdvanceDefs;
David Majnemer42531262016-08-12 03:55:06 +00001877 if (is_contained(RADefs, ProcReadAdvanceDef))
Andrew Trick1e46d482012-09-15 00:20:02 +00001878 return;
1879 RADefs.push_back(ProcReadAdvanceDef);
1880}
1881
Andrew Trick8fa00f52012-09-17 22:18:43 +00001882unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const {
David Majnemer0d955d02016-08-11 22:21:41 +00001883 RecIter PRPos = find(ProcResourceDefs, PRDef);
Andrew Trick8fa00f52012-09-17 22:18:43 +00001884 if (PRPos == ProcResourceDefs.end())
Joerg Sonnenberger635debe2012-10-25 20:33:17 +00001885 PrintFatalError(PRDef->getLoc(), "ProcResource def is not included in "
1886 "the ProcResources list for " + ModelName);
Andrew Trick8fa00f52012-09-17 22:18:43 +00001887 // Idx=0 is reserved for invalid.
Rafael Espindola72961392012-11-02 20:57:36 +00001888 return 1 + (PRPos - ProcResourceDefs.begin());
Andrew Trick8fa00f52012-09-17 22:18:43 +00001889}
1890
Simon Dardis5f95c9a2016-06-24 08:43:27 +00001891bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const {
1892 for (const Record *TheDef : UnsupportedFeaturesDefs) {
1893 for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) {
1894 if (TheDef->getName() == PredDef->getName())
1895 return true;
1896 }
1897 }
1898 return false;
1899}
1900
Andrew Trick76686492012-09-15 00:19:57 +00001901#ifndef NDEBUG
1902void CodeGenProcModel::dump() const {
1903 dbgs() << Index << ": " << ModelName << " "
1904 << (ModelDef ? ModelDef->getName() : "inferred") << " "
1905 << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n';
1906}
1907
1908void CodeGenSchedRW::dump() const {
1909 dbgs() << Name << (IsVariadic ? " (V) " : " ");
1910 if (IsSequence) {
1911 dbgs() << "(";
1912 dumpIdxVec(Sequence);
1913 dbgs() << ")";
1914 }
1915}
1916
1917void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
Andrew Trickbf8a28d2013-03-16 18:58:55 +00001918 dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n'
Andrew Trick76686492012-09-15 00:19:57 +00001919 << " Writes: ";
1920 for (unsigned i = 0, N = Writes.size(); i < N; ++i) {
1921 SchedModels->getSchedWrite(Writes[i]).dump();
1922 if (i < N-1) {
1923 dbgs() << '\n';
1924 dbgs().indent(10);
1925 }
1926 }
1927 dbgs() << "\n Reads: ";
1928 for (unsigned i = 0, N = Reads.size(); i < N; ++i) {
1929 SchedModels->getSchedRead(Reads[i]).dump();
1930 if (i < N-1) {
1931 dbgs() << '\n';
1932 dbgs().indent(10);
1933 }
1934 }
1935 dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n';
Andrew Tricke97978f2013-03-26 21:36:39 +00001936 if (!Transitions.empty()) {
1937 dbgs() << "\n Transitions for Proc ";
Javed Absar67b042c2017-09-13 10:31:10 +00001938 for (const CodeGenSchedTransition &Transition : Transitions) {
1939 dumpIdxVec(Transition.ProcIndices);
Andrew Tricke97978f2013-03-26 21:36:39 +00001940 }
1941 }
Andrew Trick76686492012-09-15 00:19:57 +00001942}
Andrew Trick33401e82012-09-15 00:19:59 +00001943
1944void PredTransitions::dump() const {
1945 dbgs() << "Expanded Variants:\n";
1946 for (std::vector<PredTransition>::const_iterator
1947 TI = TransVec.begin(), TE = TransVec.end(); TI != TE; ++TI) {
1948 dbgs() << "{";
1949 for (SmallVectorImpl<PredCheck>::const_iterator
1950 PCI = TI->PredTerm.begin(), PCE = TI->PredTerm.end();
1951 PCI != PCE; ++PCI) {
1952 if (PCI != TI->PredTerm.begin())
1953 dbgs() << ", ";
1954 dbgs() << SchedModels.getSchedRW(PCI->RWIdx, PCI->IsRead).Name
1955 << ":" << PCI->Predicate->getName();
1956 }
1957 dbgs() << "},\n => {";
Eugene Zelenkoa3fe70d2016-11-30 17:48:10 +00001958 for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
Andrew Trick33401e82012-09-15 00:19:59 +00001959 WSI = TI->WriteSequences.begin(), WSE = TI->WriteSequences.end();
1960 WSI != WSE; ++WSI) {
1961 dbgs() << "(";
1962 for (SmallVectorImpl<unsigned>::const_iterator
1963 WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) {
1964 if (WI != WSI->begin())
1965 dbgs() << ", ";
1966 dbgs() << SchedModels.getSchedWrite(*WI).Name;
1967 }
1968 dbgs() << "),";
1969 }
1970 dbgs() << "}\n";
1971 }
1972}
Andrew Trick76686492012-09-15 00:19:57 +00001973#endif // NDEBUG