1 //===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend emits subtarget enumerations.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "CodeGenSchedule.h"
14 #include "CodeGenTarget.h"
15 #include "PredicateExpander.h"
16 #include "llvm/ADT/SmallPtrSet.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/MC/MCInstrItineraries.h"
21 #include "llvm/MC/MCSchedule.h"
22 #include "llvm/MC/SubtargetFeature.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/TableGen/Error.h"
27 #include "llvm/TableGen/Record.h"
28 #include "llvm/TableGen/TableGenBackend.h"
29 #include <algorithm>
30 #include <cassert>
31 #include <cstdint>
32 #include <iterator>
33 #include <map>
34 #include <string>
35 #include <vector>
36
37 using namespace llvm;
38
39 #define DEBUG_TYPE "subtarget-emitter"
40
41 namespace {
42
43 class SubtargetEmitter {
44 // Each processor has a SchedClassDesc table with an entry for each SchedClass.
45 // The SchedClassDesc table indexes into a global write resource table, write
46 // latency table, and read advance table.
47 struct SchedClassTables {
48 std::vector<std::vector<MCSchedClassDesc>> ProcSchedClasses;
49 std::vector<MCWriteProcResEntry> WriteProcResources;
50 std::vector<MCWriteLatencyEntry> WriteLatencies;
51 std::vector<std::string> WriterNames;
52 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
53
54 // Reserve an invalid entry at index 0
SchedClassTables__anon9e775afd0111::SubtargetEmitter::SchedClassTables55 SchedClassTables() {
56 ProcSchedClasses.resize(1);
57 WriteProcResources.resize(1);
58 WriteLatencies.resize(1);
59 WriterNames.push_back("InvalidWrite");
60 ReadAdvanceEntries.resize(1);
61 }
62 };
63
64 struct LessWriteProcResources {
operator ()__anon9e775afd0111::SubtargetEmitter::LessWriteProcResources65 bool operator()(const MCWriteProcResEntry &LHS,
66 const MCWriteProcResEntry &RHS) {
67 return LHS.ProcResourceIdx < RHS.ProcResourceIdx;
68 }
69 };
70
71 const CodeGenTarget &TGT;
72 RecordKeeper &Records;
73 CodeGenSchedModels &SchedModels;
74 std::string Target;
75
76 void Enumeration(raw_ostream &OS, DenseMap<Record *, unsigned> &FeatureMap);
77 void EmitSubtargetInfoMacroCalls(raw_ostream &OS);
78 unsigned FeatureKeyValues(raw_ostream &OS,
79 const DenseMap<Record *, unsigned> &FeatureMap);
80 unsigned CPUKeyValues(raw_ostream &OS,
81 const DenseMap<Record *, unsigned> &FeatureMap);
82 void FormItineraryStageString(const std::string &Names,
83 Record *ItinData, std::string &ItinString,
84 unsigned &NStages);
85 void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
86 unsigned &NOperandCycles);
87 void FormItineraryBypassString(const std::string &Names,
88 Record *ItinData,
89 std::string &ItinString, unsigned NOperandCycles);
90 void EmitStageAndOperandCycleData(raw_ostream &OS,
91 std::vector<std::vector<InstrItinerary>>
92 &ProcItinLists);
93 void EmitItineraries(raw_ostream &OS,
94 std::vector<std::vector<InstrItinerary>>
95 &ProcItinLists);
96 unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
97 raw_ostream &OS);
98 void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
99 raw_ostream &OS);
100 void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,
101 raw_ostream &OS);
102 void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name,
103 char Separator);
104 void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel,
105 raw_ostream &OS);
106 void EmitProcessorResources(const CodeGenProcModel &ProcModel,
107 raw_ostream &OS);
108 Record *FindWriteResources(const CodeGenSchedRW &SchedWrite,
109 const CodeGenProcModel &ProcModel);
110 Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
111 const CodeGenProcModel &ProcModel);
112 void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
113 const CodeGenProcModel &ProcModel);
114 void GenSchedClassTables(const CodeGenProcModel &ProcModel,
115 SchedClassTables &SchedTables);
116 void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
117 void EmitProcessorModels(raw_ostream &OS);
118 void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS);
119 void emitSchedModelHelpersImpl(raw_ostream &OS,
120 bool OnlyExpandMCInstPredicates = false);
121 void emitGenMCSubtargetInfo(raw_ostream &OS);
122 void EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS);
123
124 void EmitSchedModel(raw_ostream &OS);
125 void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS);
126 void ParseFeaturesFunction(raw_ostream &OS);
127
128 public:
SubtargetEmitter(RecordKeeper & R,CodeGenTarget & TGT)129 SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT)
130 : TGT(TGT), Records(R), SchedModels(TGT.getSchedModels()),
131 Target(TGT.getName()) {}
132
133 void run(raw_ostream &o);
134 };
135
136 } // end anonymous namespace
137
138 //
139 // Enumeration - Emit the specified class as an enumeration.
140 //
Enumeration(raw_ostream & OS,DenseMap<Record *,unsigned> & FeatureMap)141 void SubtargetEmitter::Enumeration(raw_ostream &OS,
142 DenseMap<Record *, unsigned> &FeatureMap) {
143 // Get all records of class and sort
144 std::vector<Record*> DefList =
145 Records.getAllDerivedDefinitions("SubtargetFeature");
146 llvm::sort(DefList, LessRecord());
147
148 unsigned N = DefList.size();
149 if (N == 0)
150 return;
151 if (N + 1 > MAX_SUBTARGET_FEATURES)
152 PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
153
154 OS << "namespace " << Target << " {\n";
155
156 // Open enumeration.
157 OS << "enum {\n";
158
159 // For each record
160 for (unsigned i = 0; i < N; ++i) {
161 // Next record
162 Record *Def = DefList[i];
163
164 // Get and emit name
165 OS << " " << Def->getName() << " = " << i << ",\n";
166
167 // Save the index for this feature.
168 FeatureMap[Def] = i;
169 }
170
171 OS << " "
172 << "NumSubtargetFeatures = " << N << "\n";
173
174 // Close enumeration and namespace
175 OS << "};\n";
176 OS << "} // end namespace " << Target << "\n";
177 }
178
printFeatureMask(raw_ostream & OS,RecVec & FeatureList,const DenseMap<Record *,unsigned> & FeatureMap)179 static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList,
180 const DenseMap<Record *, unsigned> &FeatureMap) {
181 std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
182 for (const Record *Feature : FeatureList) {
183 unsigned Bit = FeatureMap.lookup(Feature);
184 Mask[Bit / 64] |= 1ULL << (Bit % 64);
185 }
186
187 OS << "{ { { ";
188 for (unsigned i = 0; i != Mask.size(); ++i) {
189 OS << "0x";
190 OS.write_hex(Mask[i]);
191 OS << "ULL, ";
192 }
193 OS << "} } }";
194 }
195
196 /// Emit some information about the SubtargetFeature as calls to a macro so
197 /// that they can be used from C++.
EmitSubtargetInfoMacroCalls(raw_ostream & OS)198 void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) {
199 OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n";
200
201 std::vector<Record *> FeatureList =
202 Records.getAllDerivedDefinitions("SubtargetFeature");
203 llvm::sort(FeatureList, LessRecordFieldName());
204
205 for (const Record *Feature : FeatureList) {
206 const StringRef Attribute = Feature->getValueAsString("Attribute");
207 const StringRef Value = Feature->getValueAsString("Value");
208
209 // Only handle boolean features for now, excluding BitVectors and enums.
210 const bool IsBool = (Value == "false" || Value == "true") &&
211 !StringRef(Attribute).contains('[');
212 if (!IsBool)
213 continue;
214
215 // Some features default to true, with values set to false if enabled.
216 const char *Default = Value == "false" ? "true" : "false";
217
218 // Define the getter with lowercased first char: xxxYyy() { return XxxYyy; }
219 const std::string Getter =
220 Attribute.substr(0, 1).lower() + Attribute.substr(1).str();
221
222 OS << "GET_SUBTARGETINFO_MACRO(" << Attribute << ", " << Default << ", "
223 << Getter << ")\n";
224 }
225 OS << "#undef GET_SUBTARGETINFO_MACRO\n";
226 OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n";
227
228 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
229 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";
230 }
231
232 //
233 // FeatureKeyValues - Emit data of all the subtarget features. Used by the
234 // command line.
235 //
FeatureKeyValues(raw_ostream & OS,const DenseMap<Record *,unsigned> & FeatureMap)236 unsigned SubtargetEmitter::FeatureKeyValues(
237 raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap) {
238 // Gather and sort all the features
239 std::vector<Record*> FeatureList =
240 Records.getAllDerivedDefinitions("SubtargetFeature");
241
242 if (FeatureList.empty())
243 return 0;
244
245 llvm::sort(FeatureList, LessRecordFieldName());
246
247 // Begin feature table
248 OS << "// Sorted (by key) array of values for CPU features.\n"
249 << "extern const llvm::SubtargetFeatureKV " << Target
250 << "FeatureKV[] = {\n";
251
252 // For each feature
253 unsigned NumFeatures = 0;
254 for (const Record *Feature : FeatureList) {
255 // Next feature
256 StringRef Name = Feature->getName();
257 StringRef CommandLineName = Feature->getValueAsString("Name");
258 StringRef Desc = Feature->getValueAsString("Desc");
259
260 if (CommandLineName.empty()) continue;
261
262 // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } }
263 OS << " { "
264 << "\"" << CommandLineName << "\", "
265 << "\"" << Desc << "\", "
266 << Target << "::" << Name << ", ";
267
268 RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
269
270 printFeatureMask(OS, ImpliesList, FeatureMap);
271
272 OS << " },\n";
273 ++NumFeatures;
274 }
275
276 // End feature table
277 OS << "};\n";
278
279 return NumFeatures;
280 }
281
282 //
283 // CPUKeyValues - Emit data of all the subtarget processors. Used by command
284 // line.
285 //
286 unsigned
CPUKeyValues(raw_ostream & OS,const DenseMap<Record *,unsigned> & FeatureMap)287 SubtargetEmitter::CPUKeyValues(raw_ostream &OS,
288 const DenseMap<Record *, unsigned> &FeatureMap) {
289 // Gather and sort processor information
290 std::vector<Record*> ProcessorList =
291 Records.getAllDerivedDefinitions("Processor");
292 llvm::sort(ProcessorList, LessRecordFieldName());
293
294 // Begin processor table
295 OS << "// Sorted (by key) array of values for CPU subtype.\n"
296 << "extern const llvm::SubtargetSubTypeKV " << Target
297 << "SubTypeKV[] = {\n";
298
299 // For each processor
300 for (Record *Processor : ProcessorList) {
301 StringRef Name = Processor->getValueAsString("Name");
302 RecVec FeatureList = Processor->getValueAsListOfDefs("Features");
303 RecVec TuneFeatureList = Processor->getValueAsListOfDefs("TuneFeatures");
304
305 // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } },
306 OS << " { "
307 << "\"" << Name << "\", ";
308
309 printFeatureMask(OS, FeatureList, FeatureMap);
310 OS << ", ";
311 printFeatureMask(OS, TuneFeatureList, FeatureMap);
312
313 // Emit the scheduler model pointer.
314 const std::string &ProcModelName =
315 SchedModels.getModelForProc(Processor).ModelName;
316 OS << ", &" << ProcModelName << " },\n";
317 }
318
319 // End processor table
320 OS << "};\n";
321
322 return ProcessorList.size();
323 }
324
325 //
326 // FormItineraryStageString - Compose a string containing the stage
327 // data initialization for the specified itinerary. N is the number
328 // of stages.
329 //
FormItineraryStageString(const std::string & Name,Record * ItinData,std::string & ItinString,unsigned & NStages)330 void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
331 Record *ItinData,
332 std::string &ItinString,
333 unsigned &NStages) {
334 // Get states list
335 RecVec StageList = ItinData->getValueAsListOfDefs("Stages");
336
337 // For each stage
338 unsigned N = NStages = StageList.size();
339 for (unsigned i = 0; i < N;) {
340 // Next stage
341 const Record *Stage = StageList[i];
342
343 // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }
344 int Cycles = Stage->getValueAsInt("Cycles");
345 ItinString += " { " + itostr(Cycles) + ", ";
346
347 // Get unit list
348 RecVec UnitList = Stage->getValueAsListOfDefs("Units");
349
350 // For each unit
351 for (unsigned j = 0, M = UnitList.size(); j < M;) {
352 // Add name and bitwise or
353 ItinString += Name + "FU::" + UnitList[j]->getName().str();
354 if (++j < M) ItinString += " | ";
355 }
356
357 int TimeInc = Stage->getValueAsInt("TimeInc");
358 ItinString += ", " + itostr(TimeInc);
359
360 int Kind = Stage->getValueAsInt("Kind");
361 ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);
362
363 // Close off stage
364 ItinString += " }";
365 if (++i < N) ItinString += ", ";
366 }
367 }
368
369 //
370 // FormItineraryOperandCycleString - Compose a string containing the
371 // operand cycle initialization for the specified itinerary. N is the
372 // number of operands that has cycles specified.
373 //
FormItineraryOperandCycleString(Record * ItinData,std::string & ItinString,unsigned & NOperandCycles)374 void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData,
375 std::string &ItinString, unsigned &NOperandCycles) {
376 // Get operand cycle list
377 std::vector<int64_t> OperandCycleList =
378 ItinData->getValueAsListOfInts("OperandCycles");
379
380 // For each operand cycle
381 NOperandCycles = OperandCycleList.size();
382 ListSeparator LS;
383 for (int OCycle : OperandCycleList) {
384 // Next operand cycle
385 ItinString += LS;
386 ItinString += " " + itostr(OCycle);
387 }
388 }
389
FormItineraryBypassString(const std::string & Name,Record * ItinData,std::string & ItinString,unsigned NOperandCycles)390 void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
391 Record *ItinData,
392 std::string &ItinString,
393 unsigned NOperandCycles) {
394 RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses");
395 unsigned N = BypassList.size();
396 unsigned i = 0;
397 ListSeparator LS;
398 for (; i < N; ++i) {
399 ItinString += LS;
400 ItinString += Name + "Bypass::" + BypassList[i]->getName().str();
401 }
402 for (; i < NOperandCycles; ++i) {
403 ItinString += LS;
404 ItinString += " 0";
405 }
406 }
407
408 //
409 // EmitStageAndOperandCycleData - Generate unique itinerary stages and operand
410 // cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed
411 // by CodeGenSchedClass::Index.
412 //
413 void SubtargetEmitter::
EmitStageAndOperandCycleData(raw_ostream & OS,std::vector<std::vector<InstrItinerary>> & ProcItinLists)414 EmitStageAndOperandCycleData(raw_ostream &OS,
415 std::vector<std::vector<InstrItinerary>>
416 &ProcItinLists) {
417 // Multiple processor models may share an itinerary record. Emit it once.
418 SmallPtrSet<Record*, 8> ItinsDefSet;
419
420 // Emit functional units for all the itineraries.
421 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
422
423 if (!ItinsDefSet.insert(ProcModel.ItinsDef).second)
424 continue;
425
426 RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU");
427 if (FUs.empty())
428 continue;
429
430 StringRef Name = ProcModel.ItinsDef->getName();
431 OS << "\n// Functional units for \"" << Name << "\"\n"
432 << "namespace " << Name << "FU {\n";
433
434 for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
435 OS << " const InstrStage::FuncUnits " << FUs[j]->getName()
436 << " = 1ULL << " << j << ";\n";
437
438 OS << "} // end namespace " << Name << "FU\n";
439
440 RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");
441 if (!BPs.empty()) {
442 OS << "\n// Pipeline forwarding paths for itineraries \"" << Name
443 << "\"\n" << "namespace " << Name << "Bypass {\n";
444
445 OS << " const unsigned NoBypass = 0;\n";
446 for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
447 OS << " const unsigned " << BPs[j]->getName()
448 << " = 1 << " << j << ";\n";
449
450 OS << "} // end namespace " << Name << "Bypass\n";
451 }
452 }
453
454 // Begin stages table
455 std::string StageTable = "\nextern const llvm::InstrStage " + Target +
456 "Stages[] = {\n";
457 StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
458
459 // Begin operand cycle table
460 std::string OperandCycleTable = "extern const unsigned " + Target +
461 "OperandCycles[] = {\n";
462 OperandCycleTable += " 0, // No itinerary\n";
463
464 // Begin pipeline bypass table
465 std::string BypassTable = "extern const unsigned " + Target +
466 "ForwardingPaths[] = {\n";
467 BypassTable += " 0, // No itinerary\n";
468
469 // For each Itinerary across all processors, add a unique entry to the stages,
470 // operand cycles, and pipeline bypass tables. Then add the new Itinerary
471 // object with computed offsets to the ProcItinLists result.
472 unsigned StageCount = 1, OperandCycleCount = 1;
473 std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
474 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
475 // Add process itinerary to the list.
476 ProcItinLists.resize(ProcItinLists.size()+1);
477
478 // If this processor defines no itineraries, then leave the itinerary list
479 // empty.
480 std::vector<InstrItinerary> &ItinList = ProcItinLists.back();
481 if (!ProcModel.hasItineraries())
482 continue;
483
484 StringRef Name = ProcModel.ItinsDef->getName();
485
486 ItinList.resize(SchedModels.numInstrSchedClasses());
487 assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");
488
489 for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();
490 SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
491
492 // Next itinerary data
493 Record *ItinData = ProcModel.ItinDefList[SchedClassIdx];
494
495 // Get string and stage count
496 std::string ItinStageString;
497 unsigned NStages = 0;
498 if (ItinData)
499 FormItineraryStageString(std::string(Name), ItinData, ItinStageString,
500 NStages);
501
502 // Get string and operand cycle count
503 std::string ItinOperandCycleString;
504 unsigned NOperandCycles = 0;
505 std::string ItinBypassString;
506 if (ItinData) {
507 FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
508 NOperandCycles);
509
510 FormItineraryBypassString(std::string(Name), ItinData, ItinBypassString,
511 NOperandCycles);
512 }
513
514 // Check to see if stage already exists and create if it doesn't
515 uint16_t FindStage = 0;
516 if (NStages > 0) {
517 FindStage = ItinStageMap[ItinStageString];
518 if (FindStage == 0) {
519 // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices
520 StageTable += ItinStageString + ", // " + itostr(StageCount);
521 if (NStages > 1)
522 StageTable += "-" + itostr(StageCount + NStages - 1);
523 StageTable += "\n";
524 // Record Itin class number.
525 ItinStageMap[ItinStageString] = FindStage = StageCount;
526 StageCount += NStages;
527 }
528 }
529
530 // Check to see if operand cycle already exists and create if it doesn't
531 uint16_t FindOperandCycle = 0;
532 if (NOperandCycles > 0) {
533 std::string ItinOperandString = ItinOperandCycleString+ItinBypassString;
534 FindOperandCycle = ItinOperandMap[ItinOperandString];
535 if (FindOperandCycle == 0) {
536 // Emit as cycle, // index
537 OperandCycleTable += ItinOperandCycleString + ", // ";
538 std::string OperandIdxComment = itostr(OperandCycleCount);
539 if (NOperandCycles > 1)
540 OperandIdxComment += "-"
541 + itostr(OperandCycleCount + NOperandCycles - 1);
542 OperandCycleTable += OperandIdxComment + "\n";
543 // Record Itin class number.
544 ItinOperandMap[ItinOperandCycleString] =
545 FindOperandCycle = OperandCycleCount;
546 // Emit as bypass, // index
547 BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";
548 OperandCycleCount += NOperandCycles;
549 }
550 }
551
552 // Set up itinerary as location and location + stage count
553 int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0;
554 InstrItinerary Intinerary = {
555 NumUOps,
556 FindStage,
557 uint16_t(FindStage + NStages),
558 FindOperandCycle,
559 uint16_t(FindOperandCycle + NOperandCycles),
560 };
561
562 // Inject - empty slots will be 0, 0
563 ItinList[SchedClassIdx] = Intinerary;
564 }
565 }
566
567 // Closing stage
568 StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n";
569 StageTable += "};\n";
570
571 // Closing operand cycles
572 OperandCycleTable += " 0 // End operand cycles\n";
573 OperandCycleTable += "};\n";
574
575 BypassTable += " 0 // End bypass tables\n";
576 BypassTable += "};\n";
577
578 // Emit tables.
579 OS << StageTable;
580 OS << OperandCycleTable;
581 OS << BypassTable;
582 }
583
584 //
585 // EmitProcessorData - Generate data for processor itineraries that were
586 // computed during EmitStageAndOperandCycleData(). ProcItinLists lists all
587 // Itineraries for each processor. The Itinerary lists are indexed on
588 // CodeGenSchedClass::Index.
589 //
590 void SubtargetEmitter::
EmitItineraries(raw_ostream & OS,std::vector<std::vector<InstrItinerary>> & ProcItinLists)591 EmitItineraries(raw_ostream &OS,
592 std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
593 // Multiple processor models may share an itinerary record. Emit it once.
594 SmallPtrSet<Record*, 8> ItinsDefSet;
595
596 // For each processor's machine model
597 std::vector<std::vector<InstrItinerary>>::iterator
598 ProcItinListsIter = ProcItinLists.begin();
599 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
600 PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) {
601
602 Record *ItinsDef = PI->ItinsDef;
603 if (!ItinsDefSet.insert(ItinsDef).second)
604 continue;
605
606 // Get the itinerary list for the processor.
607 assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator");
608 std::vector<InstrItinerary> &ItinList = *ProcItinListsIter;
609
610 // Empty itineraries aren't referenced anywhere in the tablegen output
611 // so don't emit them.
612 if (ItinList.empty())
613 continue;
614
615 OS << "\n";
616 OS << "static const llvm::InstrItinerary ";
617
618 // Begin processor itinerary table
619 OS << ItinsDef->getName() << "[] = {\n";
620
621 // For each itinerary class in CodeGenSchedClass::Index order.
622 for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {
623 InstrItinerary &Intinerary = ItinList[j];
624
625 // Emit Itinerary in the form of
626 // { firstStage, lastStage, firstCycle, lastCycle } // index
627 OS << " { " <<
628 Intinerary.NumMicroOps << ", " <<
629 Intinerary.FirstStage << ", " <<
630 Intinerary.LastStage << ", " <<
631 Intinerary.FirstOperandCycle << ", " <<
632 Intinerary.LastOperandCycle << " }" <<
633 ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
634 }
635 // End processor itinerary table
636 OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }"
637 "// end marker\n";
638 OS << "};\n";
639 }
640 }
641
642 // Emit either the value defined in the TableGen Record, or the default
643 // value defined in the C++ header. The Record is null if the processor does not
644 // define a model.
EmitProcessorProp(raw_ostream & OS,const Record * R,StringRef Name,char Separator)645 void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R,
646 StringRef Name, char Separator) {
647 OS << " ";
648 int V = R ? R->getValueAsInt(Name) : -1;
649 if (V >= 0)
650 OS << V << Separator << " // " << Name;
651 else
652 OS << "MCSchedModel::Default" << Name << Separator;
653 OS << '\n';
654 }
655
EmitProcessorResourceSubUnits(const CodeGenProcModel & ProcModel,raw_ostream & OS)656 void SubtargetEmitter::EmitProcessorResourceSubUnits(
657 const CodeGenProcModel &ProcModel, raw_ostream &OS) {
658 OS << "\nstatic const unsigned " << ProcModel.ModelName
659 << "ProcResourceSubUnits[] = {\n"
660 << " 0, // Invalid\n";
661
662 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
663 Record *PRDef = ProcModel.ProcResourceDefs[i];
664 if (!PRDef->isSubClassOf("ProcResGroup"))
665 continue;
666 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
667 for (Record *RUDef : ResUnits) {
668 Record *const RU =
669 SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc());
670 for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) {
671 OS << " " << ProcModel.getProcResourceIdx(RU) << ", ";
672 }
673 }
674 OS << " // " << PRDef->getName() << "\n";
675 }
676 OS << "};\n";
677 }
678
EmitRetireControlUnitInfo(const CodeGenProcModel & ProcModel,raw_ostream & OS)679 static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel,
680 raw_ostream &OS) {
681 int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0;
682 if (Record *RCU = ProcModel.RetireControlUnit) {
683 ReorderBufferSize =
684 std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize"));
685 MaxRetirePerCycle =
686 std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle"));
687 }
688
689 OS << ReorderBufferSize << ", // ReorderBufferSize\n ";
690 OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n ";
691 }
692
EmitRegisterFileInfo(const CodeGenProcModel & ProcModel,unsigned NumRegisterFiles,unsigned NumCostEntries,raw_ostream & OS)693 static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel,
694 unsigned NumRegisterFiles,
695 unsigned NumCostEntries, raw_ostream &OS) {
696 if (NumRegisterFiles)
697 OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles);
698 else
699 OS << "nullptr,\n 0";
700
701 OS << ", // Number of register files.\n ";
702 if (NumCostEntries)
703 OS << ProcModel.ModelName << "RegisterCosts,\n ";
704 else
705 OS << "nullptr,\n ";
706 OS << NumCostEntries << ", // Number of register cost entries.\n";
707 }
708
709 unsigned
EmitRegisterFileTables(const CodeGenProcModel & ProcModel,raw_ostream & OS)710 SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
711 raw_ostream &OS) {
712 if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) {
713 return RF.hasDefaultCosts();
714 }))
715 return 0;
716
717 // Print the RegisterCost table first.
718 OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n";
719 OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName
720 << "RegisterCosts"
721 << "[] = {\n";
722
723 for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) {
724 // Skip register files with a default cost table.
725 if (RF.hasDefaultCosts())
726 continue;
727 // Add entries to the cost table.
728 for (const CodeGenRegisterCost &RC : RF.Costs) {
729 OS << " { ";
730 Record *Rec = RC.RCDef;
731 if (Rec->getValue("Namespace"))
732 OS << Rec->getValueAsString("Namespace") << "::";
733 OS << Rec->getName() << "RegClassID, " << RC.Cost << ", "
734 << RC.AllowMoveElimination << "},\n";
735 }
736 }
737 OS << "};\n";
738
739 // Now generate a table with register file info.
740 OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, "
741 << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n";
742 OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName
743 << "RegisterFiles"
744 << "[] = {\n"
745 << " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n";
746 unsigned CostTblIndex = 0;
747
748 for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) {
749 OS << " { ";
750 OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", ";
751 unsigned NumCostEntries = RD.Costs.size();
752 OS << NumCostEntries << ", " << CostTblIndex << ", "
753 << RD.MaxMovesEliminatedPerCycle << ", "
754 << RD.AllowZeroMoveEliminationOnly << "},\n";
755 CostTblIndex += NumCostEntries;
756 }
757 OS << "};\n";
758
759 return CostTblIndex;
760 }
761
EmitLoadStoreQueueInfo(const CodeGenProcModel & ProcModel,raw_ostream & OS)762 void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
763 raw_ostream &OS) {
764 unsigned QueueID = 0;
765 if (ProcModel.LoadQueue) {
766 const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor");
767 QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
768 find(ProcModel.ProcResourceDefs, Queue));
769 }
770 OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n";
771
772 QueueID = 0;
773 if (ProcModel.StoreQueue) {
774 const Record *Queue =
775 ProcModel.StoreQueue->getValueAsDef("QueueDescriptor");
776 QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
777 find(ProcModel.ProcResourceDefs, Queue));
778 }
779 OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n";
780 }
781
EmitExtraProcessorInfo(const CodeGenProcModel & ProcModel,raw_ostream & OS)782 void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,
783 raw_ostream &OS) {
784 // Generate a table of register file descriptors (one entry per each user
785 // defined register file), and a table of register costs.
786 unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS);
787
788 // Now generate a table for the extra processor info.
789 OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName
790 << "ExtraInfo = {\n ";
791
792 // Add information related to the retire control unit.
793 EmitRetireControlUnitInfo(ProcModel, OS);
794
795 // Add information related to the register files (i.e. where to find register
796 // file descriptors and register costs).
797 EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(),
798 NumCostEntries, OS);
799
800 // Add information about load/store queues.
801 EmitLoadStoreQueueInfo(ProcModel, OS);
802
803 OS << "};\n";
804 }
805
EmitProcessorResources(const CodeGenProcModel & ProcModel,raw_ostream & OS)806 void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
807 raw_ostream &OS) {
808 EmitProcessorResourceSubUnits(ProcModel, OS);
809
810 OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n";
811 OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName
812 << "ProcResources"
813 << "[] = {\n"
814 << " {\"InvalidUnit\", 0, 0, 0, 0},\n";
815
816 unsigned SubUnitsOffset = 1;
817 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
818 Record *PRDef = ProcModel.ProcResourceDefs[i];
819
820 Record *SuperDef = nullptr;
821 unsigned SuperIdx = 0;
822 unsigned NumUnits = 0;
823 const unsigned SubUnitsBeginOffset = SubUnitsOffset;
824 int BufferSize = PRDef->getValueAsInt("BufferSize");
825 if (PRDef->isSubClassOf("ProcResGroup")) {
826 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
827 for (Record *RU : ResUnits) {
828 NumUnits += RU->getValueAsInt("NumUnits");
829 SubUnitsOffset += RU->getValueAsInt("NumUnits");
830 }
831 }
832 else {
833 // Find the SuperIdx
834 if (PRDef->getValueInit("Super")->isComplete()) {
835 SuperDef =
836 SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"),
837 ProcModel, PRDef->getLoc());
838 SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
839 }
840 NumUnits = PRDef->getValueAsInt("NumUnits");
841 }
842 // Emit the ProcResourceDesc
843 OS << " {\"" << PRDef->getName() << "\", ";
844 if (PRDef->getName().size() < 15)
845 OS.indent(15 - PRDef->getName().size());
846 OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", ";
847 if (SubUnitsBeginOffset != SubUnitsOffset) {
848 OS << ProcModel.ModelName << "ProcResourceSubUnits + "
849 << SubUnitsBeginOffset;
850 } else {
851 OS << "nullptr";
852 }
853 OS << "}, // #" << i+1;
854 if (SuperDef)
855 OS << ", Super=" << SuperDef->getName();
856 OS << "\n";
857 }
858 OS << "};\n";
859 }
860
861 // Find the WriteRes Record that defines processor resources for this
862 // SchedWrite.
FindWriteResources(const CodeGenSchedRW & SchedWrite,const CodeGenProcModel & ProcModel)863 Record *SubtargetEmitter::FindWriteResources(
864 const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) {
865
866 // Check if the SchedWrite is already subtarget-specific and directly
867 // specifies a set of processor resources.
868 if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))
869 return SchedWrite.TheDef;
870
871 Record *AliasDef = nullptr;
872 for (Record *A : SchedWrite.Aliases) {
873 const CodeGenSchedRW &AliasRW =
874 SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
875 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
876 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
877 if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
878 continue;
879 }
880 if (AliasDef)
881 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
882 "defined for processor " + ProcModel.ModelName +
883 " Ensure only one SchedAlias exists per RW.");
884 AliasDef = AliasRW.TheDef;
885 }
886 if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))
887 return AliasDef;
888
889 // Check this processor's list of write resources.
890 Record *ResDef = nullptr;
891 for (Record *WR : ProcModel.WriteResDefs) {
892 if (!WR->isSubClassOf("WriteRes"))
893 continue;
894 if (AliasDef == WR->getValueAsDef("WriteType")
895 || SchedWrite.TheDef == WR->getValueAsDef("WriteType")) {
896 if (ResDef) {
897 PrintFatalError(WR->getLoc(), "Resources are defined for both "
898 "SchedWrite and its alias on processor " +
899 ProcModel.ModelName);
900 }
901 ResDef = WR;
902 }
903 }
904 // TODO: If ProcModel has a base model (previous generation processor),
905 // then call FindWriteResources recursively with that model here.
906 if (!ResDef) {
907 PrintFatalError(ProcModel.ModelDef->getLoc(),
908 Twine("Processor does not define resources for ") +
909 SchedWrite.TheDef->getName());
910 }
911 return ResDef;
912 }
913
914 /// Find the ReadAdvance record for the given SchedRead on this processor or
915 /// return NULL.
FindReadAdvance(const CodeGenSchedRW & SchedRead,const CodeGenProcModel & ProcModel)916 Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
917 const CodeGenProcModel &ProcModel) {
918 // Check for SchedReads that directly specify a ReadAdvance.
919 if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))
920 return SchedRead.TheDef;
921
922 // Check this processor's list of aliases for SchedRead.
923 Record *AliasDef = nullptr;
924 for (Record *A : SchedRead.Aliases) {
925 const CodeGenSchedRW &AliasRW =
926 SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
927 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
928 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
929 if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
930 continue;
931 }
932 if (AliasDef)
933 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
934 "defined for processor " + ProcModel.ModelName +
935 " Ensure only one SchedAlias exists per RW.");
936 AliasDef = AliasRW.TheDef;
937 }
938 if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))
939 return AliasDef;
940
941 // Check this processor's ReadAdvanceList.
942 Record *ResDef = nullptr;
943 for (Record *RA : ProcModel.ReadAdvanceDefs) {
944 if (!RA->isSubClassOf("ReadAdvance"))
945 continue;
946 if (AliasDef == RA->getValueAsDef("ReadType")
947 || SchedRead.TheDef == RA->getValueAsDef("ReadType")) {
948 if (ResDef) {
949 PrintFatalError(RA->getLoc(), "Resources are defined for both "
950 "SchedRead and its alias on processor " +
951 ProcModel.ModelName);
952 }
953 ResDef = RA;
954 }
955 }
956 // TODO: If ProcModel has a base model (previous generation processor),
957 // then call FindReadAdvance recursively with that model here.
958 if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {
959 PrintFatalError(ProcModel.ModelDef->getLoc(),
960 Twine("Processor does not define resources for ") +
961 SchedRead.TheDef->getName());
962 }
963 return ResDef;
964 }
965
966 // Expand an explicit list of processor resources into a full list of implied
967 // resource groups and super resources that cover them.
ExpandProcResources(RecVec & PRVec,std::vector<int64_t> & Cycles,const CodeGenProcModel & PM)968 void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
969 std::vector<int64_t> &Cycles,
970 const CodeGenProcModel &PM) {
971 assert(PRVec.size() == Cycles.size() && "failed precondition");
972 for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
973 Record *PRDef = PRVec[i];
974 RecVec SubResources;
975 if (PRDef->isSubClassOf("ProcResGroup"))
976 SubResources = PRDef->getValueAsListOfDefs("Resources");
977 else {
978 SubResources.push_back(PRDef);
979 PRDef = SchedModels.findProcResUnits(PRDef, PM, PRDef->getLoc());
980 for (Record *SubDef = PRDef;
981 SubDef->getValueInit("Super")->isComplete();) {
982 if (SubDef->isSubClassOf("ProcResGroup")) {
983 // Disallow this for simplicitly.
984 PrintFatalError(SubDef->getLoc(), "Processor resource group "
985 " cannot be a super resources.");
986 }
987 Record *SuperDef =
988 SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM,
989 SubDef->getLoc());
990 PRVec.push_back(SuperDef);
991 Cycles.push_back(Cycles[i]);
992 SubDef = SuperDef;
993 }
994 }
995 for (Record *PR : PM.ProcResourceDefs) {
996 if (PR == PRDef || !PR->isSubClassOf("ProcResGroup"))
997 continue;
998 RecVec SuperResources = PR->getValueAsListOfDefs("Resources");
999 RecIter SubI = SubResources.begin(), SubE = SubResources.end();
1000 for( ; SubI != SubE; ++SubI) {
1001 if (!is_contained(SuperResources, *SubI)) {
1002 break;
1003 }
1004 }
1005 if (SubI == SubE) {
1006 PRVec.push_back(PR);
1007 Cycles.push_back(Cycles[i]);
1008 }
1009 }
1010 }
1011 }
1012
1013 // Generate the SchedClass table for this processor and update global
1014 // tables. Must be called for each processor in order.
GenSchedClassTables(const CodeGenProcModel & ProcModel,SchedClassTables & SchedTables)1015 void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
1016 SchedClassTables &SchedTables) {
1017 SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1);
1018 if (!ProcModel.hasInstrSchedModel())
1019 return;
1020
1021 std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back();
1022 LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n");
1023 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
1024 LLVM_DEBUG(SC.dump(&SchedModels));
1025
1026 SCTab.resize(SCTab.size() + 1);
1027 MCSchedClassDesc &SCDesc = SCTab.back();
1028 // SCDesc.Name is guarded by NDEBUG
1029 SCDesc.NumMicroOps = 0;
1030 SCDesc.BeginGroup = false;
1031 SCDesc.EndGroup = false;
1032 SCDesc.RetireOOO = false;
1033 SCDesc.WriteProcResIdx = 0;
1034 SCDesc.WriteLatencyIdx = 0;
1035 SCDesc.ReadAdvanceIdx = 0;
1036
1037 // A Variant SchedClass has no resources of its own.
1038 bool HasVariants = false;
1039 for (const CodeGenSchedTransition &CGT :
1040 make_range(SC.Transitions.begin(), SC.Transitions.end())) {
1041 if (CGT.ProcIndex == ProcModel.Index) {
1042 HasVariants = true;
1043 break;
1044 }
1045 }
1046 if (HasVariants) {
1047 SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;
1048 continue;
1049 }
1050
1051 // Determine if the SchedClass is actually reachable on this processor. If
1052 // not don't try to locate the processor resources, it will fail.
1053 // If ProcIndices contains 0, this class applies to all processors.
1054 assert(!SC.ProcIndices.empty() && "expect at least one procidx");
1055 if (SC.ProcIndices[0] != 0) {
1056 if (!is_contained(SC.ProcIndices, ProcModel.Index))
1057 continue;
1058 }
1059 IdxVec Writes = SC.Writes;
1060 IdxVec Reads = SC.Reads;
1061 if (!SC.InstRWs.empty()) {
1062 // This class has a default ReadWrite list which can be overridden by
1063 // InstRW definitions.
1064 Record *RWDef = nullptr;
1065 for (Record *RW : SC.InstRWs) {
1066 Record *RWModelDef = RW->getValueAsDef("SchedModel");
1067 if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {
1068 RWDef = RW;
1069 break;
1070 }
1071 }
1072 if (RWDef) {
1073 Writes.clear();
1074 Reads.clear();
1075 SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
1076 Writes, Reads);
1077 }
1078 }
1079 if (Writes.empty()) {
1080 // Check this processor's itinerary class resources.
1081 for (Record *I : ProcModel.ItinRWDefs) {
1082 RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses");
1083 if (is_contained(Matched, SC.ItinClassDef)) {
1084 SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"),
1085 Writes, Reads);
1086 break;
1087 }
1088 }
1089 if (Writes.empty()) {
1090 LLVM_DEBUG(dbgs() << ProcModel.ModelName
1091 << " does not have resources for class " << SC.Name
1092 << '\n');
1093 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1094 }
1095 }
1096 // Sum resources across all operand writes.
1097 std::vector<MCWriteProcResEntry> WriteProcResources;
1098 std::vector<MCWriteLatencyEntry> WriteLatencies;
1099 std::vector<std::string> WriterNames;
1100 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
1101 for (unsigned W : Writes) {
1102 IdxVec WriteSeq;
1103 SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false,
1104 ProcModel);
1105
1106 // For each operand, create a latency entry.
1107 MCWriteLatencyEntry WLEntry;
1108 WLEntry.Cycles = 0;
1109 unsigned WriteID = WriteSeq.back();
1110 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
1111 // If this Write is not referenced by a ReadAdvance, don't distinguish it
1112 // from other WriteLatency entries.
1113 if (!SchedModels.hasReadOfWrite(
1114 SchedModels.getSchedWrite(WriteID).TheDef)) {
1115 WriteID = 0;
1116 }
1117 WLEntry.WriteResourceID = WriteID;
1118
1119 for (unsigned WS : WriteSeq) {
1120
1121 Record *WriteRes =
1122 FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
1123
1124 // Mark the parent class as invalid for unsupported write types.
1125 if (WriteRes->getValueAsBit("Unsupported")) {
1126 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1127 break;
1128 }
1129 WLEntry.Cycles += WriteRes->getValueAsInt("Latency");
1130 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");
1131 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");
1132 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");
1133 SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue");
1134 SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue");
1135 SCDesc.RetireOOO |= WriteRes->getValueAsBit("RetireOOO");
1136
1137 // Create an entry for each ProcResource listed in WriteRes.
1138 RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
1139 std::vector<int64_t> Cycles =
1140 WriteRes->getValueAsListOfInts("ResourceCycles");
1141
1142 if (Cycles.empty()) {
1143 // If ResourceCycles is not provided, default to one cycle per
1144 // resource.
1145 Cycles.resize(PRVec.size(), 1);
1146 } else if (Cycles.size() != PRVec.size()) {
1147 // If ResourceCycles is provided, check consistency.
1148 PrintFatalError(
1149 WriteRes->getLoc(),
1150 Twine("Inconsistent resource cycles: !size(ResourceCycles) != "
1151 "!size(ProcResources): ")
1152 .concat(Twine(PRVec.size()))
1153 .concat(" vs ")
1154 .concat(Twine(Cycles.size())));
1155 }
1156
1157 ExpandProcResources(PRVec, Cycles, ProcModel);
1158
1159 for (unsigned PRIdx = 0, PREnd = PRVec.size();
1160 PRIdx != PREnd; ++PRIdx) {
1161 MCWriteProcResEntry WPREntry;
1162 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
1163 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
1164 WPREntry.Cycles = Cycles[PRIdx];
1165 // If this resource is already used in this sequence, add the current
1166 // entry's cycles so that the same resource appears to be used
1167 // serially, rather than multiple parallel uses. This is important for
1168 // in-order machine where the resource consumption is a hazard.
1169 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
1170 for( ; WPRIdx != WPREnd; ++WPRIdx) {
1171 if (WriteProcResources[WPRIdx].ProcResourceIdx
1172 == WPREntry.ProcResourceIdx) {
1173 WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
1174 break;
1175 }
1176 }
1177 if (WPRIdx == WPREnd)
1178 WriteProcResources.push_back(WPREntry);
1179 }
1180 }
1181 WriteLatencies.push_back(WLEntry);
1182 }
1183 // Create an entry for each operand Read in this SchedClass.
1184 // Entries must be sorted first by UseIdx then by WriteResourceID.
1185 for (unsigned UseIdx = 0, EndIdx = Reads.size();
1186 UseIdx != EndIdx; ++UseIdx) {
1187 Record *ReadAdvance =
1188 FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
1189 if (!ReadAdvance)
1190 continue;
1191
1192 // Mark the parent class as invalid for unsupported write types.
1193 if (ReadAdvance->getValueAsBit("Unsupported")) {
1194 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1195 break;
1196 }
1197 RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");
1198 IdxVec WriteIDs;
1199 if (ValidWrites.empty())
1200 WriteIDs.push_back(0);
1201 else {
1202 for (Record *VW : ValidWrites) {
1203 WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false));
1204 }
1205 }
1206 llvm::sort(WriteIDs);
1207 for(unsigned W : WriteIDs) {
1208 MCReadAdvanceEntry RAEntry;
1209 RAEntry.UseIdx = UseIdx;
1210 RAEntry.WriteResourceID = W;
1211 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
1212 ReadAdvanceEntries.push_back(RAEntry);
1213 }
1214 }
1215 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
1216 WriteProcResources.clear();
1217 WriteLatencies.clear();
1218 ReadAdvanceEntries.clear();
1219 }
1220 // Add the information for this SchedClass to the global tables using basic
1221 // compression.
1222 //
1223 // WritePrecRes entries are sorted by ProcResIdx.
1224 llvm::sort(WriteProcResources, LessWriteProcResources());
1225
1226 SCDesc.NumWriteProcResEntries = WriteProcResources.size();
1227 std::vector<MCWriteProcResEntry>::iterator WPRPos =
1228 std::search(SchedTables.WriteProcResources.begin(),
1229 SchedTables.WriteProcResources.end(),
1230 WriteProcResources.begin(), WriteProcResources.end());
1231 if (WPRPos != SchedTables.WriteProcResources.end())
1232 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
1233 else {
1234 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();
1235 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),
1236 WriteProcResources.end());
1237 }
1238 // Latency entries must remain in operand order.
1239 SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
1240 std::vector<MCWriteLatencyEntry>::iterator WLPos =
1241 std::search(SchedTables.WriteLatencies.begin(),
1242 SchedTables.WriteLatencies.end(),
1243 WriteLatencies.begin(), WriteLatencies.end());
1244 if (WLPos != SchedTables.WriteLatencies.end()) {
1245 unsigned idx = WLPos - SchedTables.WriteLatencies.begin();
1246 SCDesc.WriteLatencyIdx = idx;
1247 for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)
1248 if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==
1249 std::string::npos) {
1250 SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];
1251 }
1252 }
1253 else {
1254 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
1255 llvm::append_range(SchedTables.WriteLatencies, WriteLatencies);
1256 llvm::append_range(SchedTables.WriterNames, WriterNames);
1257 }
1258 // ReadAdvanceEntries must remain in operand order.
1259 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
1260 std::vector<MCReadAdvanceEntry>::iterator RAPos =
1261 std::search(SchedTables.ReadAdvanceEntries.begin(),
1262 SchedTables.ReadAdvanceEntries.end(),
1263 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
1264 if (RAPos != SchedTables.ReadAdvanceEntries.end())
1265 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
1266 else {
1267 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
1268 llvm::append_range(SchedTables.ReadAdvanceEntries, ReadAdvanceEntries);
1269 }
1270 }
1271 }
1272
1273 // Emit SchedClass tables for all processors and associated global tables.
EmitSchedClassTables(SchedClassTables & SchedTables,raw_ostream & OS)1274 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
1275 raw_ostream &OS) {
1276 // Emit global WriteProcResTable.
1277 OS << "\n// {ProcResourceIdx, Cycles}\n"
1278 << "extern const llvm::MCWriteProcResEntry "
1279 << Target << "WriteProcResTable[] = {\n"
1280 << " { 0, 0}, // Invalid\n";
1281 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
1282 WPRIdx != WPREnd; ++WPRIdx) {
1283 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
1284 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
1285 << format("%2d", WPREntry.Cycles) << "}";
1286 if (WPRIdx + 1 < WPREnd)
1287 OS << ',';
1288 OS << " // #" << WPRIdx << '\n';
1289 }
1290 OS << "}; // " << Target << "WriteProcResTable\n";
1291
1292 // Emit global WriteLatencyTable.
1293 OS << "\n// {Cycles, WriteResourceID}\n"
1294 << "extern const llvm::MCWriteLatencyEntry "
1295 << Target << "WriteLatencyTable[] = {\n"
1296 << " { 0, 0}, // Invalid\n";
1297 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
1298 WLIdx != WLEnd; ++WLIdx) {
1299 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
1300 OS << " {" << format("%2d", WLEntry.Cycles) << ", "
1301 << format("%2d", WLEntry.WriteResourceID) << "}";
1302 if (WLIdx + 1 < WLEnd)
1303 OS << ',';
1304 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
1305 }
1306 OS << "}; // " << Target << "WriteLatencyTable\n";
1307
1308 // Emit global ReadAdvanceTable.
1309 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
1310 << "extern const llvm::MCReadAdvanceEntry "
1311 << Target << "ReadAdvanceTable[] = {\n"
1312 << " {0, 0, 0}, // Invalid\n";
1313 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
1314 RAIdx != RAEnd; ++RAIdx) {
1315 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
1316 OS << " {" << RAEntry.UseIdx << ", "
1317 << format("%2d", RAEntry.WriteResourceID) << ", "
1318 << format("%2d", RAEntry.Cycles) << "}";
1319 if (RAIdx + 1 < RAEnd)
1320 OS << ',';
1321 OS << " // #" << RAIdx << '\n';
1322 }
1323 OS << "}; // " << Target << "ReadAdvanceTable\n";
1324
1325 // Emit a SchedClass table for each processor.
1326 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1327 PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1328 if (!PI->hasInstrSchedModel())
1329 continue;
1330
1331 std::vector<MCSchedClassDesc> &SCTab =
1332 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
1333
1334 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"
1335 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
1336 OS << "static const llvm::MCSchedClassDesc "
1337 << PI->ModelName << "SchedClasses[] = {\n";
1338
1339 // The first class is always invalid. We no way to distinguish it except by
1340 // name and position.
1341 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
1342 && "invalid class not first");
1343 OS << " {DBGFIELD(\"InvalidSchedClass\") "
1344 << MCSchedClassDesc::InvalidNumMicroOps
1345 << ", false, false, false, 0, 0, 0, 0, 0, 0},\n";
1346
1347 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
1348 MCSchedClassDesc &MCDesc = SCTab[SCIdx];
1349 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
1350 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";
1351 if (SchedClass.Name.size() < 18)
1352 OS.indent(18 - SchedClass.Name.size());
1353 OS << MCDesc.NumMicroOps
1354 << ", " << ( MCDesc.BeginGroup ? "true" : "false" )
1355 << ", " << ( MCDesc.EndGroup ? "true" : "false" )
1356 << ", " << ( MCDesc.RetireOOO ? "true" : "false" )
1357 << ", " << format("%2d", MCDesc.WriteProcResIdx)
1358 << ", " << MCDesc.NumWriteProcResEntries
1359 << ", " << format("%2d", MCDesc.WriteLatencyIdx)
1360 << ", " << MCDesc.NumWriteLatencyEntries
1361 << ", " << format("%2d", MCDesc.ReadAdvanceIdx)
1362 << ", " << MCDesc.NumReadAdvanceEntries
1363 << "}, // #" << SCIdx << '\n';
1364 }
1365 OS << "}; // " << PI->ModelName << "SchedClasses\n";
1366 }
1367 }
1368
EmitProcessorModels(raw_ostream & OS)1369 void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
1370 // For each processor model.
1371 for (const CodeGenProcModel &PM : SchedModels.procModels()) {
1372 // Emit extra processor info if available.
1373 if (PM.hasExtraProcessorInfo())
1374 EmitExtraProcessorInfo(PM, OS);
1375 // Emit processor resource table.
1376 if (PM.hasInstrSchedModel())
1377 EmitProcessorResources(PM, OS);
1378 else if(!PM.ProcResourceDefs.empty())
1379 PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines "
1380 "ProcResources without defining WriteRes SchedWriteRes");
1381
1382 // Begin processor itinerary properties
1383 OS << "\n";
1384 OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n";
1385 EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ',');
1386 EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ',');
1387 EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ',');
1388 EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ',');
1389 EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ',');
1390 EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');
1391
1392 bool PostRAScheduler =
1393 (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
1394
1395 OS << " " << (PostRAScheduler ? "true" : "false") << ", // "
1396 << "PostRAScheduler\n";
1397
1398 bool CompleteModel =
1399 (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
1400
1401 OS << " " << (CompleteModel ? "true" : "false") << ", // "
1402 << "CompleteModel\n";
1403
1404 OS << " " << PM.Index << ", // Processor ID\n";
1405 if (PM.hasInstrSchedModel())
1406 OS << " " << PM.ModelName << "ProcResources" << ",\n"
1407 << " " << PM.ModelName << "SchedClasses" << ",\n"
1408 << " " << PM.ProcResourceDefs.size()+1 << ",\n"
1409 << " " << (SchedModels.schedClassEnd()
1410 - SchedModels.schedClassBegin()) << ",\n";
1411 else
1412 OS << " nullptr, nullptr, 0, 0,"
1413 << " // No instruction-level machine model.\n";
1414 if (PM.hasItineraries())
1415 OS << " " << PM.ItinsDef->getName() << ",\n";
1416 else
1417 OS << " nullptr, // No Itinerary\n";
1418 if (PM.hasExtraProcessorInfo())
1419 OS << " &" << PM.ModelName << "ExtraInfo,\n";
1420 else
1421 OS << " nullptr // No extra processor descriptor\n";
1422 OS << "};\n";
1423 }
1424 }
1425
1426 //
1427 // EmitSchedModel - Emits all scheduling model tables, folding common patterns.
1428 //
EmitSchedModel(raw_ostream & OS)1429 void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
1430 OS << "#ifdef DBGFIELD\n"
1431 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n"
1432 << "#endif\n"
1433 << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n"
1434 << "#define DBGFIELD(x) x,\n"
1435 << "#else\n"
1436 << "#define DBGFIELD(x)\n"
1437 << "#endif\n";
1438
1439 if (SchedModels.hasItineraries()) {
1440 std::vector<std::vector<InstrItinerary>> ProcItinLists;
1441 // Emit the stage data
1442 EmitStageAndOperandCycleData(OS, ProcItinLists);
1443 EmitItineraries(OS, ProcItinLists);
1444 }
1445 OS << "\n// ===============================================================\n"
1446 << "// Data tables for the new per-operand machine model.\n";
1447
1448 SchedClassTables SchedTables;
1449 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
1450 GenSchedClassTables(ProcModel, SchedTables);
1451 }
1452 EmitSchedClassTables(SchedTables, OS);
1453
1454 OS << "\n#undef DBGFIELD\n";
1455
1456 // Emit the processor machine model
1457 EmitProcessorModels(OS);
1458 }
1459
emitPredicateProlog(const RecordKeeper & Records,raw_ostream & OS)1460 static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {
1461 std::string Buffer;
1462 raw_string_ostream Stream(Buffer);
1463
1464 // Collect all the PredicateProlog records and print them to the output
1465 // stream.
1466 std::vector<Record *> Prologs =
1467 Records.getAllDerivedDefinitions("PredicateProlog");
1468 llvm::sort(Prologs, LessRecord());
1469 for (Record *P : Prologs)
1470 Stream << P->getValueAsString("Code") << '\n';
1471
1472 OS << Buffer;
1473 }
1474
isTruePredicate(const Record * Rec)1475 static bool isTruePredicate(const Record *Rec) {
1476 return Rec->isSubClassOf("MCSchedPredicate") &&
1477 Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
1478 }
1479
emitPredicates(const CodeGenSchedTransition & T,const CodeGenSchedClass & SC,PredicateExpander & PE,raw_ostream & OS)1480 static void emitPredicates(const CodeGenSchedTransition &T,
1481 const CodeGenSchedClass &SC, PredicateExpander &PE,
1482 raw_ostream &OS) {
1483 std::string Buffer;
1484 raw_string_ostream SS(Buffer);
1485
1486 // If not all predicates are MCTrue, then we need an if-stmt.
1487 unsigned NumNonTruePreds =
1488 T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate);
1489
1490 SS.indent(PE.getIndentLevel() * 2);
1491
1492 if (NumNonTruePreds) {
1493 bool FirstNonTruePredicate = true;
1494 SS << "if (";
1495
1496 PE.setIndentLevel(PE.getIndentLevel() + 2);
1497
1498 for (const Record *Rec : T.PredTerm) {
1499 // Skip predicates that evaluate to "true".
1500 if (isTruePredicate(Rec))
1501 continue;
1502
1503 if (FirstNonTruePredicate) {
1504 FirstNonTruePredicate = false;
1505 } else {
1506 SS << "\n";
1507 SS.indent(PE.getIndentLevel() * 2);
1508 SS << "&& ";
1509 }
1510
1511 if (Rec->isSubClassOf("MCSchedPredicate")) {
1512 PE.expandPredicate(SS, Rec->getValueAsDef("Pred"));
1513 continue;
1514 }
1515
1516 // Expand this legacy predicate and wrap it around braces if there is more
1517 // than one predicate to expand.
1518 SS << ((NumNonTruePreds > 1) ? "(" : "")
1519 << Rec->getValueAsString("Predicate")
1520 << ((NumNonTruePreds > 1) ? ")" : "");
1521 }
1522
1523 SS << ")\n"; // end of if-stmt
1524 PE.decreaseIndentLevel();
1525 SS.indent(PE.getIndentLevel() * 2);
1526 PE.decreaseIndentLevel();
1527 }
1528
1529 SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n';
1530 OS << Buffer;
1531 }
1532
1533 // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate
1534 // epilogue code for the auto-generated helper.
emitSchedModelHelperEpilogue(raw_ostream & OS,bool ShouldReturnZero)1535 static void emitSchedModelHelperEpilogue(raw_ostream &OS,
1536 bool ShouldReturnZero) {
1537 if (ShouldReturnZero) {
1538 OS << " // Don't know how to resolve this scheduling class.\n"
1539 << " return 0;\n";
1540 return;
1541 }
1542
1543 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n";
1544 }
1545
hasMCSchedPredicates(const CodeGenSchedTransition & T)1546 static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
1547 return all_of(T.PredTerm, [](const Record *Rec) {
1548 return Rec->isSubClassOf("MCSchedPredicate");
1549 });
1550 }
1551
collectVariantClasses(const CodeGenSchedModels & SchedModels,IdxVec & VariantClasses,bool OnlyExpandMCInstPredicates)1552 static void collectVariantClasses(const CodeGenSchedModels &SchedModels,
1553 IdxVec &VariantClasses,
1554 bool OnlyExpandMCInstPredicates) {
1555 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
1556 // Ignore non-variant scheduling classes.
1557 if (SC.Transitions.empty())
1558 continue;
1559
1560 if (OnlyExpandMCInstPredicates) {
1561 // Ignore this variant scheduling class no transitions use any meaningful
1562 // MCSchedPredicate definitions.
1563 if (llvm::none_of(SC.Transitions, hasMCSchedPredicates))
1564 continue;
1565 }
1566
1567 VariantClasses.push_back(SC.Index);
1568 }
1569 }
1570
collectProcessorIndices(const CodeGenSchedClass & SC,IdxVec & ProcIndices)1571 static void collectProcessorIndices(const CodeGenSchedClass &SC,
1572 IdxVec &ProcIndices) {
1573 // A variant scheduling class may define transitions for multiple
1574 // processors. This function identifies wich processors are associated with
1575 // transition rules specified by variant class `SC`.
1576 for (const CodeGenSchedTransition &T : SC.Transitions) {
1577 IdxVec PI;
1578 std::set_union(&T.ProcIndex, &T.ProcIndex + 1, ProcIndices.begin(),
1579 ProcIndices.end(), std::back_inserter(PI));
1580 ProcIndices.swap(PI);
1581 }
1582 }
1583
isAlwaysTrue(const CodeGenSchedTransition & T)1584 static bool isAlwaysTrue(const CodeGenSchedTransition &T) {
1585 return llvm::all_of(T.PredTerm, isTruePredicate);
1586 }
1587
emitSchedModelHelpersImpl(raw_ostream & OS,bool OnlyExpandMCInstPredicates)1588 void SubtargetEmitter::emitSchedModelHelpersImpl(
1589 raw_ostream &OS, bool OnlyExpandMCInstPredicates) {
1590 IdxVec VariantClasses;
1591 collectVariantClasses(SchedModels, VariantClasses,
1592 OnlyExpandMCInstPredicates);
1593
1594 if (VariantClasses.empty()) {
1595 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
1596 return;
1597 }
1598
1599 // Construct a switch statement where the condition is a check on the
1600 // scheduling class identifier. There is a `case` for every variant class
1601 // defined by the processor models of this target.
1602 // Each `case` implements a number of rules to resolve (i.e. to transition from)
1603 // a variant scheduling class to another scheduling class. Rules are
1604 // described by instances of CodeGenSchedTransition. Note that transitions may
1605 // not be valid for all processors.
1606 OS << " switch (SchedClass) {\n";
1607 for (unsigned VC : VariantClasses) {
1608 IdxVec ProcIndices;
1609 const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC);
1610 collectProcessorIndices(SC, ProcIndices);
1611
1612 OS << " case " << VC << ": // " << SC.Name << '\n';
1613
1614 PredicateExpander PE(Target);
1615 PE.setByRef(false);
1616 PE.setExpandForMC(OnlyExpandMCInstPredicates);
1617 for (unsigned PI : ProcIndices) {
1618 OS << " ";
1619
1620 // Emit a guard on the processor ID.
1621 if (PI != 0) {
1622 OS << (OnlyExpandMCInstPredicates
1623 ? "if (CPUID == "
1624 : "if (SchedModel->getProcessorID() == ");
1625 OS << PI << ") ";
1626 OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n';
1627 }
1628
1629 // Now emit transitions associated with processor PI.
1630 const CodeGenSchedTransition *FinalT = nullptr;
1631 for (const CodeGenSchedTransition &T : SC.Transitions) {
1632 if (PI != 0 && T.ProcIndex != PI)
1633 continue;
1634
1635 // Emit only transitions based on MCSchedPredicate, if it's the case.
1636 // At least the transition specified by NoSchedPred is emitted,
1637 // which becomes the default transition for those variants otherwise
1638 // not based on MCSchedPredicate.
1639 // FIXME: preferably, llvm-mca should instead assume a reasonable
1640 // default when a variant transition is not based on MCSchedPredicate
1641 // for a given processor.
1642 if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))
1643 continue;
1644
1645 // If transition is folded to 'return X' it should be the last one.
1646 if (isAlwaysTrue(T)) {
1647 FinalT = &T;
1648 continue;
1649 }
1650 PE.setIndentLevel(3);
1651 emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);
1652 }
1653 if (FinalT)
1654 emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx),
1655 PE, OS);
1656
1657 OS << " }\n";
1658
1659 if (PI == 0)
1660 break;
1661 }
1662
1663 if (SC.isInferred())
1664 OS << " return " << SC.Index << ";\n";
1665 OS << " break;\n";
1666 }
1667
1668 OS << " };\n";
1669
1670 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
1671 }
1672
EmitSchedModelHelpers(const std::string & ClassName,raw_ostream & OS)1673 void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
1674 raw_ostream &OS) {
1675 OS << "unsigned " << ClassName
1676 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"
1677 << " const TargetSchedModel *SchedModel) const {\n";
1678
1679 // Emit the predicate prolog code.
1680 emitPredicateProlog(Records, OS);
1681
1682 // Emit target predicates.
1683 emitSchedModelHelpersImpl(OS);
1684
1685 OS << "} // " << ClassName << "::resolveSchedClass\n\n";
1686
1687 OS << "unsigned " << ClassName
1688 << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"
1689 << " const MCInstrInfo *MCII, unsigned CPUID) const {\n"
1690 << " return " << Target << "_MC"
1691 << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"
1692 << "} // " << ClassName << "::resolveVariantSchedClass\n\n";
1693
1694 STIPredicateExpander PE(Target);
1695 PE.setClassPrefix(ClassName);
1696 PE.setExpandDefinition(true);
1697 PE.setByRef(false);
1698 PE.setIndentLevel(0);
1699
1700 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1701 PE.expandSTIPredicate(OS, Fn);
1702 }
1703
EmitHwModeCheck(const std::string & ClassName,raw_ostream & OS)1704 void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
1705 raw_ostream &OS) {
1706 const CodeGenHwModes &CGH = TGT.getHwModes();
1707 assert(CGH.getNumModeIds() > 0);
1708 if (CGH.getNumModeIds() == 1)
1709 return;
1710
1711 OS << "unsigned " << ClassName << "::getHwMode() const {\n";
1712 for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
1713 const HwMode &HM = CGH.getMode(M);
1714 OS << " if (checkFeatures(\"" << HM.Features
1715 << "\")) return " << M << ";\n";
1716 }
1717 OS << " return 0;\n}\n";
1718 }
1719
1720 // Produces a subtarget specific function for parsing
1721 // the subtarget features string.
ParseFeaturesFunction(raw_ostream & OS)1722 void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
1723 std::vector<Record*> Features =
1724 Records.getAllDerivedDefinitions("SubtargetFeature");
1725 llvm::sort(Features, LessRecord());
1726
1727 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
1728 << "// subtarget options.\n"
1729 << "void llvm::";
1730 OS << Target;
1731 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, "
1732 << "StringRef FS) {\n"
1733 << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
1734 << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n"
1735 << " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n";
1736
1737 if (Features.empty()) {
1738 OS << "}\n";
1739 return;
1740 }
1741
1742 OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n"
1743 << " const FeatureBitset &Bits = getFeatureBits();\n";
1744
1745 for (Record *R : Features) {
1746 // Next record
1747 StringRef Instance = R->getName();
1748 StringRef Value = R->getValueAsString("Value");
1749 StringRef Attribute = R->getValueAsString("Attribute");
1750
1751 if (Value=="true" || Value=="false")
1752 OS << " if (Bits[" << Target << "::"
1753 << Instance << "]) "
1754 << Attribute << " = " << Value << ";\n";
1755 else
1756 OS << " if (Bits[" << Target << "::"
1757 << Instance << "] && "
1758 << Attribute << " < " << Value << ") "
1759 << Attribute << " = " << Value << ";\n";
1760 }
1761
1762 OS << "}\n";
1763 }
1764
emitGenMCSubtargetInfo(raw_ostream & OS)1765 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
1766 OS << "namespace " << Target << "_MC {\n"
1767 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
1768 << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n";
1769 emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
1770 OS << "}\n";
1771 OS << "} // end namespace " << Target << "_MC\n\n";
1772
1773 OS << "struct " << Target
1774 << "GenMCSubtargetInfo : public MCSubtargetInfo {\n";
1775 OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT,\n"
1776 << " StringRef CPU, StringRef TuneCPU, StringRef FS,\n"
1777 << " ArrayRef<SubtargetFeatureKV> PF,\n"
1778 << " ArrayRef<SubtargetSubTypeKV> PD,\n"
1779 << " const MCWriteProcResEntry *WPR,\n"
1780 << " const MCWriteLatencyEntry *WL,\n"
1781 << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n"
1782 << " const unsigned *OC, const unsigned *FP) :\n"
1783 << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n"
1784 << " WPR, WL, RA, IS, OC, FP) { }\n\n"
1785 << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
1786 << " const MCInst *MI, const MCInstrInfo *MCII,\n"
1787 << " unsigned CPUID) const override {\n"
1788 << " return " << Target << "_MC"
1789 << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n";
1790 OS << " }\n";
1791 if (TGT.getHwModes().getNumModeIds() > 1)
1792 OS << " unsigned getHwMode() const override;\n";
1793 OS << "};\n";
1794 EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
1795 }
1796
EmitMCInstrAnalysisPredicateFunctions(raw_ostream & OS)1797 void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) {
1798 OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n";
1799 OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
1800
1801 STIPredicateExpander PE(Target);
1802 PE.setExpandForMC(true);
1803 PE.setByRef(true);
1804 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1805 PE.expandSTIPredicate(OS, Fn);
1806
1807 OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
1808
1809 OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n";
1810 OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
1811
1812 std::string ClassPrefix = Target + "MCInstrAnalysis";
1813 PE.setExpandDefinition(true);
1814 PE.setClassPrefix(ClassPrefix);
1815 PE.setIndentLevel(0);
1816 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1817 PE.expandSTIPredicate(OS, Fn);
1818
1819 OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
1820 }
1821
1822 //
1823 // SubtargetEmitter::run - Main subtarget enumeration emitter.
1824 //
run(raw_ostream & OS)1825 void SubtargetEmitter::run(raw_ostream &OS) {
1826 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
1827
1828 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
1829 OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";
1830
1831 DenseMap<Record *, unsigned> FeatureMap;
1832
1833 OS << "namespace llvm {\n";
1834 Enumeration(OS, FeatureMap);
1835 OS << "} // end namespace llvm\n\n";
1836 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
1837
1838 EmitSubtargetInfoMacroCalls(OS);
1839
1840 OS << "namespace llvm {\n";
1841 #if 0
1842 OS << "namespace {\n";
1843 #endif
1844 unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap);
1845 OS << "\n";
1846 EmitSchedModel(OS);
1847 OS << "\n";
1848 unsigned NumProcs = CPUKeyValues(OS, FeatureMap);
1849 OS << "\n";
1850 #if 0
1851 OS << "} // end anonymous namespace\n\n";
1852 #endif
1853
1854 // MCInstrInfo initialization routine.
1855 emitGenMCSubtargetInfo(OS);
1856
1857 OS << "\nstatic inline MCSubtargetInfo *create" << Target
1858 << "MCSubtargetInfoImpl("
1859 << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n";
1860 OS << " return new " << Target
1861 << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, ";
1862 if (NumFeatures)
1863 OS << Target << "FeatureKV, ";
1864 else
1865 OS << "std::nullopt, ";
1866 if (NumProcs)
1867 OS << Target << "SubTypeKV, ";
1868 else
1869 OS << "None, ";
1870 OS << '\n'; OS.indent(22);
1871 OS << Target << "WriteProcResTable, "
1872 << Target << "WriteLatencyTable, "
1873 << Target << "ReadAdvanceTable, ";
1874 OS << '\n'; OS.indent(22);
1875 if (SchedModels.hasItineraries()) {
1876 OS << Target << "Stages, "
1877 << Target << "OperandCycles, "
1878 << Target << "ForwardingPaths";
1879 } else
1880 OS << "nullptr, nullptr, nullptr";
1881 OS << ");\n}\n\n";
1882
1883 OS << "} // end namespace llvm\n\n";
1884
1885 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
1886
1887 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
1888 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";
1889
1890 OS << "#include \"llvm/Support/Debug.h\"\n";
1891 OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";
1892 ParseFeaturesFunction(OS);
1893
1894 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
1895
1896 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
1897 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
1898 OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";
1899
1900 std::string ClassName = Target + "GenSubtargetInfo";
1901 OS << "namespace llvm {\n";
1902 OS << "class DFAPacketizer;\n";
1903 OS << "namespace " << Target << "_MC {\n"
1904 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
1905 << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n"
1906 << "} // end namespace " << Target << "_MC\n\n";
1907 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
1908 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
1909 << "StringRef TuneCPU, StringRef FS);\n"
1910 << "public:\n"
1911 << " unsigned resolveSchedClass(unsigned SchedClass, "
1912 << " const MachineInstr *DefMI,"
1913 << " const TargetSchedModel *SchedModel) const override;\n"
1914 << " unsigned resolveVariantSchedClass(unsigned SchedClass,"
1915 << " const MCInst *MI, const MCInstrInfo *MCII,"
1916 << " unsigned CPUID) const override;\n"
1917 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
1918 << " const;\n";
1919 if (TGT.getHwModes().getNumModeIds() > 1)
1920 OS << " unsigned getHwMode() const override;\n";
1921
1922 STIPredicateExpander PE(Target);
1923 PE.setByRef(false);
1924 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1925 PE.expandSTIPredicate(OS, Fn);
1926
1927 OS << "};\n"
1928 << "} // end namespace llvm\n\n";
1929
1930 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
1931
1932 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
1933 OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";
1934
1935 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
1936 OS << "namespace llvm {\n";
1937 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
1938 OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
1939 OS << "extern const llvm::MCWriteProcResEntry "
1940 << Target << "WriteProcResTable[];\n";
1941 OS << "extern const llvm::MCWriteLatencyEntry "
1942 << Target << "WriteLatencyTable[];\n";
1943 OS << "extern const llvm::MCReadAdvanceEntry "
1944 << Target << "ReadAdvanceTable[];\n";
1945
1946 if (SchedModels.hasItineraries()) {
1947 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
1948 OS << "extern const unsigned " << Target << "OperandCycles[];\n";
1949 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
1950 }
1951
1952 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
1953 << "StringRef TuneCPU, StringRef FS)\n"
1954 << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
1955 if (NumFeatures)
1956 OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
1957 else
1958 OS << "std::nullopt, ";
1959 if (NumProcs)
1960 OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
1961 else
1962 OS << "None, ";
1963 OS << '\n'; OS.indent(24);
1964 OS << Target << "WriteProcResTable, "
1965 << Target << "WriteLatencyTable, "
1966 << Target << "ReadAdvanceTable, ";
1967 OS << '\n'; OS.indent(24);
1968 if (SchedModels.hasItineraries()) {
1969 OS << Target << "Stages, "
1970 << Target << "OperandCycles, "
1971 << Target << "ForwardingPaths";
1972 } else
1973 OS << "nullptr, nullptr, nullptr";
1974 OS << ") {}\n\n";
1975
1976 EmitSchedModelHelpers(ClassName, OS);
1977 EmitHwModeCheck(ClassName, OS);
1978
1979 OS << "} // end namespace llvm\n\n";
1980
1981 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
1982
1983 EmitMCInstrAnalysisPredicateFunctions(OS);
1984 }
1985
1986 namespace llvm {
1987
EmitSubtarget(RecordKeeper & RK,raw_ostream & OS)1988 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
1989 CodeGenTarget CGTarget(RK);
1990 SubtargetEmitter(RK, CGTarget).run(OS);
1991 }
1992
1993 } // end namespace llvm
1994