xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/SubtargetEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This tablegen backend emits subtarget enumerations.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "Common/CodeGenHwModes.h"
14*0fca6ea1SDimitry Andric #include "Common/CodeGenSchedule.h"
15*0fca6ea1SDimitry Andric #include "Common/CodeGenTarget.h"
16*0fca6ea1SDimitry Andric #include "Common/PredicateExpander.h"
170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
1806c3fb27SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCInstrItineraries.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCSchedule.h"
230b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
240b57cec5SDimitry Andric #include "llvm/Support/Format.h"
250b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
260b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
270b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
280b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
2906c3fb27SDimitry Andric #include "llvm/TargetParser/SubtargetFeature.h"
300b57cec5SDimitry Andric #include <algorithm>
310b57cec5SDimitry Andric #include <cassert>
320b57cec5SDimitry Andric #include <cstdint>
330b57cec5SDimitry Andric #include <iterator>
340b57cec5SDimitry Andric #include <map>
35*0fca6ea1SDimitry Andric #include <set>
360b57cec5SDimitry Andric #include <string>
370b57cec5SDimitry Andric #include <vector>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace llvm;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric #define DEBUG_TYPE "subtarget-emitter"
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric namespace {
440b57cec5SDimitry Andric 
4506c3fb27SDimitry Andric /// Sorting predicate to sort record pointers by their
4606c3fb27SDimitry Andric /// FieldName field.
4706c3fb27SDimitry Andric struct LessRecordFieldFieldName {
4806c3fb27SDimitry Andric   bool operator()(const Record *Rec1, const Record *Rec2) const {
4906c3fb27SDimitry Andric     return Rec1->getValueAsString("FieldName") <
5006c3fb27SDimitry Andric            Rec2->getValueAsString("FieldName");
5106c3fb27SDimitry Andric   }
5206c3fb27SDimitry Andric };
5306c3fb27SDimitry Andric 
540b57cec5SDimitry Andric class SubtargetEmitter {
55*0fca6ea1SDimitry Andric   // Each processor has a SchedClassDesc table with an entry for each
56*0fca6ea1SDimitry Andric   // SchedClass. The SchedClassDesc table indexes into a global write resource
57*0fca6ea1SDimitry Andric   // table, write latency table, and read advance table.
580b57cec5SDimitry Andric   struct SchedClassTables {
590b57cec5SDimitry Andric     std::vector<std::vector<MCSchedClassDesc>> ProcSchedClasses;
600b57cec5SDimitry Andric     std::vector<MCWriteProcResEntry> WriteProcResources;
610b57cec5SDimitry Andric     std::vector<MCWriteLatencyEntry> WriteLatencies;
620b57cec5SDimitry Andric     std::vector<std::string> WriterNames;
630b57cec5SDimitry Andric     std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric     // Reserve an invalid entry at index 0
660b57cec5SDimitry Andric     SchedClassTables() {
670b57cec5SDimitry Andric       ProcSchedClasses.resize(1);
680b57cec5SDimitry Andric       WriteProcResources.resize(1);
690b57cec5SDimitry Andric       WriteLatencies.resize(1);
700b57cec5SDimitry Andric       WriterNames.push_back("InvalidWrite");
710b57cec5SDimitry Andric       ReadAdvanceEntries.resize(1);
720b57cec5SDimitry Andric     }
730b57cec5SDimitry Andric   };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   struct LessWriteProcResources {
760b57cec5SDimitry Andric     bool operator()(const MCWriteProcResEntry &LHS,
770b57cec5SDimitry Andric                     const MCWriteProcResEntry &RHS) {
780b57cec5SDimitry Andric       return LHS.ProcResourceIdx < RHS.ProcResourceIdx;
790b57cec5SDimitry Andric     }
800b57cec5SDimitry Andric   };
810b57cec5SDimitry Andric 
8206c3fb27SDimitry Andric   CodeGenTarget TGT;
830b57cec5SDimitry Andric   RecordKeeper &Records;
840b57cec5SDimitry Andric   CodeGenSchedModels &SchedModels;
850b57cec5SDimitry Andric   std::string Target;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   void Enumeration(raw_ostream &OS, DenseMap<Record *, unsigned> &FeatureMap);
8881ad6265SDimitry Andric   void EmitSubtargetInfoMacroCalls(raw_ostream &OS);
890b57cec5SDimitry Andric   unsigned FeatureKeyValues(raw_ostream &OS,
900b57cec5SDimitry Andric                             const DenseMap<Record *, unsigned> &FeatureMap);
910b57cec5SDimitry Andric   unsigned CPUKeyValues(raw_ostream &OS,
920b57cec5SDimitry Andric                         const DenseMap<Record *, unsigned> &FeatureMap);
93*0fca6ea1SDimitry Andric   void FormItineraryStageString(const std::string &Names, Record *ItinData,
94*0fca6ea1SDimitry Andric                                 std::string &ItinString, unsigned &NStages);
95*0fca6ea1SDimitry Andric   void FormItineraryOperandCycleString(Record *ItinData,
96*0fca6ea1SDimitry Andric                                        std::string &ItinString,
970b57cec5SDimitry Andric                                        unsigned &NOperandCycles);
98*0fca6ea1SDimitry Andric   void FormItineraryBypassString(const std::string &Names, Record *ItinData,
99*0fca6ea1SDimitry Andric                                  std::string &ItinString,
100*0fca6ea1SDimitry Andric                                  unsigned NOperandCycles);
101*0fca6ea1SDimitry Andric   void EmitStageAndOperandCycleData(
102*0fca6ea1SDimitry Andric       raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists);
1030b57cec5SDimitry Andric   void EmitItineraries(raw_ostream &OS,
104*0fca6ea1SDimitry Andric                        std::vector<std::vector<InstrItinerary>> &ProcItinLists);
1050b57cec5SDimitry Andric   unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
1060b57cec5SDimitry Andric                                   raw_ostream &OS);
1070b57cec5SDimitry Andric   void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
1080b57cec5SDimitry Andric                               raw_ostream &OS);
1090b57cec5SDimitry Andric   void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,
1100b57cec5SDimitry Andric                               raw_ostream &OS);
1110b57cec5SDimitry Andric   void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name,
1120b57cec5SDimitry Andric                          char Separator);
1130b57cec5SDimitry Andric   void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel,
1140b57cec5SDimitry Andric                                      raw_ostream &OS);
1150b57cec5SDimitry Andric   void EmitProcessorResources(const CodeGenProcModel &ProcModel,
1160b57cec5SDimitry Andric                               raw_ostream &OS);
1170b57cec5SDimitry Andric   Record *FindWriteResources(const CodeGenSchedRW &SchedWrite,
1180b57cec5SDimitry Andric                              const CodeGenProcModel &ProcModel);
1190b57cec5SDimitry Andric   Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
1200b57cec5SDimitry Andric                           const CodeGenProcModel &ProcModel);
1215f757f3fSDimitry Andric   void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &ReleaseAtCycles,
1225f757f3fSDimitry Andric                            std::vector<int64_t> &AcquireAtCycles,
1230b57cec5SDimitry Andric                            const CodeGenProcModel &ProcModel);
1240b57cec5SDimitry Andric   void GenSchedClassTables(const CodeGenProcModel &ProcModel,
1250b57cec5SDimitry Andric                            SchedClassTables &SchedTables);
1260b57cec5SDimitry Andric   void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
1270b57cec5SDimitry Andric   void EmitProcessorModels(raw_ostream &OS);
1280b57cec5SDimitry Andric   void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS);
1290b57cec5SDimitry Andric   void emitSchedModelHelpersImpl(raw_ostream &OS,
1300b57cec5SDimitry Andric                                  bool OnlyExpandMCInstPredicates = false);
1310b57cec5SDimitry Andric   void emitGenMCSubtargetInfo(raw_ostream &OS);
1320b57cec5SDimitry Andric   void EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   void EmitSchedModel(raw_ostream &OS);
1357a6dacacSDimitry Andric   void emitGetMacroFusions(const std::string &ClassName, raw_ostream &OS);
1360b57cec5SDimitry Andric   void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS);
13781ad6265SDimitry Andric   void ParseFeaturesFunction(raw_ostream &OS);
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric public:
14006c3fb27SDimitry Andric   SubtargetEmitter(RecordKeeper &R)
14106c3fb27SDimitry Andric       : TGT(R), Records(R), SchedModels(TGT.getSchedModels()),
1420b57cec5SDimitry Andric         Target(TGT.getName()) {}
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   void run(raw_ostream &o);
1450b57cec5SDimitry Andric };
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric } // end anonymous namespace
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric //
1500b57cec5SDimitry Andric // Enumeration - Emit the specified class as an enumeration.
1510b57cec5SDimitry Andric //
1520b57cec5SDimitry Andric void SubtargetEmitter::Enumeration(raw_ostream &OS,
1530b57cec5SDimitry Andric                                    DenseMap<Record *, unsigned> &FeatureMap) {
1540b57cec5SDimitry Andric   // Get all records of class and sort
1550b57cec5SDimitry Andric   std::vector<Record *> DefList =
1560b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("SubtargetFeature");
1570b57cec5SDimitry Andric   llvm::sort(DefList, LessRecord());
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   unsigned N = DefList.size();
1600b57cec5SDimitry Andric   if (N == 0)
1610b57cec5SDimitry Andric     return;
1620b57cec5SDimitry Andric   if (N + 1 > MAX_SUBTARGET_FEATURES)
163*0fca6ea1SDimitry Andric     PrintFatalError(
164*0fca6ea1SDimitry Andric         "Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   OS << "namespace " << Target << " {\n";
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   // Open enumeration.
1690b57cec5SDimitry Andric   OS << "enum {\n";
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   // For each record
1720b57cec5SDimitry Andric   for (unsigned i = 0; i < N; ++i) {
1730b57cec5SDimitry Andric     // Next record
1740b57cec5SDimitry Andric     Record *Def = DefList[i];
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     // Get and emit name
1770b57cec5SDimitry Andric     OS << "  " << Def->getName() << " = " << i << ",\n";
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric     // Save the index for this feature.
1800b57cec5SDimitry Andric     FeatureMap[Def] = i;
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   OS << "  "
1840b57cec5SDimitry Andric      << "NumSubtargetFeatures = " << N << "\n";
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   // Close enumeration and namespace
1870b57cec5SDimitry Andric   OS << "};\n";
1880b57cec5SDimitry Andric   OS << "} // end namespace " << Target << "\n";
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList,
1920b57cec5SDimitry Andric                              const DenseMap<Record *, unsigned> &FeatureMap) {
1930b57cec5SDimitry Andric   std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
194fe6060f1SDimitry Andric   for (const Record *Feature : FeatureList) {
195fe6060f1SDimitry Andric     unsigned Bit = FeatureMap.lookup(Feature);
1960b57cec5SDimitry Andric     Mask[Bit / 64] |= 1ULL << (Bit % 64);
1970b57cec5SDimitry Andric   }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   OS << "{ { { ";
2000b57cec5SDimitry Andric   for (unsigned i = 0; i != Mask.size(); ++i) {
2010b57cec5SDimitry Andric     OS << "0x";
2020b57cec5SDimitry Andric     OS.write_hex(Mask[i]);
2030b57cec5SDimitry Andric     OS << "ULL, ";
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   OS << "} } }";
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
20881ad6265SDimitry Andric /// Emit some information about the SubtargetFeature as calls to a macro so
20981ad6265SDimitry Andric /// that they can be used from C++.
21081ad6265SDimitry Andric void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) {
21181ad6265SDimitry Andric   OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n";
21281ad6265SDimitry Andric 
21381ad6265SDimitry Andric   std::vector<Record *> FeatureList =
21481ad6265SDimitry Andric       Records.getAllDerivedDefinitions("SubtargetFeature");
21506c3fb27SDimitry Andric   llvm::sort(FeatureList, LessRecordFieldFieldName());
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric   for (const Record *Feature : FeatureList) {
21806c3fb27SDimitry Andric     const StringRef FieldName = Feature->getValueAsString("FieldName");
21981ad6265SDimitry Andric     const StringRef Value = Feature->getValueAsString("Value");
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric     // Only handle boolean features for now, excluding BitVectors and enums.
22281ad6265SDimitry Andric     const bool IsBool = (Value == "false" || Value == "true") &&
22306c3fb27SDimitry Andric                         !StringRef(FieldName).contains('[');
22481ad6265SDimitry Andric     if (!IsBool)
22581ad6265SDimitry Andric       continue;
22681ad6265SDimitry Andric 
22781ad6265SDimitry Andric     // Some features default to true, with values set to false if enabled.
22881ad6265SDimitry Andric     const char *Default = Value == "false" ? "true" : "false";
22981ad6265SDimitry Andric 
23081ad6265SDimitry Andric     // Define the getter with lowercased first char: xxxYyy() { return XxxYyy; }
23181ad6265SDimitry Andric     const std::string Getter =
23206c3fb27SDimitry Andric         FieldName.substr(0, 1).lower() + FieldName.substr(1).str();
23381ad6265SDimitry Andric 
23406c3fb27SDimitry Andric     OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", "
23581ad6265SDimitry Andric        << Getter << ")\n";
23681ad6265SDimitry Andric   }
23781ad6265SDimitry Andric   OS << "#undef GET_SUBTARGETINFO_MACRO\n";
23881ad6265SDimitry Andric   OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n";
23981ad6265SDimitry Andric 
24081ad6265SDimitry Andric   OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
24181ad6265SDimitry Andric   OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";
242*0fca6ea1SDimitry Andric 
243*0fca6ea1SDimitry Andric   if (Target == "AArch64")
244*0fca6ea1SDimitry Andric     OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
24581ad6265SDimitry Andric }
24681ad6265SDimitry Andric 
2470b57cec5SDimitry Andric //
2480b57cec5SDimitry Andric // FeatureKeyValues - Emit data of all the subtarget features.  Used by the
2490b57cec5SDimitry Andric // command line.
2500b57cec5SDimitry Andric //
2510b57cec5SDimitry Andric unsigned SubtargetEmitter::FeatureKeyValues(
2520b57cec5SDimitry Andric     raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap) {
2530b57cec5SDimitry Andric   // Gather and sort all the features
2540b57cec5SDimitry Andric   std::vector<Record *> FeatureList =
2550b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("SubtargetFeature");
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   if (FeatureList.empty())
2580b57cec5SDimitry Andric     return 0;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   llvm::sort(FeatureList, LessRecordFieldName());
2610b57cec5SDimitry Andric 
262*0fca6ea1SDimitry Andric   // Check that there are no duplicate keys
263*0fca6ea1SDimitry Andric   std::set<StringRef> UniqueKeys;
264*0fca6ea1SDimitry Andric 
2650b57cec5SDimitry Andric   // Begin feature table
2660b57cec5SDimitry Andric   OS << "// Sorted (by key) array of values for CPU features.\n"
2670b57cec5SDimitry Andric      << "extern const llvm::SubtargetFeatureKV " << Target
2680b57cec5SDimitry Andric      << "FeatureKV[] = {\n";
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // For each feature
2710b57cec5SDimitry Andric   unsigned NumFeatures = 0;
272fe6060f1SDimitry Andric   for (const Record *Feature : FeatureList) {
2730b57cec5SDimitry Andric     // Next feature
2740b57cec5SDimitry Andric     StringRef Name = Feature->getName();
2750b57cec5SDimitry Andric     StringRef CommandLineName = Feature->getValueAsString("Name");
2760b57cec5SDimitry Andric     StringRef Desc = Feature->getValueAsString("Desc");
2770b57cec5SDimitry Andric 
278*0fca6ea1SDimitry Andric     if (CommandLineName.empty())
279*0fca6ea1SDimitry Andric       continue;
2800b57cec5SDimitry Andric 
281*0fca6ea1SDimitry Andric     // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in
282*0fca6ea1SDimitry Andric     // } }
2830b57cec5SDimitry Andric     OS << "  { "
2840b57cec5SDimitry Andric        << "\"" << CommandLineName << "\", "
285*0fca6ea1SDimitry Andric        << "\"" << Desc << "\", " << Target << "::" << Name << ", ";
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric     RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric     printFeatureMask(OS, ImpliesList, FeatureMap);
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric     OS << " },\n";
2920b57cec5SDimitry Andric     ++NumFeatures;
293*0fca6ea1SDimitry Andric 
294*0fca6ea1SDimitry Andric     if (!UniqueKeys.insert(CommandLineName).second)
295*0fca6ea1SDimitry Andric       PrintFatalError("Duplicate key in SubtargetFeatureKV: " +
296*0fca6ea1SDimitry Andric                       CommandLineName);
2970b57cec5SDimitry Andric   }
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   // End feature table
3000b57cec5SDimitry Andric   OS << "};\n";
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   return NumFeatures;
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric //
3060b57cec5SDimitry Andric // CPUKeyValues - Emit data of all the subtarget processors.  Used by command
3070b57cec5SDimitry Andric // line.
3080b57cec5SDimitry Andric //
3090b57cec5SDimitry Andric unsigned
3100b57cec5SDimitry Andric SubtargetEmitter::CPUKeyValues(raw_ostream &OS,
3110b57cec5SDimitry Andric                                const DenseMap<Record *, unsigned> &FeatureMap) {
3120b57cec5SDimitry Andric   // Gather and sort processor information
3130b57cec5SDimitry Andric   std::vector<Record *> ProcessorList =
3140b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("Processor");
3150b57cec5SDimitry Andric   llvm::sort(ProcessorList, LessRecordFieldName());
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   // Begin processor table
3180b57cec5SDimitry Andric   OS << "// Sorted (by key) array of values for CPU subtype.\n"
3190b57cec5SDimitry Andric      << "extern const llvm::SubtargetSubTypeKV " << Target
3200b57cec5SDimitry Andric      << "SubTypeKV[] = {\n";
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric   // For each processor
3230b57cec5SDimitry Andric   for (Record *Processor : ProcessorList) {
3240b57cec5SDimitry Andric     StringRef Name = Processor->getValueAsString("Name");
3250b57cec5SDimitry Andric     RecVec FeatureList = Processor->getValueAsListOfDefs("Features");
326e8d8bef9SDimitry Andric     RecVec TuneFeatureList = Processor->getValueAsListOfDefs("TuneFeatures");
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric     // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } },
3290b57cec5SDimitry Andric     OS << " { "
3300b57cec5SDimitry Andric        << "\"" << Name << "\", ";
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric     printFeatureMask(OS, FeatureList, FeatureMap);
333e8d8bef9SDimitry Andric     OS << ", ";
334e8d8bef9SDimitry Andric     printFeatureMask(OS, TuneFeatureList, FeatureMap);
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric     // Emit the scheduler model pointer.
3370b57cec5SDimitry Andric     const std::string &ProcModelName =
3380b57cec5SDimitry Andric         SchedModels.getModelForProc(Processor).ModelName;
3390b57cec5SDimitry Andric     OS << ", &" << ProcModelName << " },\n";
3400b57cec5SDimitry Andric   }
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   // End processor table
3430b57cec5SDimitry Andric   OS << "};\n";
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   return ProcessorList.size();
3460b57cec5SDimitry Andric }
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric //
3490b57cec5SDimitry Andric // FormItineraryStageString - Compose a string containing the stage
3500b57cec5SDimitry Andric // data initialization for the specified itinerary.  N is the number
3510b57cec5SDimitry Andric // of stages.
3520b57cec5SDimitry Andric //
3530b57cec5SDimitry Andric void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
3540b57cec5SDimitry Andric                                                 Record *ItinData,
3550b57cec5SDimitry Andric                                                 std::string &ItinString,
3560b57cec5SDimitry Andric                                                 unsigned &NStages) {
3570b57cec5SDimitry Andric   // Get states list
3580b57cec5SDimitry Andric   RecVec StageList = ItinData->getValueAsListOfDefs("Stages");
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   // For each stage
3610b57cec5SDimitry Andric   unsigned N = NStages = StageList.size();
3620b57cec5SDimitry Andric   for (unsigned i = 0; i < N;) {
3630b57cec5SDimitry Andric     // Next stage
3640b57cec5SDimitry Andric     const Record *Stage = StageList[i];
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric     // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }
3670b57cec5SDimitry Andric     int Cycles = Stage->getValueAsInt("Cycles");
3680b57cec5SDimitry Andric     ItinString += "  { " + itostr(Cycles) + ", ";
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric     // Get unit list
3710b57cec5SDimitry Andric     RecVec UnitList = Stage->getValueAsListOfDefs("Units");
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric     // For each unit
3740b57cec5SDimitry Andric     for (unsigned j = 0, M = UnitList.size(); j < M;) {
3750b57cec5SDimitry Andric       // Add name and bitwise or
3760b57cec5SDimitry Andric       ItinString += Name + "FU::" + UnitList[j]->getName().str();
377*0fca6ea1SDimitry Andric       if (++j < M)
378*0fca6ea1SDimitry Andric         ItinString += " | ";
3790b57cec5SDimitry Andric     }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric     int TimeInc = Stage->getValueAsInt("TimeInc");
3820b57cec5SDimitry Andric     ItinString += ", " + itostr(TimeInc);
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric     int Kind = Stage->getValueAsInt("Kind");
3850b57cec5SDimitry Andric     ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric     // Close off stage
3880b57cec5SDimitry Andric     ItinString += " }";
389*0fca6ea1SDimitry Andric     if (++i < N)
390*0fca6ea1SDimitry Andric       ItinString += ", ";
3910b57cec5SDimitry Andric   }
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric //
3950b57cec5SDimitry Andric // FormItineraryOperandCycleString - Compose a string containing the
3960b57cec5SDimitry Andric // operand cycle initialization for the specified itinerary.  N is the
3970b57cec5SDimitry Andric // number of operands that has cycles specified.
3980b57cec5SDimitry Andric //
399*0fca6ea1SDimitry Andric void SubtargetEmitter::FormItineraryOperandCycleString(
400*0fca6ea1SDimitry Andric     Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) {
4010b57cec5SDimitry Andric   // Get operand cycle list
4020b57cec5SDimitry Andric   std::vector<int64_t> OperandCycleList =
4030b57cec5SDimitry Andric       ItinData->getValueAsListOfInts("OperandCycles");
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   // For each operand cycle
406fe6060f1SDimitry Andric   NOperandCycles = OperandCycleList.size();
407fe6060f1SDimitry Andric   ListSeparator LS;
408fe6060f1SDimitry Andric   for (int OCycle : OperandCycleList) {
4090b57cec5SDimitry Andric     // Next operand cycle
410fe6060f1SDimitry Andric     ItinString += LS;
4110b57cec5SDimitry Andric     ItinString += "  " + itostr(OCycle);
4120b57cec5SDimitry Andric   }
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
4160b57cec5SDimitry Andric                                                  Record *ItinData,
4170b57cec5SDimitry Andric                                                  std::string &ItinString,
4180b57cec5SDimitry Andric                                                  unsigned NOperandCycles) {
4190b57cec5SDimitry Andric   RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses");
4200b57cec5SDimitry Andric   unsigned N = BypassList.size();
4210b57cec5SDimitry Andric   unsigned i = 0;
422fe6060f1SDimitry Andric   ListSeparator LS;
423fe6060f1SDimitry Andric   for (; i < N; ++i) {
424fe6060f1SDimitry Andric     ItinString += LS;
4250b57cec5SDimitry Andric     ItinString += Name + "Bypass::" + BypassList[i]->getName().str();
4260b57cec5SDimitry Andric   }
427fe6060f1SDimitry Andric   for (; i < NOperandCycles; ++i) {
428fe6060f1SDimitry Andric     ItinString += LS;
4290b57cec5SDimitry Andric     ItinString += " 0";
4300b57cec5SDimitry Andric   }
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric //
4340b57cec5SDimitry Andric // EmitStageAndOperandCycleData - Generate unique itinerary stages and operand
4350b57cec5SDimitry Andric // cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed
4360b57cec5SDimitry Andric // by CodeGenSchedClass::Index.
4370b57cec5SDimitry Andric //
438*0fca6ea1SDimitry Andric void SubtargetEmitter::EmitStageAndOperandCycleData(
439*0fca6ea1SDimitry Andric     raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
4400b57cec5SDimitry Andric   // Multiple processor models may share an itinerary record. Emit it once.
4410b57cec5SDimitry Andric   SmallPtrSet<Record *, 8> ItinsDefSet;
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   // Emit functional units for all the itineraries.
4440b57cec5SDimitry Andric   for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric     if (!ItinsDefSet.insert(ProcModel.ItinsDef).second)
4470b57cec5SDimitry Andric       continue;
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric     RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU");
4500b57cec5SDimitry Andric     if (FUs.empty())
4510b57cec5SDimitry Andric       continue;
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric     StringRef Name = ProcModel.ItinsDef->getName();
4540b57cec5SDimitry Andric     OS << "\n// Functional units for \"" << Name << "\"\n"
4550b57cec5SDimitry Andric        << "namespace " << Name << "FU {\n";
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric     for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
4585ffd83dbSDimitry Andric       OS << "  const InstrStage::FuncUnits " << FUs[j]->getName()
4595ffd83dbSDimitry Andric          << " = 1ULL << " << j << ";\n";
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric     OS << "} // end namespace " << Name << "FU\n";
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric     RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");
4640b57cec5SDimitry Andric     if (!BPs.empty()) {
4650b57cec5SDimitry Andric       OS << "\n// Pipeline forwarding paths for itineraries \"" << Name
466*0fca6ea1SDimitry Andric          << "\"\n"
467*0fca6ea1SDimitry Andric          << "namespace " << Name << "Bypass {\n";
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric       OS << "  const unsigned NoBypass = 0;\n";
4700b57cec5SDimitry Andric       for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
471*0fca6ea1SDimitry Andric         OS << "  const unsigned " << BPs[j]->getName() << " = 1 << " << j
472*0fca6ea1SDimitry Andric            << ";\n";
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric       OS << "} // end namespace " << Name << "Bypass\n";
4750b57cec5SDimitry Andric     }
4760b57cec5SDimitry Andric   }
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric   // Begin stages table
479*0fca6ea1SDimitry Andric   std::string StageTable =
480*0fca6ea1SDimitry Andric       "\nextern const llvm::InstrStage " + Target + "Stages[] = {\n";
4810b57cec5SDimitry Andric   StageTable += "  { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   // Begin operand cycle table
484*0fca6ea1SDimitry Andric   std::string OperandCycleTable =
485*0fca6ea1SDimitry Andric       "extern const unsigned " + Target + "OperandCycles[] = {\n";
4860b57cec5SDimitry Andric   OperandCycleTable += "  0, // No itinerary\n";
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric   // Begin pipeline bypass table
489*0fca6ea1SDimitry Andric   std::string BypassTable =
490*0fca6ea1SDimitry Andric       "extern const unsigned " + Target + "ForwardingPaths[] = {\n";
4910b57cec5SDimitry Andric   BypassTable += " 0, // No itinerary\n";
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   // For each Itinerary across all processors, add a unique entry to the stages,
4940b57cec5SDimitry Andric   // operand cycles, and pipeline bypass tables. Then add the new Itinerary
4950b57cec5SDimitry Andric   // object with computed offsets to the ProcItinLists result.
4960b57cec5SDimitry Andric   unsigned StageCount = 1, OperandCycleCount = 1;
4970b57cec5SDimitry Andric   std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
4980b57cec5SDimitry Andric   for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
4990b57cec5SDimitry Andric     // Add process itinerary to the list.
500*0fca6ea1SDimitry Andric     std::vector<InstrItinerary> &ItinList = ProcItinLists.emplace_back();
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric     // If this processor defines no itineraries, then leave the itinerary list
5030b57cec5SDimitry Andric     // empty.
5040b57cec5SDimitry Andric     if (!ProcModel.hasItineraries())
5050b57cec5SDimitry Andric       continue;
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric     StringRef Name = ProcModel.ItinsDef->getName();
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric     ItinList.resize(SchedModels.numInstrSchedClasses());
5100b57cec5SDimitry Andric     assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric     for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();
5130b57cec5SDimitry Andric          SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric       // Next itinerary data
5160b57cec5SDimitry Andric       Record *ItinData = ProcModel.ItinDefList[SchedClassIdx];
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric       // Get string and stage count
5190b57cec5SDimitry Andric       std::string ItinStageString;
5200b57cec5SDimitry Andric       unsigned NStages = 0;
5210b57cec5SDimitry Andric       if (ItinData)
5225ffd83dbSDimitry Andric         FormItineraryStageString(std::string(Name), ItinData, ItinStageString,
5235ffd83dbSDimitry Andric                                  NStages);
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric       // Get string and operand cycle count
5260b57cec5SDimitry Andric       std::string ItinOperandCycleString;
5270b57cec5SDimitry Andric       unsigned NOperandCycles = 0;
5280b57cec5SDimitry Andric       std::string ItinBypassString;
5290b57cec5SDimitry Andric       if (ItinData) {
5300b57cec5SDimitry Andric         FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
5310b57cec5SDimitry Andric                                         NOperandCycles);
5320b57cec5SDimitry Andric 
5335ffd83dbSDimitry Andric         FormItineraryBypassString(std::string(Name), ItinData, ItinBypassString,
5340b57cec5SDimitry Andric                                   NOperandCycles);
5350b57cec5SDimitry Andric       }
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric       // Check to see if stage already exists and create if it doesn't
5380b57cec5SDimitry Andric       uint16_t FindStage = 0;
5390b57cec5SDimitry Andric       if (NStages > 0) {
5400b57cec5SDimitry Andric         FindStage = ItinStageMap[ItinStageString];
5410b57cec5SDimitry Andric         if (FindStage == 0) {
5420b57cec5SDimitry Andric           // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices
5430b57cec5SDimitry Andric           StageTable += ItinStageString + ", // " + itostr(StageCount);
5440b57cec5SDimitry Andric           if (NStages > 1)
5450b57cec5SDimitry Andric             StageTable += "-" + itostr(StageCount + NStages - 1);
5460b57cec5SDimitry Andric           StageTable += "\n";
5470b57cec5SDimitry Andric           // Record Itin class number.
5480b57cec5SDimitry Andric           ItinStageMap[ItinStageString] = FindStage = StageCount;
5490b57cec5SDimitry Andric           StageCount += NStages;
5500b57cec5SDimitry Andric         }
5510b57cec5SDimitry Andric       }
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric       // Check to see if operand cycle already exists and create if it doesn't
5540b57cec5SDimitry Andric       uint16_t FindOperandCycle = 0;
5550b57cec5SDimitry Andric       if (NOperandCycles > 0) {
556*0fca6ea1SDimitry Andric         std::string ItinOperandString =
557*0fca6ea1SDimitry Andric             ItinOperandCycleString + ItinBypassString;
5580b57cec5SDimitry Andric         FindOperandCycle = ItinOperandMap[ItinOperandString];
5590b57cec5SDimitry Andric         if (FindOperandCycle == 0) {
5600b57cec5SDimitry Andric           // Emit as  cycle, // index
5610b57cec5SDimitry Andric           OperandCycleTable += ItinOperandCycleString + ", // ";
5620b57cec5SDimitry Andric           std::string OperandIdxComment = itostr(OperandCycleCount);
5630b57cec5SDimitry Andric           if (NOperandCycles > 1)
564*0fca6ea1SDimitry Andric             OperandIdxComment +=
565*0fca6ea1SDimitry Andric                 "-" + itostr(OperandCycleCount + NOperandCycles - 1);
5660b57cec5SDimitry Andric           OperandCycleTable += OperandIdxComment + "\n";
5670b57cec5SDimitry Andric           // Record Itin class number.
568*0fca6ea1SDimitry Andric           ItinOperandMap[ItinOperandCycleString] = FindOperandCycle =
569*0fca6ea1SDimitry Andric               OperandCycleCount;
5700b57cec5SDimitry Andric           // Emit as bypass, // index
5710b57cec5SDimitry Andric           BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";
5720b57cec5SDimitry Andric           OperandCycleCount += NOperandCycles;
5730b57cec5SDimitry Andric         }
5740b57cec5SDimitry Andric       }
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric       // Set up itinerary as location and location + stage count
5770b57cec5SDimitry Andric       int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0;
5780b57cec5SDimitry Andric       InstrItinerary Intinerary = {
5790b57cec5SDimitry Andric           NumUOps,
5800b57cec5SDimitry Andric           FindStage,
5810b57cec5SDimitry Andric           uint16_t(FindStage + NStages),
5820b57cec5SDimitry Andric           FindOperandCycle,
5830b57cec5SDimitry Andric           uint16_t(FindOperandCycle + NOperandCycles),
5840b57cec5SDimitry Andric       };
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric       // Inject - empty slots will be 0, 0
5870b57cec5SDimitry Andric       ItinList[SchedClassIdx] = Intinerary;
5880b57cec5SDimitry Andric     }
5890b57cec5SDimitry Andric   }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric   // Closing stage
5920b57cec5SDimitry Andric   StageTable += "  { 0, 0, 0, llvm::InstrStage::Required } // End stages\n";
5930b57cec5SDimitry Andric   StageTable += "};\n";
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   // Closing operand cycles
5960b57cec5SDimitry Andric   OperandCycleTable += "  0 // End operand cycles\n";
5970b57cec5SDimitry Andric   OperandCycleTable += "};\n";
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric   BypassTable += " 0 // End bypass tables\n";
6000b57cec5SDimitry Andric   BypassTable += "};\n";
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric   // Emit tables.
6030b57cec5SDimitry Andric   OS << StageTable;
6040b57cec5SDimitry Andric   OS << OperandCycleTable;
6050b57cec5SDimitry Andric   OS << BypassTable;
6060b57cec5SDimitry Andric }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric //
6090b57cec5SDimitry Andric // EmitProcessorData - Generate data for processor itineraries that were
6100b57cec5SDimitry Andric // computed during EmitStageAndOperandCycleData(). ProcItinLists lists all
6110b57cec5SDimitry Andric // Itineraries for each processor. The Itinerary lists are indexed on
6120b57cec5SDimitry Andric // CodeGenSchedClass::Index.
6130b57cec5SDimitry Andric //
614*0fca6ea1SDimitry Andric void SubtargetEmitter::EmitItineraries(
615*0fca6ea1SDimitry Andric     raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
6160b57cec5SDimitry Andric   // Multiple processor models may share an itinerary record. Emit it once.
6170b57cec5SDimitry Andric   SmallPtrSet<Record *, 8> ItinsDefSet;
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   // For each processor's machine model
620*0fca6ea1SDimitry Andric   std::vector<std::vector<InstrItinerary>>::iterator ProcItinListsIter =
621*0fca6ea1SDimitry Andric       ProcItinLists.begin();
6220b57cec5SDimitry Andric   for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
623*0fca6ea1SDimitry Andric                                     PE = SchedModels.procModelEnd();
624*0fca6ea1SDimitry Andric        PI != PE; ++PI, ++ProcItinListsIter) {
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric     Record *ItinsDef = PI->ItinsDef;
6270b57cec5SDimitry Andric     if (!ItinsDefSet.insert(ItinsDef).second)
6280b57cec5SDimitry Andric       continue;
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric     // Get the itinerary list for the processor.
6310b57cec5SDimitry Andric     assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator");
6320b57cec5SDimitry Andric     std::vector<InstrItinerary> &ItinList = *ProcItinListsIter;
6330b57cec5SDimitry Andric 
6340b57cec5SDimitry Andric     // Empty itineraries aren't referenced anywhere in the tablegen output
6350b57cec5SDimitry Andric     // so don't emit them.
6360b57cec5SDimitry Andric     if (ItinList.empty())
6370b57cec5SDimitry Andric       continue;
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric     OS << "\n";
6400b57cec5SDimitry Andric     OS << "static const llvm::InstrItinerary ";
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric     // Begin processor itinerary table
6430b57cec5SDimitry Andric     OS << ItinsDef->getName() << "[] = {\n";
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric     // For each itinerary class in CodeGenSchedClass::Index order.
6460b57cec5SDimitry Andric     for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {
6470b57cec5SDimitry Andric       InstrItinerary &Intinerary = ItinList[j];
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric       // Emit Itinerary in the form of
6500b57cec5SDimitry Andric       // { firstStage, lastStage, firstCycle, lastCycle } // index
651*0fca6ea1SDimitry Andric       OS << "  { " << Intinerary.NumMicroOps << ", " << Intinerary.FirstStage
652*0fca6ea1SDimitry Andric          << ", " << Intinerary.LastStage << ", " << Intinerary.FirstOperandCycle
653*0fca6ea1SDimitry Andric          << ", " << Intinerary.LastOperandCycle << " }"
654*0fca6ea1SDimitry Andric          << ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
6550b57cec5SDimitry Andric     }
6560b57cec5SDimitry Andric     // End processor itinerary table
6570b57cec5SDimitry Andric     OS << "  { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }"
6580b57cec5SDimitry Andric           "// end marker\n";
6590b57cec5SDimitry Andric     OS << "};\n";
6600b57cec5SDimitry Andric   }
6610b57cec5SDimitry Andric }
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric // Emit either the value defined in the TableGen Record, or the default
6640b57cec5SDimitry Andric // value defined in the C++ header. The Record is null if the processor does not
6650b57cec5SDimitry Andric // define a model.
6660b57cec5SDimitry Andric void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R,
6670b57cec5SDimitry Andric                                          StringRef Name, char Separator) {
6680b57cec5SDimitry Andric   OS << "  ";
6690b57cec5SDimitry Andric   int V = R ? R->getValueAsInt(Name) : -1;
6700b57cec5SDimitry Andric   if (V >= 0)
6710b57cec5SDimitry Andric     OS << V << Separator << " // " << Name;
6720b57cec5SDimitry Andric   else
6730b57cec5SDimitry Andric     OS << "MCSchedModel::Default" << Name << Separator;
6740b57cec5SDimitry Andric   OS << '\n';
6750b57cec5SDimitry Andric }
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric void SubtargetEmitter::EmitProcessorResourceSubUnits(
6780b57cec5SDimitry Andric     const CodeGenProcModel &ProcModel, raw_ostream &OS) {
6790b57cec5SDimitry Andric   OS << "\nstatic const unsigned " << ProcModel.ModelName
6800b57cec5SDimitry Andric      << "ProcResourceSubUnits[] = {\n"
6810b57cec5SDimitry Andric      << "  0,  // Invalid\n";
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
6840b57cec5SDimitry Andric     Record *PRDef = ProcModel.ProcResourceDefs[i];
6850b57cec5SDimitry Andric     if (!PRDef->isSubClassOf("ProcResGroup"))
6860b57cec5SDimitry Andric       continue;
6870b57cec5SDimitry Andric     RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
6880b57cec5SDimitry Andric     for (Record *RUDef : ResUnits) {
6890b57cec5SDimitry Andric       Record *const RU =
6900b57cec5SDimitry Andric           SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc());
6910b57cec5SDimitry Andric       for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) {
6920b57cec5SDimitry Andric         OS << "  " << ProcModel.getProcResourceIdx(RU) << ", ";
6930b57cec5SDimitry Andric       }
6940b57cec5SDimitry Andric     }
6950b57cec5SDimitry Andric     OS << "  // " << PRDef->getName() << "\n";
6960b57cec5SDimitry Andric   }
6970b57cec5SDimitry Andric   OS << "};\n";
6980b57cec5SDimitry Andric }
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel,
7010b57cec5SDimitry Andric                                       raw_ostream &OS) {
7020b57cec5SDimitry Andric   int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0;
7030b57cec5SDimitry Andric   if (Record *RCU = ProcModel.RetireControlUnit) {
7040b57cec5SDimitry Andric     ReorderBufferSize =
7050b57cec5SDimitry Andric         std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize"));
7060b57cec5SDimitry Andric     MaxRetirePerCycle =
7070b57cec5SDimitry Andric         std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle"));
7080b57cec5SDimitry Andric   }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   OS << ReorderBufferSize << ", // ReorderBufferSize\n  ";
7110b57cec5SDimitry Andric   OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n  ";
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel,
7150b57cec5SDimitry Andric                                  unsigned NumRegisterFiles,
7160b57cec5SDimitry Andric                                  unsigned NumCostEntries, raw_ostream &OS) {
7170b57cec5SDimitry Andric   if (NumRegisterFiles)
7180b57cec5SDimitry Andric     OS << ProcModel.ModelName << "RegisterFiles,\n  " << (1 + NumRegisterFiles);
7190b57cec5SDimitry Andric   else
7200b57cec5SDimitry Andric     OS << "nullptr,\n  0";
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric   OS << ", // Number of register files.\n  ";
7230b57cec5SDimitry Andric   if (NumCostEntries)
7240b57cec5SDimitry Andric     OS << ProcModel.ModelName << "RegisterCosts,\n  ";
7250b57cec5SDimitry Andric   else
7260b57cec5SDimitry Andric     OS << "nullptr,\n  ";
7270b57cec5SDimitry Andric   OS << NumCostEntries << ", // Number of register cost entries.\n";
7280b57cec5SDimitry Andric }
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric unsigned
7310b57cec5SDimitry Andric SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
7320b57cec5SDimitry Andric                                          raw_ostream &OS) {
7330b57cec5SDimitry Andric   if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) {
7340b57cec5SDimitry Andric         return RF.hasDefaultCosts();
7350b57cec5SDimitry Andric       }))
7360b57cec5SDimitry Andric     return 0;
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric   // Print the RegisterCost table first.
7390b57cec5SDimitry Andric   OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n";
7400b57cec5SDimitry Andric   OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName
7410b57cec5SDimitry Andric      << "RegisterCosts"
7420b57cec5SDimitry Andric      << "[] = {\n";
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric   for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) {
7450b57cec5SDimitry Andric     // Skip register files with a default cost table.
7460b57cec5SDimitry Andric     if (RF.hasDefaultCosts())
7470b57cec5SDimitry Andric       continue;
7480b57cec5SDimitry Andric     // Add entries to the cost table.
7490b57cec5SDimitry Andric     for (const CodeGenRegisterCost &RC : RF.Costs) {
7500b57cec5SDimitry Andric       OS << "  { ";
7510b57cec5SDimitry Andric       Record *Rec = RC.RCDef;
7520b57cec5SDimitry Andric       if (Rec->getValue("Namespace"))
7530b57cec5SDimitry Andric         OS << Rec->getValueAsString("Namespace") << "::";
7540b57cec5SDimitry Andric       OS << Rec->getName() << "RegClassID, " << RC.Cost << ", "
7550b57cec5SDimitry Andric          << RC.AllowMoveElimination << "},\n";
7560b57cec5SDimitry Andric     }
7570b57cec5SDimitry Andric   }
7580b57cec5SDimitry Andric   OS << "};\n";
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric   // Now generate a table with register file info.
7610b57cec5SDimitry Andric   OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, "
7620b57cec5SDimitry Andric      << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n";
7630b57cec5SDimitry Andric   OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName
7640b57cec5SDimitry Andric      << "RegisterFiles"
7650b57cec5SDimitry Andric      << "[] = {\n"
7660b57cec5SDimitry Andric      << "  { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n";
7670b57cec5SDimitry Andric   unsigned CostTblIndex = 0;
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric   for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) {
7700b57cec5SDimitry Andric     OS << "  { ";
7710b57cec5SDimitry Andric     OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", ";
7720b57cec5SDimitry Andric     unsigned NumCostEntries = RD.Costs.size();
7730b57cec5SDimitry Andric     OS << NumCostEntries << ", " << CostTblIndex << ", "
7740b57cec5SDimitry Andric        << RD.MaxMovesEliminatedPerCycle << ", "
7750b57cec5SDimitry Andric        << RD.AllowZeroMoveEliminationOnly << "},\n";
7760b57cec5SDimitry Andric     CostTblIndex += NumCostEntries;
7770b57cec5SDimitry Andric   }
7780b57cec5SDimitry Andric   OS << "};\n";
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric   return CostTblIndex;
7810b57cec5SDimitry Andric }
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
7840b57cec5SDimitry Andric                                               raw_ostream &OS) {
7850b57cec5SDimitry Andric   unsigned QueueID = 0;
7860b57cec5SDimitry Andric   if (ProcModel.LoadQueue) {
7870b57cec5SDimitry Andric     const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor");
788e8d8bef9SDimitry Andric     QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
789e8d8bef9SDimitry Andric                                 find(ProcModel.ProcResourceDefs, Queue));
7900b57cec5SDimitry Andric   }
7910b57cec5SDimitry Andric   OS << "  " << QueueID << ", // Resource Descriptor for the Load Queue\n";
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   QueueID = 0;
7940b57cec5SDimitry Andric   if (ProcModel.StoreQueue) {
7950b57cec5SDimitry Andric     const Record *Queue =
7960b57cec5SDimitry Andric         ProcModel.StoreQueue->getValueAsDef("QueueDescriptor");
797e8d8bef9SDimitry Andric     QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
798e8d8bef9SDimitry Andric                                 find(ProcModel.ProcResourceDefs, Queue));
7990b57cec5SDimitry Andric   }
8000b57cec5SDimitry Andric   OS << "  " << QueueID << ", // Resource Descriptor for the Store Queue\n";
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric 
8030b57cec5SDimitry Andric void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,
8040b57cec5SDimitry Andric                                               raw_ostream &OS) {
8050b57cec5SDimitry Andric   // Generate a table of register file descriptors (one entry per each user
8060b57cec5SDimitry Andric   // defined register file), and a table of register costs.
8070b57cec5SDimitry Andric   unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS);
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric   // Now generate a table for the extra processor info.
8100b57cec5SDimitry Andric   OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName
8110b57cec5SDimitry Andric      << "ExtraInfo = {\n  ";
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric   // Add information related to the retire control unit.
8140b57cec5SDimitry Andric   EmitRetireControlUnitInfo(ProcModel, OS);
8150b57cec5SDimitry Andric 
8160b57cec5SDimitry Andric   // Add information related to the register files (i.e. where to find register
8170b57cec5SDimitry Andric   // file descriptors and register costs).
8180b57cec5SDimitry Andric   EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(),
8190b57cec5SDimitry Andric                        NumCostEntries, OS);
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric   // Add information about load/store queues.
8220b57cec5SDimitry Andric   EmitLoadStoreQueueInfo(ProcModel, OS);
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   OS << "};\n";
8250b57cec5SDimitry Andric }
8260b57cec5SDimitry Andric 
8270b57cec5SDimitry Andric void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
8280b57cec5SDimitry Andric                                               raw_ostream &OS) {
8290b57cec5SDimitry Andric   EmitProcessorResourceSubUnits(ProcModel, OS);
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric   OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n";
8320b57cec5SDimitry Andric   OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName
8330b57cec5SDimitry Andric      << "ProcResources"
8340b57cec5SDimitry Andric      << "[] = {\n"
8350b57cec5SDimitry Andric      << "  {\"InvalidUnit\", 0, 0, 0, 0},\n";
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric   unsigned SubUnitsOffset = 1;
8380b57cec5SDimitry Andric   for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
8390b57cec5SDimitry Andric     Record *PRDef = ProcModel.ProcResourceDefs[i];
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric     Record *SuperDef = nullptr;
8420b57cec5SDimitry Andric     unsigned SuperIdx = 0;
8430b57cec5SDimitry Andric     unsigned NumUnits = 0;
8440b57cec5SDimitry Andric     const unsigned SubUnitsBeginOffset = SubUnitsOffset;
8450b57cec5SDimitry Andric     int BufferSize = PRDef->getValueAsInt("BufferSize");
8460b57cec5SDimitry Andric     if (PRDef->isSubClassOf("ProcResGroup")) {
8470b57cec5SDimitry Andric       RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
8480b57cec5SDimitry Andric       for (Record *RU : ResUnits) {
8490b57cec5SDimitry Andric         NumUnits += RU->getValueAsInt("NumUnits");
8500b57cec5SDimitry Andric         SubUnitsOffset += RU->getValueAsInt("NumUnits");
8510b57cec5SDimitry Andric       }
852*0fca6ea1SDimitry Andric     } else {
8530b57cec5SDimitry Andric       // Find the SuperIdx
8540b57cec5SDimitry Andric       if (PRDef->getValueInit("Super")->isComplete()) {
855*0fca6ea1SDimitry Andric         SuperDef = SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"),
8560b57cec5SDimitry Andric                                                 ProcModel, PRDef->getLoc());
8570b57cec5SDimitry Andric         SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
8580b57cec5SDimitry Andric       }
8590b57cec5SDimitry Andric       NumUnits = PRDef->getValueAsInt("NumUnits");
8600b57cec5SDimitry Andric     }
8610b57cec5SDimitry Andric     // Emit the ProcResourceDesc
8620b57cec5SDimitry Andric     OS << "  {\"" << PRDef->getName() << "\", ";
8630b57cec5SDimitry Andric     if (PRDef->getName().size() < 15)
8640b57cec5SDimitry Andric       OS.indent(15 - PRDef->getName().size());
8650b57cec5SDimitry Andric     OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", ";
8660b57cec5SDimitry Andric     if (SubUnitsBeginOffset != SubUnitsOffset) {
8670b57cec5SDimitry Andric       OS << ProcModel.ModelName << "ProcResourceSubUnits + "
8680b57cec5SDimitry Andric          << SubUnitsBeginOffset;
8690b57cec5SDimitry Andric     } else {
8700b57cec5SDimitry Andric       OS << "nullptr";
8710b57cec5SDimitry Andric     }
8720b57cec5SDimitry Andric     OS << "}, // #" << i + 1;
8730b57cec5SDimitry Andric     if (SuperDef)
8740b57cec5SDimitry Andric       OS << ", Super=" << SuperDef->getName();
8750b57cec5SDimitry Andric     OS << "\n";
8760b57cec5SDimitry Andric   }
8770b57cec5SDimitry Andric   OS << "};\n";
8780b57cec5SDimitry Andric }
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric // Find the WriteRes Record that defines processor resources for this
8810b57cec5SDimitry Andric // SchedWrite.
882*0fca6ea1SDimitry Andric Record *
883*0fca6ea1SDimitry Andric SubtargetEmitter::FindWriteResources(const CodeGenSchedRW &SchedWrite,
884*0fca6ea1SDimitry Andric                                      const CodeGenProcModel &ProcModel) {
8850b57cec5SDimitry Andric 
8860b57cec5SDimitry Andric   // Check if the SchedWrite is already subtarget-specific and directly
8870b57cec5SDimitry Andric   // specifies a set of processor resources.
8880b57cec5SDimitry Andric   if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))
8890b57cec5SDimitry Andric     return SchedWrite.TheDef;
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric   Record *AliasDef = nullptr;
8920b57cec5SDimitry Andric   for (Record *A : SchedWrite.Aliases) {
8930b57cec5SDimitry Andric     const CodeGenSchedRW &AliasRW =
8940b57cec5SDimitry Andric         SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
8950b57cec5SDimitry Andric     if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
8960b57cec5SDimitry Andric       Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
8970b57cec5SDimitry Andric       if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
8980b57cec5SDimitry Andric         continue;
8990b57cec5SDimitry Andric     }
9000b57cec5SDimitry Andric     if (AliasDef)
901*0fca6ea1SDimitry Andric       PrintFatalError(AliasRW.TheDef->getLoc(),
902*0fca6ea1SDimitry Andric                       "Multiple aliases "
903*0fca6ea1SDimitry Andric                       "defined for processor " +
904*0fca6ea1SDimitry Andric                           ProcModel.ModelName +
9050b57cec5SDimitry Andric                           " Ensure only one SchedAlias exists per RW.");
9060b57cec5SDimitry Andric     AliasDef = AliasRW.TheDef;
9070b57cec5SDimitry Andric   }
9080b57cec5SDimitry Andric   if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))
9090b57cec5SDimitry Andric     return AliasDef;
9100b57cec5SDimitry Andric 
9110b57cec5SDimitry Andric   // Check this processor's list of write resources.
9120b57cec5SDimitry Andric   Record *ResDef = nullptr;
9130b57cec5SDimitry Andric   for (Record *WR : ProcModel.WriteResDefs) {
9140b57cec5SDimitry Andric     if (!WR->isSubClassOf("WriteRes"))
9150b57cec5SDimitry Andric       continue;
916*0fca6ea1SDimitry Andric     Record *WRDef = WR->getValueAsDef("WriteType");
917*0fca6ea1SDimitry Andric     if (AliasDef == WRDef || SchedWrite.TheDef == WRDef) {
9180b57cec5SDimitry Andric       if (ResDef) {
9190b57cec5SDimitry Andric         PrintFatalError(WR->getLoc(), "Resources are defined for both "
9200b57cec5SDimitry Andric                                       "SchedWrite and its alias on processor " +
9210b57cec5SDimitry Andric                                           ProcModel.ModelName);
9220b57cec5SDimitry Andric       }
9230b57cec5SDimitry Andric       ResDef = WR;
924*0fca6ea1SDimitry Andric       // If there is no AliasDef and we find a match, we can early exit since
925*0fca6ea1SDimitry Andric       // there is no need to verify whether there are resources defined for both
926*0fca6ea1SDimitry Andric       // SchedWrite and its alias.
927*0fca6ea1SDimitry Andric       if (!AliasDef)
928*0fca6ea1SDimitry Andric         break;
9290b57cec5SDimitry Andric     }
9300b57cec5SDimitry Andric   }
9310b57cec5SDimitry Andric   // TODO: If ProcModel has a base model (previous generation processor),
9320b57cec5SDimitry Andric   // then call FindWriteResources recursively with that model here.
9330b57cec5SDimitry Andric   if (!ResDef) {
9340b57cec5SDimitry Andric     PrintFatalError(ProcModel.ModelDef->getLoc(),
9350b57cec5SDimitry Andric                     Twine("Processor does not define resources for ") +
9360b57cec5SDimitry Andric                         SchedWrite.TheDef->getName());
9370b57cec5SDimitry Andric   }
9380b57cec5SDimitry Andric   return ResDef;
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric 
9410b57cec5SDimitry Andric /// Find the ReadAdvance record for the given SchedRead on this processor or
9420b57cec5SDimitry Andric /// return NULL.
9430b57cec5SDimitry Andric Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
9440b57cec5SDimitry Andric                                           const CodeGenProcModel &ProcModel) {
9450b57cec5SDimitry Andric   // Check for SchedReads that directly specify a ReadAdvance.
9460b57cec5SDimitry Andric   if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))
9470b57cec5SDimitry Andric     return SchedRead.TheDef;
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric   // Check this processor's list of aliases for SchedRead.
9500b57cec5SDimitry Andric   Record *AliasDef = nullptr;
9510b57cec5SDimitry Andric   for (Record *A : SchedRead.Aliases) {
9520b57cec5SDimitry Andric     const CodeGenSchedRW &AliasRW =
9530b57cec5SDimitry Andric         SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
9540b57cec5SDimitry Andric     if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
9550b57cec5SDimitry Andric       Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
9560b57cec5SDimitry Andric       if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
9570b57cec5SDimitry Andric         continue;
9580b57cec5SDimitry Andric     }
9590b57cec5SDimitry Andric     if (AliasDef)
960*0fca6ea1SDimitry Andric       PrintFatalError(AliasRW.TheDef->getLoc(),
961*0fca6ea1SDimitry Andric                       "Multiple aliases "
962*0fca6ea1SDimitry Andric                       "defined for processor " +
963*0fca6ea1SDimitry Andric                           ProcModel.ModelName +
9640b57cec5SDimitry Andric                           " Ensure only one SchedAlias exists per RW.");
9650b57cec5SDimitry Andric     AliasDef = AliasRW.TheDef;
9660b57cec5SDimitry Andric   }
9670b57cec5SDimitry Andric   if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))
9680b57cec5SDimitry Andric     return AliasDef;
9690b57cec5SDimitry Andric 
9700b57cec5SDimitry Andric   // Check this processor's ReadAdvanceList.
9710b57cec5SDimitry Andric   Record *ResDef = nullptr;
9720b57cec5SDimitry Andric   for (Record *RA : ProcModel.ReadAdvanceDefs) {
9730b57cec5SDimitry Andric     if (!RA->isSubClassOf("ReadAdvance"))
9740b57cec5SDimitry Andric       continue;
975*0fca6ea1SDimitry Andric     Record *RADef = RA->getValueAsDef("ReadType");
976*0fca6ea1SDimitry Andric     if (AliasDef == RADef || SchedRead.TheDef == RADef) {
9770b57cec5SDimitry Andric       if (ResDef) {
9780b57cec5SDimitry Andric         PrintFatalError(RA->getLoc(), "Resources are defined for both "
9790b57cec5SDimitry Andric                                       "SchedRead and its alias on processor " +
9800b57cec5SDimitry Andric                                           ProcModel.ModelName);
9810b57cec5SDimitry Andric       }
9820b57cec5SDimitry Andric       ResDef = RA;
983*0fca6ea1SDimitry Andric       // If there is no AliasDef and we find a match, we can early exit since
984*0fca6ea1SDimitry Andric       // there is no need to verify whether there are resources defined for both
985*0fca6ea1SDimitry Andric       // SchedRead and its alias.
986*0fca6ea1SDimitry Andric       if (!AliasDef)
987*0fca6ea1SDimitry Andric         break;
9880b57cec5SDimitry Andric     }
9890b57cec5SDimitry Andric   }
9900b57cec5SDimitry Andric   // TODO: If ProcModel has a base model (previous generation processor),
9910b57cec5SDimitry Andric   // then call FindReadAdvance recursively with that model here.
9920b57cec5SDimitry Andric   if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {
9930b57cec5SDimitry Andric     PrintFatalError(ProcModel.ModelDef->getLoc(),
9940b57cec5SDimitry Andric                     Twine("Processor does not define resources for ") +
9950b57cec5SDimitry Andric                         SchedRead.TheDef->getName());
9960b57cec5SDimitry Andric   }
9970b57cec5SDimitry Andric   return ResDef;
9980b57cec5SDimitry Andric }
9990b57cec5SDimitry Andric 
10000b57cec5SDimitry Andric // Expand an explicit list of processor resources into a full list of implied
10010b57cec5SDimitry Andric // resource groups and super resources that cover them.
10025f757f3fSDimitry Andric void SubtargetEmitter::ExpandProcResources(
10035f757f3fSDimitry Andric     RecVec &PRVec, std::vector<int64_t> &ReleaseAtCycles,
10045f757f3fSDimitry Andric     std::vector<int64_t> &AcquireAtCycles, const CodeGenProcModel &PM) {
10055f757f3fSDimitry Andric   assert(PRVec.size() == ReleaseAtCycles.size() && "failed precondition");
10060b57cec5SDimitry Andric   for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
10070b57cec5SDimitry Andric     Record *PRDef = PRVec[i];
10080b57cec5SDimitry Andric     RecVec SubResources;
10090b57cec5SDimitry Andric     if (PRDef->isSubClassOf("ProcResGroup"))
10100b57cec5SDimitry Andric       SubResources = PRDef->getValueAsListOfDefs("Resources");
10110b57cec5SDimitry Andric     else {
10120b57cec5SDimitry Andric       SubResources.push_back(PRDef);
10130b57cec5SDimitry Andric       PRDef = SchedModels.findProcResUnits(PRDef, PM, PRDef->getLoc());
10140b57cec5SDimitry Andric       for (Record *SubDef = PRDef;
10150b57cec5SDimitry Andric            SubDef->getValueInit("Super")->isComplete();) {
10160b57cec5SDimitry Andric         if (SubDef->isSubClassOf("ProcResGroup")) {
10170b57cec5SDimitry Andric           // Disallow this for simplicitly.
10180b57cec5SDimitry Andric           PrintFatalError(SubDef->getLoc(), "Processor resource group "
10190b57cec5SDimitry Andric                                             " cannot be a super resources.");
10200b57cec5SDimitry Andric         }
1021*0fca6ea1SDimitry Andric         Record *SuperDef = SchedModels.findProcResUnits(
1022*0fca6ea1SDimitry Andric             SubDef->getValueAsDef("Super"), PM, SubDef->getLoc());
10230b57cec5SDimitry Andric         PRVec.push_back(SuperDef);
10245f757f3fSDimitry Andric         ReleaseAtCycles.push_back(ReleaseAtCycles[i]);
10255f757f3fSDimitry Andric         AcquireAtCycles.push_back(AcquireAtCycles[i]);
10260b57cec5SDimitry Andric         SubDef = SuperDef;
10270b57cec5SDimitry Andric       }
10280b57cec5SDimitry Andric     }
10290b57cec5SDimitry Andric     for (Record *PR : PM.ProcResourceDefs) {
10300b57cec5SDimitry Andric       if (PR == PRDef || !PR->isSubClassOf("ProcResGroup"))
10310b57cec5SDimitry Andric         continue;
10320b57cec5SDimitry Andric       RecVec SuperResources = PR->getValueAsListOfDefs("Resources");
10330b57cec5SDimitry Andric       RecIter SubI = SubResources.begin(), SubE = SubResources.end();
10340b57cec5SDimitry Andric       for (; SubI != SubE; ++SubI) {
10350b57cec5SDimitry Andric         if (!is_contained(SuperResources, *SubI)) {
10360b57cec5SDimitry Andric           break;
10370b57cec5SDimitry Andric         }
10380b57cec5SDimitry Andric       }
10390b57cec5SDimitry Andric       if (SubI == SubE) {
10400b57cec5SDimitry Andric         PRVec.push_back(PR);
10415f757f3fSDimitry Andric         ReleaseAtCycles.push_back(ReleaseAtCycles[i]);
10425f757f3fSDimitry Andric         AcquireAtCycles.push_back(AcquireAtCycles[i]);
10430b57cec5SDimitry Andric       }
10440b57cec5SDimitry Andric     }
10450b57cec5SDimitry Andric   }
10460b57cec5SDimitry Andric }
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric // Generate the SchedClass table for this processor and update global
10490b57cec5SDimitry Andric // tables. Must be called for each processor in order.
10500b57cec5SDimitry Andric void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
10510b57cec5SDimitry Andric                                            SchedClassTables &SchedTables) {
1052*0fca6ea1SDimitry Andric   std::vector<MCSchedClassDesc> &SCTab =
1053*0fca6ea1SDimitry Andric       SchedTables.ProcSchedClasses.emplace_back();
10540b57cec5SDimitry Andric   if (!ProcModel.hasInstrSchedModel())
10550b57cec5SDimitry Andric     return;
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n");
10580b57cec5SDimitry Andric   for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
10590b57cec5SDimitry Andric     LLVM_DEBUG(SC.dump(&SchedModels));
10600b57cec5SDimitry Andric 
1061*0fca6ea1SDimitry Andric     MCSchedClassDesc &SCDesc = SCTab.emplace_back();
10620b57cec5SDimitry Andric     // SCDesc.Name is guarded by NDEBUG
10630b57cec5SDimitry Andric     SCDesc.NumMicroOps = 0;
10640b57cec5SDimitry Andric     SCDesc.BeginGroup = false;
10650b57cec5SDimitry Andric     SCDesc.EndGroup = false;
1066fe6060f1SDimitry Andric     SCDesc.RetireOOO = false;
10670b57cec5SDimitry Andric     SCDesc.WriteProcResIdx = 0;
10680b57cec5SDimitry Andric     SCDesc.WriteLatencyIdx = 0;
10690b57cec5SDimitry Andric     SCDesc.ReadAdvanceIdx = 0;
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric     // A Variant SchedClass has no resources of its own.
10720b57cec5SDimitry Andric     bool HasVariants = false;
10730b57cec5SDimitry Andric     for (const CodeGenSchedTransition &CGT :
10740b57cec5SDimitry Andric          make_range(SC.Transitions.begin(), SC.Transitions.end())) {
1075e8d8bef9SDimitry Andric       if (CGT.ProcIndex == ProcModel.Index) {
10760b57cec5SDimitry Andric         HasVariants = true;
10770b57cec5SDimitry Andric         break;
10780b57cec5SDimitry Andric       }
10790b57cec5SDimitry Andric     }
10800b57cec5SDimitry Andric     if (HasVariants) {
10810b57cec5SDimitry Andric       SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;
10820b57cec5SDimitry Andric       continue;
10830b57cec5SDimitry Andric     }
10840b57cec5SDimitry Andric 
10850b57cec5SDimitry Andric     // Determine if the SchedClass is actually reachable on this processor. If
10860b57cec5SDimitry Andric     // not don't try to locate the processor resources, it will fail.
10870b57cec5SDimitry Andric     // If ProcIndices contains 0, this class applies to all processors.
10880b57cec5SDimitry Andric     assert(!SC.ProcIndices.empty() && "expect at least one procidx");
10890b57cec5SDimitry Andric     if (SC.ProcIndices[0] != 0) {
10900b57cec5SDimitry Andric       if (!is_contained(SC.ProcIndices, ProcModel.Index))
10910b57cec5SDimitry Andric         continue;
10920b57cec5SDimitry Andric     }
10930b57cec5SDimitry Andric     IdxVec Writes = SC.Writes;
10940b57cec5SDimitry Andric     IdxVec Reads = SC.Reads;
10950b57cec5SDimitry Andric     if (!SC.InstRWs.empty()) {
10960b57cec5SDimitry Andric       // This class has a default ReadWrite list which can be overridden by
10970b57cec5SDimitry Andric       // InstRW definitions.
10980b57cec5SDimitry Andric       Record *RWDef = nullptr;
10990b57cec5SDimitry Andric       for (Record *RW : SC.InstRWs) {
11000b57cec5SDimitry Andric         Record *RWModelDef = RW->getValueAsDef("SchedModel");
11010b57cec5SDimitry Andric         if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {
11020b57cec5SDimitry Andric           RWDef = RW;
11030b57cec5SDimitry Andric           break;
11040b57cec5SDimitry Andric         }
11050b57cec5SDimitry Andric       }
11060b57cec5SDimitry Andric       if (RWDef) {
11070b57cec5SDimitry Andric         Writes.clear();
11080b57cec5SDimitry Andric         Reads.clear();
11090b57cec5SDimitry Andric         SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
11100b57cec5SDimitry Andric                             Writes, Reads);
11110b57cec5SDimitry Andric       }
11120b57cec5SDimitry Andric     }
11130b57cec5SDimitry Andric     if (Writes.empty()) {
11140b57cec5SDimitry Andric       // Check this processor's itinerary class resources.
11150b57cec5SDimitry Andric       for (Record *I : ProcModel.ItinRWDefs) {
11160b57cec5SDimitry Andric         RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses");
11170b57cec5SDimitry Andric         if (is_contained(Matched, SC.ItinClassDef)) {
11180b57cec5SDimitry Andric           SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"),
11190b57cec5SDimitry Andric                               Writes, Reads);
11200b57cec5SDimitry Andric           break;
11210b57cec5SDimitry Andric         }
11220b57cec5SDimitry Andric       }
11230b57cec5SDimitry Andric       if (Writes.empty()) {
11240b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << ProcModel.ModelName
11250b57cec5SDimitry Andric                           << " does not have resources for class " << SC.Name
11260b57cec5SDimitry Andric                           << '\n');
11278bcb0991SDimitry Andric         SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
11280b57cec5SDimitry Andric       }
11290b57cec5SDimitry Andric     }
11300b57cec5SDimitry Andric     // Sum resources across all operand writes.
11310b57cec5SDimitry Andric     std::vector<MCWriteProcResEntry> WriteProcResources;
11320b57cec5SDimitry Andric     std::vector<MCWriteLatencyEntry> WriteLatencies;
11330b57cec5SDimitry Andric     std::vector<std::string> WriterNames;
11340b57cec5SDimitry Andric     std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
11350b57cec5SDimitry Andric     for (unsigned W : Writes) {
11360b57cec5SDimitry Andric       IdxVec WriteSeq;
1137*0fca6ea1SDimitry Andric       SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, ProcModel);
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric       // For each operand, create a latency entry.
11400b57cec5SDimitry Andric       MCWriteLatencyEntry WLEntry;
11410b57cec5SDimitry Andric       WLEntry.Cycles = 0;
11420b57cec5SDimitry Andric       unsigned WriteID = WriteSeq.back();
11430b57cec5SDimitry Andric       WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
11440b57cec5SDimitry Andric       // If this Write is not referenced by a ReadAdvance, don't distinguish it
11450b57cec5SDimitry Andric       // from other WriteLatency entries.
1146*0fca6ea1SDimitry Andric       if (!ProcModel.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef))
11470b57cec5SDimitry Andric         WriteID = 0;
11480b57cec5SDimitry Andric       WLEntry.WriteResourceID = WriteID;
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric       for (unsigned WS : WriteSeq) {
11510b57cec5SDimitry Andric 
11520b57cec5SDimitry Andric         Record *WriteRes =
11530b57cec5SDimitry Andric             FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
11540b57cec5SDimitry Andric 
11550b57cec5SDimitry Andric         // Mark the parent class as invalid for unsupported write types.
11560b57cec5SDimitry Andric         if (WriteRes->getValueAsBit("Unsupported")) {
11570b57cec5SDimitry Andric           SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
11580b57cec5SDimitry Andric           break;
11590b57cec5SDimitry Andric         }
11600b57cec5SDimitry Andric         WLEntry.Cycles += WriteRes->getValueAsInt("Latency");
11610b57cec5SDimitry Andric         SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");
11620b57cec5SDimitry Andric         SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");
11630b57cec5SDimitry Andric         SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");
11640b57cec5SDimitry Andric         SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue");
11650b57cec5SDimitry Andric         SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue");
1166fe6060f1SDimitry Andric         SCDesc.RetireOOO |= WriteRes->getValueAsBit("RetireOOO");
11670b57cec5SDimitry Andric 
11680b57cec5SDimitry Andric         // Create an entry for each ProcResource listed in WriteRes.
11690b57cec5SDimitry Andric         RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
11705f757f3fSDimitry Andric         std::vector<int64_t> ReleaseAtCycles =
11715f757f3fSDimitry Andric             WriteRes->getValueAsListOfInts("ReleaseAtCycles");
11720b57cec5SDimitry Andric 
11735f757f3fSDimitry Andric         std::vector<int64_t> AcquireAtCycles =
11745f757f3fSDimitry Andric             WriteRes->getValueAsListOfInts("AcquireAtCycles");
117506c3fb27SDimitry Andric 
117606c3fb27SDimitry Andric         // Check consistency of the two vectors carrying the start and
117706c3fb27SDimitry Andric         // stop cycles of the resources.
11785f757f3fSDimitry Andric         if (!ReleaseAtCycles.empty() &&
11795f757f3fSDimitry Andric             ReleaseAtCycles.size() != PRVec.size()) {
11805f757f3fSDimitry Andric           // If ReleaseAtCycles is provided, check consistency.
11810b57cec5SDimitry Andric           PrintFatalError(
11820b57cec5SDimitry Andric               WriteRes->getLoc(),
11835f757f3fSDimitry Andric               Twine("Inconsistent release at cycles: size(ReleaseAtCycles) != "
118406c3fb27SDimitry Andric                     "size(ProcResources): ")
11850b57cec5SDimitry Andric                   .concat(Twine(PRVec.size()))
11860b57cec5SDimitry Andric                   .concat(" vs ")
11875f757f3fSDimitry Andric                   .concat(Twine(ReleaseAtCycles.size())));
11880b57cec5SDimitry Andric         }
11890b57cec5SDimitry Andric 
1190*0fca6ea1SDimitry Andric         if (!AcquireAtCycles.empty() &&
1191*0fca6ea1SDimitry Andric             AcquireAtCycles.size() != PRVec.size()) {
119206c3fb27SDimitry Andric           PrintFatalError(
119306c3fb27SDimitry Andric               WriteRes->getLoc(),
11945f757f3fSDimitry Andric               Twine("Inconsistent resource cycles: size(AcquireAtCycles) != "
119506c3fb27SDimitry Andric                     "size(ProcResources): ")
11965f757f3fSDimitry Andric                   .concat(Twine(AcquireAtCycles.size()))
119706c3fb27SDimitry Andric                   .concat(" vs ")
119806c3fb27SDimitry Andric                   .concat(Twine(PRVec.size())));
119906c3fb27SDimitry Andric         }
120006c3fb27SDimitry Andric 
12015f757f3fSDimitry Andric         if (ReleaseAtCycles.empty()) {
12025f757f3fSDimitry Andric           // If ReleaseAtCycles is not provided, default to one cycle
120306c3fb27SDimitry Andric           // per resource.
12045f757f3fSDimitry Andric           ReleaseAtCycles.resize(PRVec.size(), 1);
120506c3fb27SDimitry Andric         }
120606c3fb27SDimitry Andric 
12075f757f3fSDimitry Andric         if (AcquireAtCycles.empty()) {
12085f757f3fSDimitry Andric           // If AcquireAtCycles is not provided, reserve the resource
120906c3fb27SDimitry Andric           // starting from cycle 0.
12105f757f3fSDimitry Andric           AcquireAtCycles.resize(PRVec.size(), 0);
121106c3fb27SDimitry Andric         }
121206c3fb27SDimitry Andric 
12135f757f3fSDimitry Andric         assert(AcquireAtCycles.size() == ReleaseAtCycles.size());
121406c3fb27SDimitry Andric 
12155f757f3fSDimitry Andric         ExpandProcResources(PRVec, ReleaseAtCycles, AcquireAtCycles, ProcModel);
12165f757f3fSDimitry Andric         assert(AcquireAtCycles.size() == ReleaseAtCycles.size());
12170b57cec5SDimitry Andric 
1218*0fca6ea1SDimitry Andric         for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd;
1219*0fca6ea1SDimitry Andric              ++PRIdx) {
12200b57cec5SDimitry Andric           MCWriteProcResEntry WPREntry;
12210b57cec5SDimitry Andric           WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
12220b57cec5SDimitry Andric           assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
12235f757f3fSDimitry Andric           WPREntry.ReleaseAtCycle = ReleaseAtCycles[PRIdx];
12245f757f3fSDimitry Andric           WPREntry.AcquireAtCycle = AcquireAtCycles[PRIdx];
12255f757f3fSDimitry Andric           if (AcquireAtCycles[PRIdx] > ReleaseAtCycles[PRIdx]) {
12265f757f3fSDimitry Andric             PrintFatalError(
12275f757f3fSDimitry Andric                 WriteRes->getLoc(),
12285f757f3fSDimitry Andric                 Twine("Inconsistent resource cycles: AcquireAtCycles "
12295f757f3fSDimitry Andric                       "< ReleaseAtCycles must hold."));
123006c3fb27SDimitry Andric           }
12315f757f3fSDimitry Andric           if (AcquireAtCycles[PRIdx] < 0) {
123206c3fb27SDimitry Andric             PrintFatalError(WriteRes->getLoc(),
12335f757f3fSDimitry Andric                             Twine("Invalid value: AcquireAtCycle "
123406c3fb27SDimitry Andric                                   "must be a non-negative value."));
123506c3fb27SDimitry Andric           }
12360b57cec5SDimitry Andric           // If this resource is already used in this sequence, add the current
12370b57cec5SDimitry Andric           // entry's cycles so that the same resource appears to be used
12380b57cec5SDimitry Andric           // serially, rather than multiple parallel uses. This is important for
12390b57cec5SDimitry Andric           // in-order machine where the resource consumption is a hazard.
12400b57cec5SDimitry Andric           unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
12410b57cec5SDimitry Andric           for (; WPRIdx != WPREnd; ++WPRIdx) {
1242*0fca6ea1SDimitry Andric             if (WriteProcResources[WPRIdx].ProcResourceIdx ==
1243*0fca6ea1SDimitry Andric                 WPREntry.ProcResourceIdx) {
124406c3fb27SDimitry Andric               // TODO: multiple use of the same resources would
124506c3fb27SDimitry Andric               // require either 1. thinking of how to handle multiple
124606c3fb27SDimitry Andric               // intervals for the same resource in
124706c3fb27SDimitry Andric               // `<Target>WriteProcResTable` (see
124806c3fb27SDimitry Andric               // `SubtargetEmitter::EmitSchedClassTables`), or
124906c3fb27SDimitry Andric               // 2. thinking how to merge multiple intervals into a
125006c3fb27SDimitry Andric               // single interval.
12515f757f3fSDimitry Andric               assert(WPREntry.AcquireAtCycle == 0 &&
125206c3fb27SDimitry Andric                      "multiple use ofthe same resource is not yet handled");
12535f757f3fSDimitry Andric               WriteProcResources[WPRIdx].ReleaseAtCycle +=
12545f757f3fSDimitry Andric                   WPREntry.ReleaseAtCycle;
12550b57cec5SDimitry Andric               break;
12560b57cec5SDimitry Andric             }
12570b57cec5SDimitry Andric           }
12580b57cec5SDimitry Andric           if (WPRIdx == WPREnd)
12590b57cec5SDimitry Andric             WriteProcResources.push_back(WPREntry);
12600b57cec5SDimitry Andric         }
12610b57cec5SDimitry Andric       }
12620b57cec5SDimitry Andric       WriteLatencies.push_back(WLEntry);
12630b57cec5SDimitry Andric     }
12640b57cec5SDimitry Andric     // Create an entry for each operand Read in this SchedClass.
12650b57cec5SDimitry Andric     // Entries must be sorted first by UseIdx then by WriteResourceID.
1266*0fca6ea1SDimitry Andric     for (unsigned UseIdx = 0, EndIdx = Reads.size(); UseIdx != EndIdx;
1267*0fca6ea1SDimitry Andric          ++UseIdx) {
12680b57cec5SDimitry Andric       Record *ReadAdvance =
12690b57cec5SDimitry Andric           FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
12700b57cec5SDimitry Andric       if (!ReadAdvance)
12710b57cec5SDimitry Andric         continue;
12720b57cec5SDimitry Andric 
12730b57cec5SDimitry Andric       // Mark the parent class as invalid for unsupported write types.
12740b57cec5SDimitry Andric       if (ReadAdvance->getValueAsBit("Unsupported")) {
12750b57cec5SDimitry Andric         SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
12760b57cec5SDimitry Andric         break;
12770b57cec5SDimitry Andric       }
12780b57cec5SDimitry Andric       RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");
12790b57cec5SDimitry Andric       IdxVec WriteIDs;
12800b57cec5SDimitry Andric       if (ValidWrites.empty())
12810b57cec5SDimitry Andric         WriteIDs.push_back(0);
12820b57cec5SDimitry Andric       else {
12830b57cec5SDimitry Andric         for (Record *VW : ValidWrites) {
1284*0fca6ea1SDimitry Andric           unsigned WriteID = SchedModels.getSchedRWIdx(VW, /*IsRead=*/false);
1285*0fca6ea1SDimitry Andric           assert(WriteID != 0 &&
1286*0fca6ea1SDimitry Andric                  "Expected a valid SchedRW in the list of ValidWrites");
1287*0fca6ea1SDimitry Andric           WriteIDs.push_back(WriteID);
12880b57cec5SDimitry Andric         }
12890b57cec5SDimitry Andric       }
12900b57cec5SDimitry Andric       llvm::sort(WriteIDs);
12910b57cec5SDimitry Andric       for (unsigned W : WriteIDs) {
12920b57cec5SDimitry Andric         MCReadAdvanceEntry RAEntry;
12930b57cec5SDimitry Andric         RAEntry.UseIdx = UseIdx;
12940b57cec5SDimitry Andric         RAEntry.WriteResourceID = W;
12950b57cec5SDimitry Andric         RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
12960b57cec5SDimitry Andric         ReadAdvanceEntries.push_back(RAEntry);
12970b57cec5SDimitry Andric       }
12980b57cec5SDimitry Andric     }
12990b57cec5SDimitry Andric     if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
13000b57cec5SDimitry Andric       WriteProcResources.clear();
13010b57cec5SDimitry Andric       WriteLatencies.clear();
13020b57cec5SDimitry Andric       ReadAdvanceEntries.clear();
13030b57cec5SDimitry Andric     }
13040b57cec5SDimitry Andric     // Add the information for this SchedClass to the global tables using basic
13050b57cec5SDimitry Andric     // compression.
13060b57cec5SDimitry Andric     //
13070b57cec5SDimitry Andric     // WritePrecRes entries are sorted by ProcResIdx.
13080b57cec5SDimitry Andric     llvm::sort(WriteProcResources, LessWriteProcResources());
13090b57cec5SDimitry Andric 
13100b57cec5SDimitry Andric     SCDesc.NumWriteProcResEntries = WriteProcResources.size();
13110b57cec5SDimitry Andric     std::vector<MCWriteProcResEntry>::iterator WPRPos =
13120b57cec5SDimitry Andric         std::search(SchedTables.WriteProcResources.begin(),
13130b57cec5SDimitry Andric                     SchedTables.WriteProcResources.end(),
13140b57cec5SDimitry Andric                     WriteProcResources.begin(), WriteProcResources.end());
13150b57cec5SDimitry Andric     if (WPRPos != SchedTables.WriteProcResources.end())
13160b57cec5SDimitry Andric       SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
13170b57cec5SDimitry Andric     else {
13180b57cec5SDimitry Andric       SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();
13190b57cec5SDimitry Andric       SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),
13200b57cec5SDimitry Andric                                             WriteProcResources.end());
13210b57cec5SDimitry Andric     }
13220b57cec5SDimitry Andric     // Latency entries must remain in operand order.
13230b57cec5SDimitry Andric     SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
1324*0fca6ea1SDimitry Andric     std::vector<MCWriteLatencyEntry>::iterator WLPos = std::search(
1325*0fca6ea1SDimitry Andric         SchedTables.WriteLatencies.begin(), SchedTables.WriteLatencies.end(),
13260b57cec5SDimitry Andric         WriteLatencies.begin(), WriteLatencies.end());
13270b57cec5SDimitry Andric     if (WLPos != SchedTables.WriteLatencies.end()) {
13280b57cec5SDimitry Andric       unsigned idx = WLPos - SchedTables.WriteLatencies.begin();
13290b57cec5SDimitry Andric       SCDesc.WriteLatencyIdx = idx;
13300b57cec5SDimitry Andric       for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)
13310b57cec5SDimitry Andric         if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==
13320b57cec5SDimitry Andric             std::string::npos) {
13330b57cec5SDimitry Andric           SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];
13340b57cec5SDimitry Andric         }
1335*0fca6ea1SDimitry Andric     } else {
13360b57cec5SDimitry Andric       SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
1337e8d8bef9SDimitry Andric       llvm::append_range(SchedTables.WriteLatencies, WriteLatencies);
1338e8d8bef9SDimitry Andric       llvm::append_range(SchedTables.WriterNames, WriterNames);
13390b57cec5SDimitry Andric     }
13400b57cec5SDimitry Andric     // ReadAdvanceEntries must remain in operand order.
13410b57cec5SDimitry Andric     SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
13420b57cec5SDimitry Andric     std::vector<MCReadAdvanceEntry>::iterator RAPos =
13430b57cec5SDimitry Andric         std::search(SchedTables.ReadAdvanceEntries.begin(),
13440b57cec5SDimitry Andric                     SchedTables.ReadAdvanceEntries.end(),
13450b57cec5SDimitry Andric                     ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
13460b57cec5SDimitry Andric     if (RAPos != SchedTables.ReadAdvanceEntries.end())
13470b57cec5SDimitry Andric       SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
13480b57cec5SDimitry Andric     else {
13490b57cec5SDimitry Andric       SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
1350e8d8bef9SDimitry Andric       llvm::append_range(SchedTables.ReadAdvanceEntries, ReadAdvanceEntries);
13510b57cec5SDimitry Andric     }
13520b57cec5SDimitry Andric   }
13530b57cec5SDimitry Andric }
13540b57cec5SDimitry Andric 
13550b57cec5SDimitry Andric // Emit SchedClass tables for all processors and associated global tables.
13560b57cec5SDimitry Andric void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
13570b57cec5SDimitry Andric                                             raw_ostream &OS) {
13580b57cec5SDimitry Andric   // Emit global WriteProcResTable.
13595f757f3fSDimitry Andric   OS << "\n// {ProcResourceIdx, ReleaseAtCycle, AcquireAtCycle}\n"
136006c3fb27SDimitry Andric      << "extern const llvm::MCWriteProcResEntry " << Target
136106c3fb27SDimitry Andric      << "WriteProcResTable[] = {\n"
136206c3fb27SDimitry Andric      << "  { 0,  0,  0 }, // Invalid\n";
13630b57cec5SDimitry Andric   for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
13640b57cec5SDimitry Andric        WPRIdx != WPREnd; ++WPRIdx) {
13650b57cec5SDimitry Andric     MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
13660b57cec5SDimitry Andric     OS << "  {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
13675f757f3fSDimitry Andric        << format("%2d", WPREntry.ReleaseAtCycle) << ",  "
13685f757f3fSDimitry Andric        << format("%2d", WPREntry.AcquireAtCycle) << "}";
13690b57cec5SDimitry Andric     if (WPRIdx + 1 < WPREnd)
13700b57cec5SDimitry Andric       OS << ',';
13710b57cec5SDimitry Andric     OS << " // #" << WPRIdx << '\n';
13720b57cec5SDimitry Andric   }
13730b57cec5SDimitry Andric   OS << "}; // " << Target << "WriteProcResTable\n";
13740b57cec5SDimitry Andric 
13750b57cec5SDimitry Andric   // Emit global WriteLatencyTable.
13760b57cec5SDimitry Andric   OS << "\n// {Cycles, WriteResourceID}\n"
1377*0fca6ea1SDimitry Andric      << "extern const llvm::MCWriteLatencyEntry " << Target
1378*0fca6ea1SDimitry Andric      << "WriteLatencyTable[] = {\n"
13790b57cec5SDimitry Andric      << "  { 0,  0}, // Invalid\n";
13800b57cec5SDimitry Andric   for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
13810b57cec5SDimitry Andric        WLIdx != WLEnd; ++WLIdx) {
13820b57cec5SDimitry Andric     MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
13830b57cec5SDimitry Andric     OS << "  {" << format("%2d", WLEntry.Cycles) << ", "
13840b57cec5SDimitry Andric        << format("%2d", WLEntry.WriteResourceID) << "}";
13850b57cec5SDimitry Andric     if (WLIdx + 1 < WLEnd)
13860b57cec5SDimitry Andric       OS << ',';
13870b57cec5SDimitry Andric     OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
13880b57cec5SDimitry Andric   }
13890b57cec5SDimitry Andric   OS << "}; // " << Target << "WriteLatencyTable\n";
13900b57cec5SDimitry Andric 
13910b57cec5SDimitry Andric   // Emit global ReadAdvanceTable.
13920b57cec5SDimitry Andric   OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
1393*0fca6ea1SDimitry Andric      << "extern const llvm::MCReadAdvanceEntry " << Target
1394*0fca6ea1SDimitry Andric      << "ReadAdvanceTable[] = {\n"
13950b57cec5SDimitry Andric      << "  {0,  0,  0}, // Invalid\n";
13960b57cec5SDimitry Andric   for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
13970b57cec5SDimitry Andric        RAIdx != RAEnd; ++RAIdx) {
13980b57cec5SDimitry Andric     MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
13990b57cec5SDimitry Andric     OS << "  {" << RAEntry.UseIdx << ", "
14000b57cec5SDimitry Andric        << format("%2d", RAEntry.WriteResourceID) << ", "
14010b57cec5SDimitry Andric        << format("%2d", RAEntry.Cycles) << "}";
14020b57cec5SDimitry Andric     if (RAIdx + 1 < RAEnd)
14030b57cec5SDimitry Andric       OS << ',';
14040b57cec5SDimitry Andric     OS << " // #" << RAIdx << '\n';
14050b57cec5SDimitry Andric   }
14060b57cec5SDimitry Andric   OS << "}; // " << Target << "ReadAdvanceTable\n";
14070b57cec5SDimitry Andric 
14080b57cec5SDimitry Andric   // Emit a SchedClass table for each processor.
14090b57cec5SDimitry Andric   for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1410*0fca6ea1SDimitry Andric                                     PE = SchedModels.procModelEnd();
1411*0fca6ea1SDimitry Andric        PI != PE; ++PI) {
14120b57cec5SDimitry Andric     if (!PI->hasInstrSchedModel())
14130b57cec5SDimitry Andric       continue;
14140b57cec5SDimitry Andric 
14150b57cec5SDimitry Andric     std::vector<MCSchedClassDesc> &SCTab =
14160b57cec5SDimitry Andric         SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
14170b57cec5SDimitry Andric 
1418fe6060f1SDimitry Andric     OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"
14190b57cec5SDimitry Andric        << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
1420*0fca6ea1SDimitry Andric     OS << "static const llvm::MCSchedClassDesc " << PI->ModelName
1421*0fca6ea1SDimitry Andric        << "SchedClasses[] = {\n";
14220b57cec5SDimitry Andric 
14230b57cec5SDimitry Andric     // The first class is always invalid. We no way to distinguish it except by
14240b57cec5SDimitry Andric     // name and position.
1425*0fca6ea1SDimitry Andric     assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" &&
1426*0fca6ea1SDimitry Andric            "invalid class not first");
14270b57cec5SDimitry Andric     OS << "  {DBGFIELD(\"InvalidSchedClass\")  "
14280b57cec5SDimitry Andric        << MCSchedClassDesc::InvalidNumMicroOps
1429fe6060f1SDimitry Andric        << ", false, false, false, 0, 0,  0, 0,  0, 0},\n";
14300b57cec5SDimitry Andric 
14310b57cec5SDimitry Andric     for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
14320b57cec5SDimitry Andric       MCSchedClassDesc &MCDesc = SCTab[SCIdx];
14330b57cec5SDimitry Andric       const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
14340b57cec5SDimitry Andric       OS << "  {DBGFIELD(\"" << SchedClass.Name << "\") ";
14350b57cec5SDimitry Andric       if (SchedClass.Name.size() < 18)
14360b57cec5SDimitry Andric         OS.indent(18 - SchedClass.Name.size());
1437*0fca6ea1SDimitry Andric       OS << MCDesc.NumMicroOps << ", " << (MCDesc.BeginGroup ? "true" : "false")
1438*0fca6ea1SDimitry Andric          << ", " << (MCDesc.EndGroup ? "true" : "false") << ", "
1439*0fca6ea1SDimitry Andric          << (MCDesc.RetireOOO ? "true" : "false") << ", "
1440*0fca6ea1SDimitry Andric          << format("%2d", MCDesc.WriteProcResIdx) << ", "
1441*0fca6ea1SDimitry Andric          << MCDesc.NumWriteProcResEntries << ", "
1442*0fca6ea1SDimitry Andric          << format("%2d", MCDesc.WriteLatencyIdx) << ", "
1443*0fca6ea1SDimitry Andric          << MCDesc.NumWriteLatencyEntries << ", "
1444*0fca6ea1SDimitry Andric          << format("%2d", MCDesc.ReadAdvanceIdx) << ", "
1445*0fca6ea1SDimitry Andric          << MCDesc.NumReadAdvanceEntries << "}, // #" << SCIdx << '\n';
14460b57cec5SDimitry Andric     }
14470b57cec5SDimitry Andric     OS << "}; // " << PI->ModelName << "SchedClasses\n";
14480b57cec5SDimitry Andric   }
14490b57cec5SDimitry Andric }
14500b57cec5SDimitry Andric 
14510b57cec5SDimitry Andric void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
14520b57cec5SDimitry Andric   // For each processor model.
14530b57cec5SDimitry Andric   for (const CodeGenProcModel &PM : SchedModels.procModels()) {
14540b57cec5SDimitry Andric     // Emit extra processor info if available.
14550b57cec5SDimitry Andric     if (PM.hasExtraProcessorInfo())
14560b57cec5SDimitry Andric       EmitExtraProcessorInfo(PM, OS);
14570b57cec5SDimitry Andric     // Emit processor resource table.
14580b57cec5SDimitry Andric     if (PM.hasInstrSchedModel())
14590b57cec5SDimitry Andric       EmitProcessorResources(PM, OS);
14600b57cec5SDimitry Andric     else if (!PM.ProcResourceDefs.empty())
1461*0fca6ea1SDimitry Andric       PrintFatalError(PM.ModelDef->getLoc(),
1462*0fca6ea1SDimitry Andric                       "SchedMachineModel defines "
14630b57cec5SDimitry Andric                       "ProcResources without defining WriteRes SchedWriteRes");
14640b57cec5SDimitry Andric 
14650b57cec5SDimitry Andric     // Begin processor itinerary properties
14660b57cec5SDimitry Andric     OS << "\n";
14670b57cec5SDimitry Andric     OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n";
14680b57cec5SDimitry Andric     EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ',');
14690b57cec5SDimitry Andric     EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ',');
14700b57cec5SDimitry Andric     EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ',');
14710b57cec5SDimitry Andric     EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ',');
14720b57cec5SDimitry Andric     EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ',');
14730b57cec5SDimitry Andric     EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric     bool PostRAScheduler =
14760b57cec5SDimitry Andric         (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
14770b57cec5SDimitry Andric 
14780b57cec5SDimitry Andric     OS << "  " << (PostRAScheduler ? "true" : "false") << ", // "
14790b57cec5SDimitry Andric        << "PostRAScheduler\n";
14800b57cec5SDimitry Andric 
14810b57cec5SDimitry Andric     bool CompleteModel =
14820b57cec5SDimitry Andric         (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
14830b57cec5SDimitry Andric 
14840b57cec5SDimitry Andric     OS << "  " << (CompleteModel ? "true" : "false") << ", // "
14850b57cec5SDimitry Andric        << "CompleteModel\n";
14860b57cec5SDimitry Andric 
148706c3fb27SDimitry Andric     bool EnableIntervals =
148806c3fb27SDimitry Andric         (PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false);
148906c3fb27SDimitry Andric 
149006c3fb27SDimitry Andric     OS << "  " << (EnableIntervals ? "true" : "false") << ", // "
149106c3fb27SDimitry Andric        << "EnableIntervals\n";
149206c3fb27SDimitry Andric 
14930b57cec5SDimitry Andric     OS << "  " << PM.Index << ", // Processor ID\n";
14940b57cec5SDimitry Andric     if (PM.hasInstrSchedModel())
1495*0fca6ea1SDimitry Andric       OS << "  " << PM.ModelName << "ProcResources"
1496*0fca6ea1SDimitry Andric          << ",\n"
1497*0fca6ea1SDimitry Andric          << "  " << PM.ModelName << "SchedClasses"
1498*0fca6ea1SDimitry Andric          << ",\n"
14990b57cec5SDimitry Andric          << "  " << PM.ProcResourceDefs.size() + 1 << ",\n"
1500*0fca6ea1SDimitry Andric          << "  "
1501*0fca6ea1SDimitry Andric          << (SchedModels.schedClassEnd() - SchedModels.schedClassBegin())
1502*0fca6ea1SDimitry Andric          << ",\n";
15030b57cec5SDimitry Andric     else
15040b57cec5SDimitry Andric       OS << "  nullptr, nullptr, 0, 0,"
15050b57cec5SDimitry Andric          << " // No instruction-level machine model.\n";
15060b57cec5SDimitry Andric     if (PM.hasItineraries())
15070b57cec5SDimitry Andric       OS << "  " << PM.ItinsDef->getName() << ",\n";
15080b57cec5SDimitry Andric     else
15090b57cec5SDimitry Andric       OS << "  nullptr, // No Itinerary\n";
15100b57cec5SDimitry Andric     if (PM.hasExtraProcessorInfo())
15110b57cec5SDimitry Andric       OS << "  &" << PM.ModelName << "ExtraInfo,\n";
15120b57cec5SDimitry Andric     else
15130b57cec5SDimitry Andric       OS << "  nullptr // No extra processor descriptor\n";
15140b57cec5SDimitry Andric     OS << "};\n";
15150b57cec5SDimitry Andric   }
15160b57cec5SDimitry Andric }
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric //
15190b57cec5SDimitry Andric // EmitSchedModel - Emits all scheduling model tables, folding common patterns.
15200b57cec5SDimitry Andric //
15210b57cec5SDimitry Andric void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
15220b57cec5SDimitry Andric   OS << "#ifdef DBGFIELD\n"
15230b57cec5SDimitry Andric      << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n"
15240b57cec5SDimitry Andric      << "#endif\n"
15250b57cec5SDimitry Andric      << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n"
15260b57cec5SDimitry Andric      << "#define DBGFIELD(x) x,\n"
15270b57cec5SDimitry Andric      << "#else\n"
15280b57cec5SDimitry Andric      << "#define DBGFIELD(x)\n"
15290b57cec5SDimitry Andric      << "#endif\n";
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric   if (SchedModels.hasItineraries()) {
15320b57cec5SDimitry Andric     std::vector<std::vector<InstrItinerary>> ProcItinLists;
15330b57cec5SDimitry Andric     // Emit the stage data
15340b57cec5SDimitry Andric     EmitStageAndOperandCycleData(OS, ProcItinLists);
15350b57cec5SDimitry Andric     EmitItineraries(OS, ProcItinLists);
15360b57cec5SDimitry Andric   }
15370b57cec5SDimitry Andric   OS << "\n// ===============================================================\n"
15380b57cec5SDimitry Andric      << "// Data tables for the new per-operand machine model.\n";
15390b57cec5SDimitry Andric 
15400b57cec5SDimitry Andric   SchedClassTables SchedTables;
15410b57cec5SDimitry Andric   for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
15420b57cec5SDimitry Andric     GenSchedClassTables(ProcModel, SchedTables);
15430b57cec5SDimitry Andric   }
15440b57cec5SDimitry Andric   EmitSchedClassTables(SchedTables, OS);
15450b57cec5SDimitry Andric 
15460b57cec5SDimitry Andric   OS << "\n#undef DBGFIELD\n";
15470b57cec5SDimitry Andric 
15480b57cec5SDimitry Andric   // Emit the processor machine model
15490b57cec5SDimitry Andric   EmitProcessorModels(OS);
15500b57cec5SDimitry Andric }
15510b57cec5SDimitry Andric 
15520b57cec5SDimitry Andric static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {
15530b57cec5SDimitry Andric   std::string Buffer;
15540b57cec5SDimitry Andric   raw_string_ostream Stream(Buffer);
15550b57cec5SDimitry Andric 
15560b57cec5SDimitry Andric   // Collect all the PredicateProlog records and print them to the output
15570b57cec5SDimitry Andric   // stream.
15580b57cec5SDimitry Andric   std::vector<Record *> Prologs =
15590b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("PredicateProlog");
15600b57cec5SDimitry Andric   llvm::sort(Prologs, LessRecord());
15610b57cec5SDimitry Andric   for (Record *P : Prologs)
15620b57cec5SDimitry Andric     Stream << P->getValueAsString("Code") << '\n';
15630b57cec5SDimitry Andric 
15640b57cec5SDimitry Andric   OS << Buffer;
15650b57cec5SDimitry Andric }
15660b57cec5SDimitry Andric 
1567e8d8bef9SDimitry Andric static bool isTruePredicate(const Record *Rec) {
1568e8d8bef9SDimitry Andric   return Rec->isSubClassOf("MCSchedPredicate") &&
1569e8d8bef9SDimitry Andric          Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
1570e8d8bef9SDimitry Andric }
1571e8d8bef9SDimitry Andric 
15720b57cec5SDimitry Andric static void emitPredicates(const CodeGenSchedTransition &T,
15730b57cec5SDimitry Andric                            const CodeGenSchedClass &SC, PredicateExpander &PE,
15740b57cec5SDimitry Andric                            raw_ostream &OS) {
15750b57cec5SDimitry Andric   std::string Buffer;
15760b57cec5SDimitry Andric   raw_string_ostream SS(Buffer);
15770b57cec5SDimitry Andric 
15780b57cec5SDimitry Andric   // If not all predicates are MCTrue, then we need an if-stmt.
15790b57cec5SDimitry Andric   unsigned NumNonTruePreds =
1580e8d8bef9SDimitry Andric       T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate);
15810b57cec5SDimitry Andric 
15820b57cec5SDimitry Andric   SS.indent(PE.getIndentLevel() * 2);
15830b57cec5SDimitry Andric 
15840b57cec5SDimitry Andric   if (NumNonTruePreds) {
15850b57cec5SDimitry Andric     bool FirstNonTruePredicate = true;
15860b57cec5SDimitry Andric     SS << "if (";
15870b57cec5SDimitry Andric 
15880b57cec5SDimitry Andric     PE.setIndentLevel(PE.getIndentLevel() + 2);
15890b57cec5SDimitry Andric 
15900b57cec5SDimitry Andric     for (const Record *Rec : T.PredTerm) {
15910b57cec5SDimitry Andric       // Skip predicates that evaluate to "true".
1592e8d8bef9SDimitry Andric       if (isTruePredicate(Rec))
15930b57cec5SDimitry Andric         continue;
15940b57cec5SDimitry Andric 
15950b57cec5SDimitry Andric       if (FirstNonTruePredicate) {
15960b57cec5SDimitry Andric         FirstNonTruePredicate = false;
15970b57cec5SDimitry Andric       } else {
15980b57cec5SDimitry Andric         SS << "\n";
15990b57cec5SDimitry Andric         SS.indent(PE.getIndentLevel() * 2);
16000b57cec5SDimitry Andric         SS << "&& ";
16010b57cec5SDimitry Andric       }
16020b57cec5SDimitry Andric 
16030b57cec5SDimitry Andric       if (Rec->isSubClassOf("MCSchedPredicate")) {
16040b57cec5SDimitry Andric         PE.expandPredicate(SS, Rec->getValueAsDef("Pred"));
16050b57cec5SDimitry Andric         continue;
16060b57cec5SDimitry Andric       }
16070b57cec5SDimitry Andric 
16080b57cec5SDimitry Andric       // Expand this legacy predicate and wrap it around braces if there is more
16090b57cec5SDimitry Andric       // than one predicate to expand.
16100b57cec5SDimitry Andric       SS << ((NumNonTruePreds > 1) ? "(" : "")
16110b57cec5SDimitry Andric          << Rec->getValueAsString("Predicate")
16120b57cec5SDimitry Andric          << ((NumNonTruePreds > 1) ? ")" : "");
16130b57cec5SDimitry Andric     }
16140b57cec5SDimitry Andric 
16150b57cec5SDimitry Andric     SS << ")\n"; // end of if-stmt
16160b57cec5SDimitry Andric     PE.decreaseIndentLevel();
16170b57cec5SDimitry Andric     SS.indent(PE.getIndentLevel() * 2);
16180b57cec5SDimitry Andric     PE.decreaseIndentLevel();
16190b57cec5SDimitry Andric   }
16200b57cec5SDimitry Andric 
16210b57cec5SDimitry Andric   SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n';
16220b57cec5SDimitry Andric   OS << Buffer;
16230b57cec5SDimitry Andric }
16240b57cec5SDimitry Andric 
16250b57cec5SDimitry Andric // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate
16260b57cec5SDimitry Andric // epilogue code for the auto-generated helper.
1627e8d8bef9SDimitry Andric static void emitSchedModelHelperEpilogue(raw_ostream &OS,
1628e8d8bef9SDimitry Andric                                          bool ShouldReturnZero) {
16290b57cec5SDimitry Andric   if (ShouldReturnZero) {
16300b57cec5SDimitry Andric     OS << "  // Don't know how to resolve this scheduling class.\n"
16310b57cec5SDimitry Andric        << "  return 0;\n";
16320b57cec5SDimitry Andric     return;
16330b57cec5SDimitry Andric   }
16340b57cec5SDimitry Andric 
16350b57cec5SDimitry Andric   OS << "  report_fatal_error(\"Expected a variant SchedClass\");\n";
16360b57cec5SDimitry Andric }
16370b57cec5SDimitry Andric 
1638e8d8bef9SDimitry Andric static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
16390b57cec5SDimitry Andric   return all_of(T.PredTerm, [](const Record *Rec) {
16400b57cec5SDimitry Andric     return Rec->isSubClassOf("MCSchedPredicate");
16410b57cec5SDimitry Andric   });
16420b57cec5SDimitry Andric }
16430b57cec5SDimitry Andric 
1644e8d8bef9SDimitry Andric static void collectVariantClasses(const CodeGenSchedModels &SchedModels,
16450b57cec5SDimitry Andric                                   IdxVec &VariantClasses,
16460b57cec5SDimitry Andric                                   bool OnlyExpandMCInstPredicates) {
16470b57cec5SDimitry Andric   for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
16480b57cec5SDimitry Andric     // Ignore non-variant scheduling classes.
16490b57cec5SDimitry Andric     if (SC.Transitions.empty())
16500b57cec5SDimitry Andric       continue;
16510b57cec5SDimitry Andric 
16520b57cec5SDimitry Andric     if (OnlyExpandMCInstPredicates) {
16530b57cec5SDimitry Andric       // Ignore this variant scheduling class no transitions use any meaningful
16540b57cec5SDimitry Andric       // MCSchedPredicate definitions.
16550eae32dcSDimitry Andric       if (llvm::none_of(SC.Transitions, hasMCSchedPredicates))
16560b57cec5SDimitry Andric         continue;
16570b57cec5SDimitry Andric     }
16580b57cec5SDimitry Andric 
16590b57cec5SDimitry Andric     VariantClasses.push_back(SC.Index);
16600b57cec5SDimitry Andric   }
16610b57cec5SDimitry Andric }
16620b57cec5SDimitry Andric 
1663e8d8bef9SDimitry Andric static void collectProcessorIndices(const CodeGenSchedClass &SC,
1664e8d8bef9SDimitry Andric                                     IdxVec &ProcIndices) {
16650b57cec5SDimitry Andric   // A variant scheduling class may define transitions for multiple
16660b57cec5SDimitry Andric   // processors.  This function identifies wich processors are associated with
16670b57cec5SDimitry Andric   // transition rules specified by variant class `SC`.
16680b57cec5SDimitry Andric   for (const CodeGenSchedTransition &T : SC.Transitions) {
16690b57cec5SDimitry Andric     IdxVec PI;
1670e8d8bef9SDimitry Andric     std::set_union(&T.ProcIndex, &T.ProcIndex + 1, ProcIndices.begin(),
1671e8d8bef9SDimitry Andric                    ProcIndices.end(), std::back_inserter(PI));
1672*0fca6ea1SDimitry Andric     ProcIndices = std::move(PI);
16730b57cec5SDimitry Andric   }
16740b57cec5SDimitry Andric }
16750b57cec5SDimitry Andric 
1676e8d8bef9SDimitry Andric static bool isAlwaysTrue(const CodeGenSchedTransition &T) {
16770eae32dcSDimitry Andric   return llvm::all_of(T.PredTerm, isTruePredicate);
1678e8d8bef9SDimitry Andric }
1679e8d8bef9SDimitry Andric 
16800b57cec5SDimitry Andric void SubtargetEmitter::emitSchedModelHelpersImpl(
16810b57cec5SDimitry Andric     raw_ostream &OS, bool OnlyExpandMCInstPredicates) {
16820b57cec5SDimitry Andric   IdxVec VariantClasses;
16830b57cec5SDimitry Andric   collectVariantClasses(SchedModels, VariantClasses,
16840b57cec5SDimitry Andric                         OnlyExpandMCInstPredicates);
16850b57cec5SDimitry Andric 
16860b57cec5SDimitry Andric   if (VariantClasses.empty()) {
16870b57cec5SDimitry Andric     emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
16880b57cec5SDimitry Andric     return;
16890b57cec5SDimitry Andric   }
16900b57cec5SDimitry Andric 
16910b57cec5SDimitry Andric   // Construct a switch statement where the condition is a check on the
16920b57cec5SDimitry Andric   // scheduling class identifier. There is a `case` for every variant class
16930b57cec5SDimitry Andric   // defined by the processor models of this target.
1694*0fca6ea1SDimitry Andric   // Each `case` implements a number of rules to resolve (i.e. to transition
1695*0fca6ea1SDimitry Andric   // from) a variant scheduling class to another scheduling class.  Rules are
16960b57cec5SDimitry Andric   // described by instances of CodeGenSchedTransition. Note that transitions may
16970b57cec5SDimitry Andric   // not be valid for all processors.
16980b57cec5SDimitry Andric   OS << "  switch (SchedClass) {\n";
16990b57cec5SDimitry Andric   for (unsigned VC : VariantClasses) {
17000b57cec5SDimitry Andric     IdxVec ProcIndices;
17010b57cec5SDimitry Andric     const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC);
17020b57cec5SDimitry Andric     collectProcessorIndices(SC, ProcIndices);
17030b57cec5SDimitry Andric 
17040b57cec5SDimitry Andric     OS << "  case " << VC << ": // " << SC.Name << '\n';
17050b57cec5SDimitry Andric 
17060b57cec5SDimitry Andric     PredicateExpander PE(Target);
17070b57cec5SDimitry Andric     PE.setByRef(false);
17080b57cec5SDimitry Andric     PE.setExpandForMC(OnlyExpandMCInstPredicates);
17090b57cec5SDimitry Andric     for (unsigned PI : ProcIndices) {
17100b57cec5SDimitry Andric       OS << "    ";
17110b57cec5SDimitry Andric 
17120b57cec5SDimitry Andric       // Emit a guard on the processor ID.
17130b57cec5SDimitry Andric       if (PI != 0) {
17140b57cec5SDimitry Andric         OS << (OnlyExpandMCInstPredicates
17150b57cec5SDimitry Andric                    ? "if (CPUID == "
17160b57cec5SDimitry Andric                    : "if (SchedModel->getProcessorID() == ");
17170b57cec5SDimitry Andric         OS << PI << ") ";
17180b57cec5SDimitry Andric         OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n';
17190b57cec5SDimitry Andric       }
17200b57cec5SDimitry Andric 
17210b57cec5SDimitry Andric       // Now emit transitions associated with processor PI.
1722e8d8bef9SDimitry Andric       const CodeGenSchedTransition *FinalT = nullptr;
17230b57cec5SDimitry Andric       for (const CodeGenSchedTransition &T : SC.Transitions) {
1724e8d8bef9SDimitry Andric         if (PI != 0 && T.ProcIndex != PI)
17250b57cec5SDimitry Andric           continue;
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric         // Emit only transitions based on MCSchedPredicate, if it's the case.
17280b57cec5SDimitry Andric         // At least the transition specified by NoSchedPred is emitted,
17290b57cec5SDimitry Andric         // which becomes the default transition for those variants otherwise
17300b57cec5SDimitry Andric         // not based on MCSchedPredicate.
17310b57cec5SDimitry Andric         // FIXME: preferably, llvm-mca should instead assume a reasonable
17320b57cec5SDimitry Andric         // default when a variant transition is not based on MCSchedPredicate
17330b57cec5SDimitry Andric         // for a given processor.
17340b57cec5SDimitry Andric         if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))
17350b57cec5SDimitry Andric           continue;
17360b57cec5SDimitry Andric 
1737e8d8bef9SDimitry Andric         // If transition is folded to 'return X' it should be the last one.
1738e8d8bef9SDimitry Andric         if (isAlwaysTrue(T)) {
1739e8d8bef9SDimitry Andric           FinalT = &T;
1740e8d8bef9SDimitry Andric           continue;
1741e8d8bef9SDimitry Andric         }
17420b57cec5SDimitry Andric         PE.setIndentLevel(3);
17430b57cec5SDimitry Andric         emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);
17440b57cec5SDimitry Andric       }
1745e8d8bef9SDimitry Andric       if (FinalT)
1746e8d8bef9SDimitry Andric         emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx),
1747e8d8bef9SDimitry Andric                        PE, OS);
17480b57cec5SDimitry Andric 
17490b57cec5SDimitry Andric       OS << "    }\n";
17500b57cec5SDimitry Andric 
17510b57cec5SDimitry Andric       if (PI == 0)
17520b57cec5SDimitry Andric         break;
17530b57cec5SDimitry Andric     }
17540b57cec5SDimitry Andric 
17550b57cec5SDimitry Andric     if (SC.isInferred())
17560b57cec5SDimitry Andric       OS << "    return " << SC.Index << ";\n";
17570b57cec5SDimitry Andric     OS << "    break;\n";
17580b57cec5SDimitry Andric   }
17590b57cec5SDimitry Andric 
17600b57cec5SDimitry Andric   OS << "  };\n";
17610b57cec5SDimitry Andric 
17620b57cec5SDimitry Andric   emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
17630b57cec5SDimitry Andric }
17640b57cec5SDimitry Andric 
17650b57cec5SDimitry Andric void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
17660b57cec5SDimitry Andric                                              raw_ostream &OS) {
17670b57cec5SDimitry Andric   OS << "unsigned " << ClassName
17680b57cec5SDimitry Andric      << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"
17690b57cec5SDimitry Andric      << " const TargetSchedModel *SchedModel) const {\n";
17700b57cec5SDimitry Andric 
17710b57cec5SDimitry Andric   // Emit the predicate prolog code.
17720b57cec5SDimitry Andric   emitPredicateProlog(Records, OS);
17730b57cec5SDimitry Andric 
17740b57cec5SDimitry Andric   // Emit target predicates.
17750b57cec5SDimitry Andric   emitSchedModelHelpersImpl(OS);
17760b57cec5SDimitry Andric 
17770b57cec5SDimitry Andric   OS << "} // " << ClassName << "::resolveSchedClass\n\n";
17780b57cec5SDimitry Andric 
17790b57cec5SDimitry Andric   OS << "unsigned " << ClassName
17800b57cec5SDimitry Andric      << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"
1781e8d8bef9SDimitry Andric      << " const MCInstrInfo *MCII, unsigned CPUID) const {\n"
17820b57cec5SDimitry Andric      << "  return " << Target << "_MC"
1783e8d8bef9SDimitry Andric      << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"
17840b57cec5SDimitry Andric      << "} // " << ClassName << "::resolveVariantSchedClass\n\n";
17850b57cec5SDimitry Andric 
17860b57cec5SDimitry Andric   STIPredicateExpander PE(Target);
17870b57cec5SDimitry Andric   PE.setClassPrefix(ClassName);
17880b57cec5SDimitry Andric   PE.setExpandDefinition(true);
17890b57cec5SDimitry Andric   PE.setByRef(false);
17900b57cec5SDimitry Andric   PE.setIndentLevel(0);
17910b57cec5SDimitry Andric 
17920b57cec5SDimitry Andric   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
17930b57cec5SDimitry Andric     PE.expandSTIPredicate(OS, Fn);
17940b57cec5SDimitry Andric }
17950b57cec5SDimitry Andric 
17960b57cec5SDimitry Andric void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
17970b57cec5SDimitry Andric                                        raw_ostream &OS) {
17980b57cec5SDimitry Andric   const CodeGenHwModes &CGH = TGT.getHwModes();
17990b57cec5SDimitry Andric   assert(CGH.getNumModeIds() > 0);
18000b57cec5SDimitry Andric   if (CGH.getNumModeIds() == 1)
18010b57cec5SDimitry Andric     return;
18020b57cec5SDimitry Andric 
1803*0fca6ea1SDimitry Andric   // Collect all HwModes and related features defined in the TD files,
1804*0fca6ea1SDimitry Andric   // and store them as a bit set.
1805*0fca6ea1SDimitry Andric   unsigned ValueTypeModes = 0;
1806*0fca6ea1SDimitry Andric   unsigned RegInfoModes = 0;
1807*0fca6ea1SDimitry Andric   unsigned EncodingInfoModes = 0;
1808*0fca6ea1SDimitry Andric   for (const auto &MS : CGH.getHwModeSelects()) {
1809*0fca6ea1SDimitry Andric     for (const HwModeSelect::PairType &P : MS.second.Items) {
1810*0fca6ea1SDimitry Andric       if (P.first == DefaultMode)
1811*0fca6ea1SDimitry Andric         continue;
1812*0fca6ea1SDimitry Andric       if (P.second->isSubClassOf("ValueType")) {
1813*0fca6ea1SDimitry Andric         ValueTypeModes |= (1 << (P.first - 1));
1814*0fca6ea1SDimitry Andric       } else if (P.second->isSubClassOf("RegInfo") ||
1815*0fca6ea1SDimitry Andric                  P.second->isSubClassOf("SubRegRange")) {
1816*0fca6ea1SDimitry Andric         RegInfoModes |= (1 << (P.first - 1));
1817*0fca6ea1SDimitry Andric       } else if (P.second->isSubClassOf("InstructionEncoding")) {
1818*0fca6ea1SDimitry Andric         EncodingInfoModes |= (1 << (P.first - 1));
1819*0fca6ea1SDimitry Andric       }
1820*0fca6ea1SDimitry Andric     }
1821*0fca6ea1SDimitry Andric   }
1822*0fca6ea1SDimitry Andric 
1823*0fca6ea1SDimitry Andric   // Start emitting for getHwModeSet().
1824*0fca6ea1SDimitry Andric   OS << "unsigned " << ClassName << "::getHwModeSet() const {\n";
1825*0fca6ea1SDimitry Andric   OS << "  // Collect HwModes and store them as a bit set.\n";
1826*0fca6ea1SDimitry Andric   OS << "  unsigned Modes = 0;\n";
18270b57cec5SDimitry Andric   for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
18280b57cec5SDimitry Andric     const HwMode &HM = CGH.getMode(M);
1829*0fca6ea1SDimitry Andric     OS << "  if (checkFeatures(\"" << HM.Features << "\")) Modes |= (1 << "
1830*0fca6ea1SDimitry Andric        << (M - 1) << ");\n";
18310b57cec5SDimitry Andric   }
1832*0fca6ea1SDimitry Andric   OS << "  return Modes;\n}\n";
1833*0fca6ea1SDimitry Andric   // End emitting for getHwModeSet().
1834*0fca6ea1SDimitry Andric 
1835*0fca6ea1SDimitry Andric   auto handlePerMode = [&](std::string ModeType, unsigned ModeInBitSet) {
1836*0fca6ea1SDimitry Andric     OS << "  case HwMode_" << ModeType << ":\n"
1837*0fca6ea1SDimitry Andric        << "    Modes &= " << ModeInBitSet << ";\n"
1838*0fca6ea1SDimitry Andric        << "    if (!Modes)\n      return Modes;\n"
1839*0fca6ea1SDimitry Andric        << "    if (!llvm::has_single_bit<unsigned>(Modes))\n"
1840*0fca6ea1SDimitry Andric        << "      llvm_unreachable(\"Two or more HwModes for " << ModeType
1841*0fca6ea1SDimitry Andric        << " were found!\");\n"
1842*0fca6ea1SDimitry Andric        << "    return llvm::countr_zero(Modes) + 1;\n";
1843*0fca6ea1SDimitry Andric   };
1844*0fca6ea1SDimitry Andric 
1845*0fca6ea1SDimitry Andric   // Start emitting for getHwMode().
1846*0fca6ea1SDimitry Andric   OS << "unsigned " << ClassName
1847*0fca6ea1SDimitry Andric      << "::getHwMode(enum HwModeType type) const {\n";
1848*0fca6ea1SDimitry Andric   OS << "  unsigned Modes = getHwModeSet();\n\n";
1849*0fca6ea1SDimitry Andric   OS << "  if (!Modes)\n    return Modes;\n\n";
1850*0fca6ea1SDimitry Andric   OS << "  switch (type) {\n";
1851*0fca6ea1SDimitry Andric   OS << "  case HwMode_Default:\n    return llvm::countr_zero(Modes) + 1;\n";
1852*0fca6ea1SDimitry Andric   handlePerMode("ValueType", ValueTypeModes);
1853*0fca6ea1SDimitry Andric   handlePerMode("RegInfo", RegInfoModes);
1854*0fca6ea1SDimitry Andric   handlePerMode("EncodingInfo", EncodingInfoModes);
1855*0fca6ea1SDimitry Andric   OS << "  }\n";
1856*0fca6ea1SDimitry Andric   OS << "  llvm_unreachable(\"unexpected HwModeType\");\n"
1857*0fca6ea1SDimitry Andric      << "  return 0; // should not get here\n}\n";
1858*0fca6ea1SDimitry Andric   // End emitting for getHwMode().
18590b57cec5SDimitry Andric }
18600b57cec5SDimitry Andric 
18617a6dacacSDimitry Andric void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName,
18627a6dacacSDimitry Andric                                            raw_ostream &OS) {
18637a6dacacSDimitry Andric   if (!TGT.hasMacroFusion())
18647a6dacacSDimitry Andric     return;
18657a6dacacSDimitry Andric 
18667a6dacacSDimitry Andric   OS << "std::vector<MacroFusionPredTy> " << ClassName
18677a6dacacSDimitry Andric      << "::getMacroFusions() const {\n";
18687a6dacacSDimitry Andric   OS.indent(2) << "std::vector<MacroFusionPredTy> Fusions;\n";
18697a6dacacSDimitry Andric   for (auto *Fusion : TGT.getMacroFusions()) {
18707a6dacacSDimitry Andric     std::string Name = Fusion->getNameInitAsString();
18717a6dacacSDimitry Andric     OS.indent(2) << "if (hasFeature(" << Target << "::" << Name
18727a6dacacSDimitry Andric                  << ")) Fusions.push_back(llvm::is" << Name << ");\n";
18737a6dacacSDimitry Andric   }
18747a6dacacSDimitry Andric 
18757a6dacacSDimitry Andric   OS.indent(2) << "return Fusions;\n";
18767a6dacacSDimitry Andric   OS << "}\n";
18777a6dacacSDimitry Andric }
18787a6dacacSDimitry Andric 
187981ad6265SDimitry Andric // Produces a subtarget specific function for parsing
18800b57cec5SDimitry Andric // the subtarget features string.
188181ad6265SDimitry Andric void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
18820b57cec5SDimitry Andric   std::vector<Record *> Features =
18830b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("SubtargetFeature");
18840b57cec5SDimitry Andric   llvm::sort(Features, LessRecord());
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric   OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
18870b57cec5SDimitry Andric      << "// subtarget options.\n"
18880b57cec5SDimitry Andric      << "void llvm::";
18890b57cec5SDimitry Andric   OS << Target;
1890e8d8bef9SDimitry Andric   OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, "
1891e8d8bef9SDimitry Andric      << "StringRef FS) {\n"
18920b57cec5SDimitry Andric      << "  LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
1893e8d8bef9SDimitry Andric      << "  LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n"
1894e8d8bef9SDimitry Andric      << "  LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n";
18950b57cec5SDimitry Andric 
18960b57cec5SDimitry Andric   if (Features.empty()) {
18970b57cec5SDimitry Andric     OS << "}\n";
18980b57cec5SDimitry Andric     return;
18990b57cec5SDimitry Andric   }
19000b57cec5SDimitry Andric 
1901*0fca6ea1SDimitry Andric   if (Target == "AArch64")
1902*0fca6ea1SDimitry Andric     OS << "  CPU = AArch64::resolveCPUAlias(CPU);\n"
1903*0fca6ea1SDimitry Andric        << "  TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";
1904*0fca6ea1SDimitry Andric 
1905e8d8bef9SDimitry Andric   OS << "  InitMCProcessorInfo(CPU, TuneCPU, FS);\n"
19060b57cec5SDimitry Andric      << "  const FeatureBitset &Bits = getFeatureBits();\n";
19070b57cec5SDimitry Andric 
19080b57cec5SDimitry Andric   for (Record *R : Features) {
19090b57cec5SDimitry Andric     // Next record
19100b57cec5SDimitry Andric     StringRef Instance = R->getName();
19110b57cec5SDimitry Andric     StringRef Value = R->getValueAsString("Value");
191206c3fb27SDimitry Andric     StringRef FieldName = R->getValueAsString("FieldName");
19130b57cec5SDimitry Andric 
19140b57cec5SDimitry Andric     if (Value == "true" || Value == "false")
1915*0fca6ea1SDimitry Andric       OS << "  if (Bits[" << Target << "::" << Instance << "]) " << FieldName
1916*0fca6ea1SDimitry Andric          << " = " << Value << ";\n";
19170b57cec5SDimitry Andric     else
1918*0fca6ea1SDimitry Andric       OS << "  if (Bits[" << Target << "::" << Instance << "] && " << FieldName
1919*0fca6ea1SDimitry Andric          << " < " << Value << ") " << FieldName << " = " << Value << ";\n";
19200b57cec5SDimitry Andric   }
19210b57cec5SDimitry Andric 
19220b57cec5SDimitry Andric   OS << "}\n";
19230b57cec5SDimitry Andric }
19240b57cec5SDimitry Andric 
19250b57cec5SDimitry Andric void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
19260b57cec5SDimitry Andric   OS << "namespace " << Target << "_MC {\n"
19270b57cec5SDimitry Andric      << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
1928e8d8bef9SDimitry Andric      << "    const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n";
19290b57cec5SDimitry Andric   emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
19300b57cec5SDimitry Andric   OS << "}\n";
19318bcb0991SDimitry Andric   OS << "} // end namespace " << Target << "_MC\n\n";
19320b57cec5SDimitry Andric 
19330b57cec5SDimitry Andric   OS << "struct " << Target
19340b57cec5SDimitry Andric      << "GenMCSubtargetInfo : public MCSubtargetInfo {\n";
19350b57cec5SDimitry Andric   OS << "  " << Target << "GenMCSubtargetInfo(const Triple &TT,\n"
1936e8d8bef9SDimitry Andric      << "    StringRef CPU, StringRef TuneCPU, StringRef FS,\n"
1937e8d8bef9SDimitry Andric      << "    ArrayRef<SubtargetFeatureKV> PF,\n"
19380b57cec5SDimitry Andric      << "    ArrayRef<SubtargetSubTypeKV> PD,\n"
19390b57cec5SDimitry Andric      << "    const MCWriteProcResEntry *WPR,\n"
19400b57cec5SDimitry Andric      << "    const MCWriteLatencyEntry *WL,\n"
19410b57cec5SDimitry Andric      << "    const MCReadAdvanceEntry *RA, const InstrStage *IS,\n"
19420b57cec5SDimitry Andric      << "    const unsigned *OC, const unsigned *FP) :\n"
1943e8d8bef9SDimitry Andric      << "      MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n"
19440b57cec5SDimitry Andric      << "                      WPR, WL, RA, IS, OC, FP) { }\n\n"
19450b57cec5SDimitry Andric      << "  unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
1946e8d8bef9SDimitry Andric      << "      const MCInst *MI, const MCInstrInfo *MCII,\n"
1947e8d8bef9SDimitry Andric      << "      unsigned CPUID) const override {\n"
19480b57cec5SDimitry Andric      << "    return " << Target << "_MC"
1949e8d8bef9SDimitry Andric      << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n";
19500b57cec5SDimitry Andric   OS << "  }\n";
1951*0fca6ea1SDimitry Andric   if (TGT.getHwModes().getNumModeIds() > 1) {
1952*0fca6ea1SDimitry Andric     OS << "  unsigned getHwModeSet() const override;\n";
1953*0fca6ea1SDimitry Andric     OS << "  unsigned getHwMode(enum HwModeType type = HwMode_Default) const "
1954*0fca6ea1SDimitry Andric           "override;\n";
1955*0fca6ea1SDimitry Andric   }
1956*0fca6ea1SDimitry Andric   if (Target == "AArch64")
1957*0fca6ea1SDimitry Andric     OS << "  bool isCPUStringValid(StringRef CPU) const override {\n"
1958*0fca6ea1SDimitry Andric        << "    CPU = AArch64::resolveCPUAlias(CPU);\n"
1959*0fca6ea1SDimitry Andric        << "    return MCSubtargetInfo::isCPUStringValid(CPU);\n"
1960*0fca6ea1SDimitry Andric        << "  }\n";
19610b57cec5SDimitry Andric   OS << "};\n";
19628bcb0991SDimitry Andric   EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
19630b57cec5SDimitry Andric }
19640b57cec5SDimitry Andric 
19650b57cec5SDimitry Andric void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) {
19660b57cec5SDimitry Andric   OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n";
19670b57cec5SDimitry Andric   OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
19680b57cec5SDimitry Andric 
19690b57cec5SDimitry Andric   STIPredicateExpander PE(Target);
19700b57cec5SDimitry Andric   PE.setExpandForMC(true);
19710b57cec5SDimitry Andric   PE.setByRef(true);
19720b57cec5SDimitry Andric   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
19730b57cec5SDimitry Andric     PE.expandSTIPredicate(OS, Fn);
19740b57cec5SDimitry Andric 
19750b57cec5SDimitry Andric   OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
19760b57cec5SDimitry Andric 
19770b57cec5SDimitry Andric   OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n";
19780b57cec5SDimitry Andric   OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
19790b57cec5SDimitry Andric 
19800b57cec5SDimitry Andric   std::string ClassPrefix = Target + "MCInstrAnalysis";
19810b57cec5SDimitry Andric   PE.setExpandDefinition(true);
19820b57cec5SDimitry Andric   PE.setClassPrefix(ClassPrefix);
19830b57cec5SDimitry Andric   PE.setIndentLevel(0);
19840b57cec5SDimitry Andric   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
19850b57cec5SDimitry Andric     PE.expandSTIPredicate(OS, Fn);
19860b57cec5SDimitry Andric 
19870b57cec5SDimitry Andric   OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
19880b57cec5SDimitry Andric }
19890b57cec5SDimitry Andric 
19900b57cec5SDimitry Andric //
19910b57cec5SDimitry Andric // SubtargetEmitter::run - Main subtarget enumeration emitter.
19920b57cec5SDimitry Andric //
19930b57cec5SDimitry Andric void SubtargetEmitter::run(raw_ostream &OS) {
19940b57cec5SDimitry Andric   emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
19950b57cec5SDimitry Andric 
19960b57cec5SDimitry Andric   OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
19970b57cec5SDimitry Andric   OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";
19980b57cec5SDimitry Andric 
19990b57cec5SDimitry Andric   DenseMap<Record *, unsigned> FeatureMap;
20000b57cec5SDimitry Andric 
20010b57cec5SDimitry Andric   OS << "namespace llvm {\n";
20020b57cec5SDimitry Andric   Enumeration(OS, FeatureMap);
20030b57cec5SDimitry Andric   OS << "} // end namespace llvm\n\n";
20040b57cec5SDimitry Andric   OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
20050b57cec5SDimitry Andric 
200681ad6265SDimitry Andric   EmitSubtargetInfoMacroCalls(OS);
20070b57cec5SDimitry Andric 
20080b57cec5SDimitry Andric   OS << "namespace llvm {\n";
20090b57cec5SDimitry Andric #if 0
20100b57cec5SDimitry Andric   OS << "namespace {\n";
20110b57cec5SDimitry Andric #endif
20120b57cec5SDimitry Andric   unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap);
20130b57cec5SDimitry Andric   OS << "\n";
20140b57cec5SDimitry Andric   EmitSchedModel(OS);
20150b57cec5SDimitry Andric   OS << "\n";
20160b57cec5SDimitry Andric   unsigned NumProcs = CPUKeyValues(OS, FeatureMap);
20170b57cec5SDimitry Andric   OS << "\n";
20180b57cec5SDimitry Andric #if 0
20190b57cec5SDimitry Andric   OS << "} // end anonymous namespace\n\n";
20200b57cec5SDimitry Andric #endif
20210b57cec5SDimitry Andric 
20220b57cec5SDimitry Andric   // MCInstrInfo initialization routine.
20230b57cec5SDimitry Andric   emitGenMCSubtargetInfo(OS);
20240b57cec5SDimitry Andric 
20250b57cec5SDimitry Andric   OS << "\nstatic inline MCSubtargetInfo *create" << Target
20260b57cec5SDimitry Andric      << "MCSubtargetInfoImpl("
2027e8d8bef9SDimitry Andric      << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n";
2028*0fca6ea1SDimitry Andric   if (Target == "AArch64")
2029*0fca6ea1SDimitry Andric     OS << "  CPU = AArch64::resolveCPUAlias(CPU);\n"
2030*0fca6ea1SDimitry Andric        << "  TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";
2031e8d8bef9SDimitry Andric   OS << "  return new " << Target
2032e8d8bef9SDimitry Andric      << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, ";
20330b57cec5SDimitry Andric   if (NumFeatures)
20340b57cec5SDimitry Andric     OS << Target << "FeatureKV, ";
20350b57cec5SDimitry Andric   else
2036bdd1243dSDimitry Andric     OS << "std::nullopt, ";
20370b57cec5SDimitry Andric   if (NumProcs)
20380b57cec5SDimitry Andric     OS << Target << "SubTypeKV, ";
20390b57cec5SDimitry Andric   else
20405f757f3fSDimitry Andric     OS << "std::nullopt, ";
2041*0fca6ea1SDimitry Andric   OS << '\n';
2042*0fca6ea1SDimitry Andric   OS.indent(22);
2043*0fca6ea1SDimitry Andric   OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
20440b57cec5SDimitry Andric      << Target << "ReadAdvanceTable, ";
2045*0fca6ea1SDimitry Andric   OS << '\n';
2046*0fca6ea1SDimitry Andric   OS.indent(22);
20470b57cec5SDimitry Andric   if (SchedModels.hasItineraries()) {
2048*0fca6ea1SDimitry Andric     OS << Target << "Stages, " << Target << "OperandCycles, " << Target
2049*0fca6ea1SDimitry Andric        << "ForwardingPaths";
20500b57cec5SDimitry Andric   } else
20510b57cec5SDimitry Andric     OS << "nullptr, nullptr, nullptr";
20520b57cec5SDimitry Andric   OS << ");\n}\n\n";
20530b57cec5SDimitry Andric 
20540b57cec5SDimitry Andric   OS << "} // end namespace llvm\n\n";
20550b57cec5SDimitry Andric 
20560b57cec5SDimitry Andric   OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
20570b57cec5SDimitry Andric 
20580b57cec5SDimitry Andric   OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
20590b57cec5SDimitry Andric   OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";
20600b57cec5SDimitry Andric 
20610b57cec5SDimitry Andric   OS << "#include \"llvm/Support/Debug.h\"\n";
20620b57cec5SDimitry Andric   OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";
2063*0fca6ea1SDimitry Andric   if (Target == "AArch64")
2064*0fca6ea1SDimitry Andric     OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
206581ad6265SDimitry Andric   ParseFeaturesFunction(OS);
20660b57cec5SDimitry Andric 
20670b57cec5SDimitry Andric   OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
20680b57cec5SDimitry Andric 
20690b57cec5SDimitry Andric   // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
20700b57cec5SDimitry Andric   OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
20710b57cec5SDimitry Andric   OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";
20720b57cec5SDimitry Andric 
20730b57cec5SDimitry Andric   std::string ClassName = Target + "GenSubtargetInfo";
20740b57cec5SDimitry Andric   OS << "namespace llvm {\n";
20750b57cec5SDimitry Andric   OS << "class DFAPacketizer;\n";
20760b57cec5SDimitry Andric   OS << "namespace " << Target << "_MC {\n"
20770b57cec5SDimitry Andric      << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
2078e8d8bef9SDimitry Andric      << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n"
20798bcb0991SDimitry Andric      << "} // end namespace " << Target << "_MC\n\n";
20800b57cec5SDimitry Andric   OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
20810b57cec5SDimitry Andric      << "  explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
2082e8d8bef9SDimitry Andric      << "StringRef TuneCPU, StringRef FS);\n"
20830b57cec5SDimitry Andric      << "public:\n"
20840b57cec5SDimitry Andric      << "  unsigned resolveSchedClass(unsigned SchedClass, "
20850b57cec5SDimitry Andric      << " const MachineInstr *DefMI,"
20860b57cec5SDimitry Andric      << " const TargetSchedModel *SchedModel) const override;\n"
20870b57cec5SDimitry Andric      << "  unsigned resolveVariantSchedClass(unsigned SchedClass,"
2088e8d8bef9SDimitry Andric      << " const MCInst *MI, const MCInstrInfo *MCII,"
2089e8d8bef9SDimitry Andric      << " unsigned CPUID) const override;\n"
20900b57cec5SDimitry Andric      << "  DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
20910b57cec5SDimitry Andric      << " const;\n";
2092*0fca6ea1SDimitry Andric   if (TGT.getHwModes().getNumModeIds() > 1) {
2093*0fca6ea1SDimitry Andric     OS << "  unsigned getHwModeSet() const override;\n";
2094*0fca6ea1SDimitry Andric     OS << "  unsigned getHwMode(enum HwModeType type = HwMode_Default) const "
2095*0fca6ea1SDimitry Andric           "override;\n";
2096*0fca6ea1SDimitry Andric   }
20977a6dacacSDimitry Andric   if (TGT.hasMacroFusion())
20987a6dacacSDimitry Andric     OS << "  std::vector<MacroFusionPredTy> getMacroFusions() const "
20997a6dacacSDimitry Andric           "override;\n";
21000b57cec5SDimitry Andric 
21010b57cec5SDimitry Andric   STIPredicateExpander PE(Target);
21020b57cec5SDimitry Andric   PE.setByRef(false);
21030b57cec5SDimitry Andric   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
21040b57cec5SDimitry Andric     PE.expandSTIPredicate(OS, Fn);
21050b57cec5SDimitry Andric 
21060b57cec5SDimitry Andric   OS << "};\n"
21070b57cec5SDimitry Andric      << "} // end namespace llvm\n\n";
21080b57cec5SDimitry Andric 
21090b57cec5SDimitry Andric   OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
21100b57cec5SDimitry Andric 
21110b57cec5SDimitry Andric   OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
21120b57cec5SDimitry Andric   OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";
21130b57cec5SDimitry Andric 
21140b57cec5SDimitry Andric   OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
21150b57cec5SDimitry Andric   OS << "namespace llvm {\n";
21160b57cec5SDimitry Andric   OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
21170b57cec5SDimitry Andric   OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
2118*0fca6ea1SDimitry Andric   OS << "extern const llvm::MCWriteProcResEntry " << Target
2119*0fca6ea1SDimitry Andric      << "WriteProcResTable[];\n";
2120*0fca6ea1SDimitry Andric   OS << "extern const llvm::MCWriteLatencyEntry " << Target
2121*0fca6ea1SDimitry Andric      << "WriteLatencyTable[];\n";
2122*0fca6ea1SDimitry Andric   OS << "extern const llvm::MCReadAdvanceEntry " << Target
2123*0fca6ea1SDimitry Andric      << "ReadAdvanceTable[];\n";
21240b57cec5SDimitry Andric 
21250b57cec5SDimitry Andric   if (SchedModels.hasItineraries()) {
21260b57cec5SDimitry Andric     OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
21270b57cec5SDimitry Andric     OS << "extern const unsigned " << Target << "OperandCycles[];\n";
21280b57cec5SDimitry Andric     OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
21290b57cec5SDimitry Andric   }
21300b57cec5SDimitry Andric 
21310b57cec5SDimitry Andric   OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
2132*0fca6ea1SDimitry Andric      << "StringRef TuneCPU, StringRef FS)\n";
2133*0fca6ea1SDimitry Andric 
2134*0fca6ea1SDimitry Andric   if (Target == "AArch64")
2135*0fca6ea1SDimitry Andric     OS << "  : TargetSubtargetInfo(TT, AArch64::resolveCPUAlias(CPU),\n"
2136*0fca6ea1SDimitry Andric        << "                        AArch64::resolveCPUAlias(TuneCPU), FS, ";
2137*0fca6ea1SDimitry Andric   else
2138*0fca6ea1SDimitry Andric     OS << "  : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
21390b57cec5SDimitry Andric   if (NumFeatures)
2140bdd1243dSDimitry Andric     OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
21410b57cec5SDimitry Andric   else
2142bdd1243dSDimitry Andric     OS << "std::nullopt, ";
21430b57cec5SDimitry Andric   if (NumProcs)
2144bdd1243dSDimitry Andric     OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
21450b57cec5SDimitry Andric   else
21465f757f3fSDimitry Andric     OS << "std::nullopt, ";
2147*0fca6ea1SDimitry Andric   OS << '\n';
2148*0fca6ea1SDimitry Andric   OS.indent(24);
2149*0fca6ea1SDimitry Andric   OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
21500b57cec5SDimitry Andric      << Target << "ReadAdvanceTable, ";
2151*0fca6ea1SDimitry Andric   OS << '\n';
2152*0fca6ea1SDimitry Andric   OS.indent(24);
21530b57cec5SDimitry Andric   if (SchedModels.hasItineraries()) {
2154*0fca6ea1SDimitry Andric     OS << Target << "Stages, " << Target << "OperandCycles, " << Target
2155*0fca6ea1SDimitry Andric        << "ForwardingPaths";
21560b57cec5SDimitry Andric   } else
21570b57cec5SDimitry Andric     OS << "nullptr, nullptr, nullptr";
21580b57cec5SDimitry Andric   OS << ") {}\n\n";
21590b57cec5SDimitry Andric 
21600b57cec5SDimitry Andric   EmitSchedModelHelpers(ClassName, OS);
21610b57cec5SDimitry Andric   EmitHwModeCheck(ClassName, OS);
21627a6dacacSDimitry Andric   emitGetMacroFusions(ClassName, OS);
21630b57cec5SDimitry Andric 
21640b57cec5SDimitry Andric   OS << "} // end namespace llvm\n\n";
21650b57cec5SDimitry Andric 
21660b57cec5SDimitry Andric   OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
21670b57cec5SDimitry Andric 
21680b57cec5SDimitry Andric   EmitMCInstrAnalysisPredicateFunctions(OS);
21690b57cec5SDimitry Andric }
21700b57cec5SDimitry Andric 
217106c3fb27SDimitry Andric static TableGen::Emitter::OptClass<SubtargetEmitter>
217206c3fb27SDimitry Andric     X("gen-subtarget", "Generate subtarget enumerations");
2173