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