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