Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/SubtargetEmitter.cpp
35258 views
//===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend emits subtarget enumerations.9//10//===----------------------------------------------------------------------===//1112#include "Common/CodeGenHwModes.h"13#include "Common/CodeGenSchedule.h"14#include "Common/CodeGenTarget.h"15#include "Common/PredicateExpander.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/SmallPtrSet.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/MC/MCInstrItineraries.h"21#include "llvm/MC/MCSchedule.h"22#include "llvm/Support/Debug.h"23#include "llvm/Support/Format.h"24#include "llvm/Support/raw_ostream.h"25#include "llvm/TableGen/Error.h"26#include "llvm/TableGen/Record.h"27#include "llvm/TableGen/TableGenBackend.h"28#include "llvm/TargetParser/SubtargetFeature.h"29#include <algorithm>30#include <cassert>31#include <cstdint>32#include <iterator>33#include <map>34#include <set>35#include <string>36#include <vector>3738using namespace llvm;3940#define DEBUG_TYPE "subtarget-emitter"4142namespace {4344/// Sorting predicate to sort record pointers by their45/// FieldName field.46struct LessRecordFieldFieldName {47bool operator()(const Record *Rec1, const Record *Rec2) const {48return Rec1->getValueAsString("FieldName") <49Rec2->getValueAsString("FieldName");50}51};5253class SubtargetEmitter {54// Each processor has a SchedClassDesc table with an entry for each55// SchedClass. The SchedClassDesc table indexes into a global write resource56// table, write latency table, and read advance table.57struct SchedClassTables {58std::vector<std::vector<MCSchedClassDesc>> ProcSchedClasses;59std::vector<MCWriteProcResEntry> WriteProcResources;60std::vector<MCWriteLatencyEntry> WriteLatencies;61std::vector<std::string> WriterNames;62std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;6364// Reserve an invalid entry at index 065SchedClassTables() {66ProcSchedClasses.resize(1);67WriteProcResources.resize(1);68WriteLatencies.resize(1);69WriterNames.push_back("InvalidWrite");70ReadAdvanceEntries.resize(1);71}72};7374struct LessWriteProcResources {75bool operator()(const MCWriteProcResEntry &LHS,76const MCWriteProcResEntry &RHS) {77return LHS.ProcResourceIdx < RHS.ProcResourceIdx;78}79};8081CodeGenTarget TGT;82RecordKeeper &Records;83CodeGenSchedModels &SchedModels;84std::string Target;8586void Enumeration(raw_ostream &OS, DenseMap<Record *, unsigned> &FeatureMap);87void EmitSubtargetInfoMacroCalls(raw_ostream &OS);88unsigned FeatureKeyValues(raw_ostream &OS,89const DenseMap<Record *, unsigned> &FeatureMap);90unsigned CPUKeyValues(raw_ostream &OS,91const DenseMap<Record *, unsigned> &FeatureMap);92void FormItineraryStageString(const std::string &Names, Record *ItinData,93std::string &ItinString, unsigned &NStages);94void FormItineraryOperandCycleString(Record *ItinData,95std::string &ItinString,96unsigned &NOperandCycles);97void FormItineraryBypassString(const std::string &Names, Record *ItinData,98std::string &ItinString,99unsigned NOperandCycles);100void EmitStageAndOperandCycleData(101raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists);102void EmitItineraries(raw_ostream &OS,103std::vector<std::vector<InstrItinerary>> &ProcItinLists);104unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel,105raw_ostream &OS);106void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,107raw_ostream &OS);108void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,109raw_ostream &OS);110void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name,111char Separator);112void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel,113raw_ostream &OS);114void EmitProcessorResources(const CodeGenProcModel &ProcModel,115raw_ostream &OS);116Record *FindWriteResources(const CodeGenSchedRW &SchedWrite,117const CodeGenProcModel &ProcModel);118Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,119const CodeGenProcModel &ProcModel);120void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &ReleaseAtCycles,121std::vector<int64_t> &AcquireAtCycles,122const CodeGenProcModel &ProcModel);123void GenSchedClassTables(const CodeGenProcModel &ProcModel,124SchedClassTables &SchedTables);125void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);126void EmitProcessorModels(raw_ostream &OS);127void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS);128void emitSchedModelHelpersImpl(raw_ostream &OS,129bool OnlyExpandMCInstPredicates = false);130void emitGenMCSubtargetInfo(raw_ostream &OS);131void EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS);132133void EmitSchedModel(raw_ostream &OS);134void emitGetMacroFusions(const std::string &ClassName, raw_ostream &OS);135void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS);136void ParseFeaturesFunction(raw_ostream &OS);137138public:139SubtargetEmitter(RecordKeeper &R)140: TGT(R), Records(R), SchedModels(TGT.getSchedModels()),141Target(TGT.getName()) {}142143void run(raw_ostream &o);144};145146} // end anonymous namespace147148//149// Enumeration - Emit the specified class as an enumeration.150//151void SubtargetEmitter::Enumeration(raw_ostream &OS,152DenseMap<Record *, unsigned> &FeatureMap) {153// Get all records of class and sort154std::vector<Record *> DefList =155Records.getAllDerivedDefinitions("SubtargetFeature");156llvm::sort(DefList, LessRecord());157158unsigned N = DefList.size();159if (N == 0)160return;161if (N + 1 > MAX_SUBTARGET_FEATURES)162PrintFatalError(163"Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");164165OS << "namespace " << Target << " {\n";166167// Open enumeration.168OS << "enum {\n";169170// For each record171for (unsigned i = 0; i < N; ++i) {172// Next record173Record *Def = DefList[i];174175// Get and emit name176OS << " " << Def->getName() << " = " << i << ",\n";177178// Save the index for this feature.179FeatureMap[Def] = i;180}181182OS << " "183<< "NumSubtargetFeatures = " << N << "\n";184185// Close enumeration and namespace186OS << "};\n";187OS << "} // end namespace " << Target << "\n";188}189190static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList,191const DenseMap<Record *, unsigned> &FeatureMap) {192std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};193for (const Record *Feature : FeatureList) {194unsigned Bit = FeatureMap.lookup(Feature);195Mask[Bit / 64] |= 1ULL << (Bit % 64);196}197198OS << "{ { { ";199for (unsigned i = 0; i != Mask.size(); ++i) {200OS << "0x";201OS.write_hex(Mask[i]);202OS << "ULL, ";203}204OS << "} } }";205}206207/// Emit some information about the SubtargetFeature as calls to a macro so208/// that they can be used from C++.209void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) {210OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n";211212std::vector<Record *> FeatureList =213Records.getAllDerivedDefinitions("SubtargetFeature");214llvm::sort(FeatureList, LessRecordFieldFieldName());215216for (const Record *Feature : FeatureList) {217const StringRef FieldName = Feature->getValueAsString("FieldName");218const StringRef Value = Feature->getValueAsString("Value");219220// Only handle boolean features for now, excluding BitVectors and enums.221const bool IsBool = (Value == "false" || Value == "true") &&222!StringRef(FieldName).contains('[');223if (!IsBool)224continue;225226// Some features default to true, with values set to false if enabled.227const char *Default = Value == "false" ? "true" : "false";228229// Define the getter with lowercased first char: xxxYyy() { return XxxYyy; }230const std::string Getter =231FieldName.substr(0, 1).lower() + FieldName.substr(1).str();232233OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", "234<< Getter << ")\n";235}236OS << "#undef GET_SUBTARGETINFO_MACRO\n";237OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n";238239OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";240OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";241242if (Target == "AArch64")243OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";244}245246//247// FeatureKeyValues - Emit data of all the subtarget features. Used by the248// command line.249//250unsigned SubtargetEmitter::FeatureKeyValues(251raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap) {252// Gather and sort all the features253std::vector<Record *> FeatureList =254Records.getAllDerivedDefinitions("SubtargetFeature");255256if (FeatureList.empty())257return 0;258259llvm::sort(FeatureList, LessRecordFieldName());260261// Check that there are no duplicate keys262std::set<StringRef> UniqueKeys;263264// Begin feature table265OS << "// Sorted (by key) array of values for CPU features.\n"266<< "extern const llvm::SubtargetFeatureKV " << Target267<< "FeatureKV[] = {\n";268269// For each feature270unsigned NumFeatures = 0;271for (const Record *Feature : FeatureList) {272// Next feature273StringRef Name = Feature->getName();274StringRef CommandLineName = Feature->getValueAsString("Name");275StringRef Desc = Feature->getValueAsString("Desc");276277if (CommandLineName.empty())278continue;279280// Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in281// } }282OS << " { "283<< "\"" << CommandLineName << "\", "284<< "\"" << Desc << "\", " << Target << "::" << Name << ", ";285286RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");287288printFeatureMask(OS, ImpliesList, FeatureMap);289290OS << " },\n";291++NumFeatures;292293if (!UniqueKeys.insert(CommandLineName).second)294PrintFatalError("Duplicate key in SubtargetFeatureKV: " +295CommandLineName);296}297298// End feature table299OS << "};\n";300301return NumFeatures;302}303304//305// CPUKeyValues - Emit data of all the subtarget processors. Used by command306// line.307//308unsigned309SubtargetEmitter::CPUKeyValues(raw_ostream &OS,310const DenseMap<Record *, unsigned> &FeatureMap) {311// Gather and sort processor information312std::vector<Record *> ProcessorList =313Records.getAllDerivedDefinitions("Processor");314llvm::sort(ProcessorList, LessRecordFieldName());315316// Begin processor table317OS << "// Sorted (by key) array of values for CPU subtype.\n"318<< "extern const llvm::SubtargetSubTypeKV " << Target319<< "SubTypeKV[] = {\n";320321// For each processor322for (Record *Processor : ProcessorList) {323StringRef Name = Processor->getValueAsString("Name");324RecVec FeatureList = Processor->getValueAsListOfDefs("Features");325RecVec TuneFeatureList = Processor->getValueAsListOfDefs("TuneFeatures");326327// Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } },328OS << " { "329<< "\"" << Name << "\", ";330331printFeatureMask(OS, FeatureList, FeatureMap);332OS << ", ";333printFeatureMask(OS, TuneFeatureList, FeatureMap);334335// Emit the scheduler model pointer.336const std::string &ProcModelName =337SchedModels.getModelForProc(Processor).ModelName;338OS << ", &" << ProcModelName << " },\n";339}340341// End processor table342OS << "};\n";343344return ProcessorList.size();345}346347//348// FormItineraryStageString - Compose a string containing the stage349// data initialization for the specified itinerary. N is the number350// of stages.351//352void SubtargetEmitter::FormItineraryStageString(const std::string &Name,353Record *ItinData,354std::string &ItinString,355unsigned &NStages) {356// Get states list357RecVec StageList = ItinData->getValueAsListOfDefs("Stages");358359// For each stage360unsigned N = NStages = StageList.size();361for (unsigned i = 0; i < N;) {362// Next stage363const Record *Stage = StageList[i];364365// Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }366int Cycles = Stage->getValueAsInt("Cycles");367ItinString += " { " + itostr(Cycles) + ", ";368369// Get unit list370RecVec UnitList = Stage->getValueAsListOfDefs("Units");371372// For each unit373for (unsigned j = 0, M = UnitList.size(); j < M;) {374// Add name and bitwise or375ItinString += Name + "FU::" + UnitList[j]->getName().str();376if (++j < M)377ItinString += " | ";378}379380int TimeInc = Stage->getValueAsInt("TimeInc");381ItinString += ", " + itostr(TimeInc);382383int Kind = Stage->getValueAsInt("Kind");384ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);385386// Close off stage387ItinString += " }";388if (++i < N)389ItinString += ", ";390}391}392393//394// FormItineraryOperandCycleString - Compose a string containing the395// operand cycle initialization for the specified itinerary. N is the396// number of operands that has cycles specified.397//398void SubtargetEmitter::FormItineraryOperandCycleString(399Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) {400// Get operand cycle list401std::vector<int64_t> OperandCycleList =402ItinData->getValueAsListOfInts("OperandCycles");403404// For each operand cycle405NOperandCycles = OperandCycleList.size();406ListSeparator LS;407for (int OCycle : OperandCycleList) {408// Next operand cycle409ItinString += LS;410ItinString += " " + itostr(OCycle);411}412}413414void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,415Record *ItinData,416std::string &ItinString,417unsigned NOperandCycles) {418RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses");419unsigned N = BypassList.size();420unsigned i = 0;421ListSeparator LS;422for (; i < N; ++i) {423ItinString += LS;424ItinString += Name + "Bypass::" + BypassList[i]->getName().str();425}426for (; i < NOperandCycles; ++i) {427ItinString += LS;428ItinString += " 0";429}430}431432//433// EmitStageAndOperandCycleData - Generate unique itinerary stages and operand434// cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed435// by CodeGenSchedClass::Index.436//437void SubtargetEmitter::EmitStageAndOperandCycleData(438raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) {439// Multiple processor models may share an itinerary record. Emit it once.440SmallPtrSet<Record *, 8> ItinsDefSet;441442// Emit functional units for all the itineraries.443for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {444445if (!ItinsDefSet.insert(ProcModel.ItinsDef).second)446continue;447448RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU");449if (FUs.empty())450continue;451452StringRef Name = ProcModel.ItinsDef->getName();453OS << "\n// Functional units for \"" << Name << "\"\n"454<< "namespace " << Name << "FU {\n";455456for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)457OS << " const InstrStage::FuncUnits " << FUs[j]->getName()458<< " = 1ULL << " << j << ";\n";459460OS << "} // end namespace " << Name << "FU\n";461462RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");463if (!BPs.empty()) {464OS << "\n// Pipeline forwarding paths for itineraries \"" << Name465<< "\"\n"466<< "namespace " << Name << "Bypass {\n";467468OS << " const unsigned NoBypass = 0;\n";469for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)470OS << " const unsigned " << BPs[j]->getName() << " = 1 << " << j471<< ";\n";472473OS << "} // end namespace " << Name << "Bypass\n";474}475}476477// Begin stages table478std::string StageTable =479"\nextern const llvm::InstrStage " + Target + "Stages[] = {\n";480StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";481482// Begin operand cycle table483std::string OperandCycleTable =484"extern const unsigned " + Target + "OperandCycles[] = {\n";485OperandCycleTable += " 0, // No itinerary\n";486487// Begin pipeline bypass table488std::string BypassTable =489"extern const unsigned " + Target + "ForwardingPaths[] = {\n";490BypassTable += " 0, // No itinerary\n";491492// For each Itinerary across all processors, add a unique entry to the stages,493// operand cycles, and pipeline bypass tables. Then add the new Itinerary494// object with computed offsets to the ProcItinLists result.495unsigned StageCount = 1, OperandCycleCount = 1;496std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;497for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {498// Add process itinerary to the list.499std::vector<InstrItinerary> &ItinList = ProcItinLists.emplace_back();500501// If this processor defines no itineraries, then leave the itinerary list502// empty.503if (!ProcModel.hasItineraries())504continue;505506StringRef Name = ProcModel.ItinsDef->getName();507508ItinList.resize(SchedModels.numInstrSchedClasses());509assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");510511for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();512SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {513514// Next itinerary data515Record *ItinData = ProcModel.ItinDefList[SchedClassIdx];516517// Get string and stage count518std::string ItinStageString;519unsigned NStages = 0;520if (ItinData)521FormItineraryStageString(std::string(Name), ItinData, ItinStageString,522NStages);523524// Get string and operand cycle count525std::string ItinOperandCycleString;526unsigned NOperandCycles = 0;527std::string ItinBypassString;528if (ItinData) {529FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,530NOperandCycles);531532FormItineraryBypassString(std::string(Name), ItinData, ItinBypassString,533NOperandCycles);534}535536// Check to see if stage already exists and create if it doesn't537uint16_t FindStage = 0;538if (NStages > 0) {539FindStage = ItinStageMap[ItinStageString];540if (FindStage == 0) {541// Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices542StageTable += ItinStageString + ", // " + itostr(StageCount);543if (NStages > 1)544StageTable += "-" + itostr(StageCount + NStages - 1);545StageTable += "\n";546// Record Itin class number.547ItinStageMap[ItinStageString] = FindStage = StageCount;548StageCount += NStages;549}550}551552// Check to see if operand cycle already exists and create if it doesn't553uint16_t FindOperandCycle = 0;554if (NOperandCycles > 0) {555std::string ItinOperandString =556ItinOperandCycleString + ItinBypassString;557FindOperandCycle = ItinOperandMap[ItinOperandString];558if (FindOperandCycle == 0) {559// Emit as cycle, // index560OperandCycleTable += ItinOperandCycleString + ", // ";561std::string OperandIdxComment = itostr(OperandCycleCount);562if (NOperandCycles > 1)563OperandIdxComment +=564"-" + itostr(OperandCycleCount + NOperandCycles - 1);565OperandCycleTable += OperandIdxComment + "\n";566// Record Itin class number.567ItinOperandMap[ItinOperandCycleString] = FindOperandCycle =568OperandCycleCount;569// Emit as bypass, // index570BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";571OperandCycleCount += NOperandCycles;572}573}574575// Set up itinerary as location and location + stage count576int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0;577InstrItinerary Intinerary = {578NumUOps,579FindStage,580uint16_t(FindStage + NStages),581FindOperandCycle,582uint16_t(FindOperandCycle + NOperandCycles),583};584585// Inject - empty slots will be 0, 0586ItinList[SchedClassIdx] = Intinerary;587}588}589590// Closing stage591StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n";592StageTable += "};\n";593594// Closing operand cycles595OperandCycleTable += " 0 // End operand cycles\n";596OperandCycleTable += "};\n";597598BypassTable += " 0 // End bypass tables\n";599BypassTable += "};\n";600601// Emit tables.602OS << StageTable;603OS << OperandCycleTable;604OS << BypassTable;605}606607//608// EmitProcessorData - Generate data for processor itineraries that were609// computed during EmitStageAndOperandCycleData(). ProcItinLists lists all610// Itineraries for each processor. The Itinerary lists are indexed on611// CodeGenSchedClass::Index.612//613void SubtargetEmitter::EmitItineraries(614raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) {615// Multiple processor models may share an itinerary record. Emit it once.616SmallPtrSet<Record *, 8> ItinsDefSet;617618// For each processor's machine model619std::vector<std::vector<InstrItinerary>>::iterator ProcItinListsIter =620ProcItinLists.begin();621for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),622PE = SchedModels.procModelEnd();623PI != PE; ++PI, ++ProcItinListsIter) {624625Record *ItinsDef = PI->ItinsDef;626if (!ItinsDefSet.insert(ItinsDef).second)627continue;628629// Get the itinerary list for the processor.630assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator");631std::vector<InstrItinerary> &ItinList = *ProcItinListsIter;632633// Empty itineraries aren't referenced anywhere in the tablegen output634// so don't emit them.635if (ItinList.empty())636continue;637638OS << "\n";639OS << "static const llvm::InstrItinerary ";640641// Begin processor itinerary table642OS << ItinsDef->getName() << "[] = {\n";643644// For each itinerary class in CodeGenSchedClass::Index order.645for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {646InstrItinerary &Intinerary = ItinList[j];647648// Emit Itinerary in the form of649// { firstStage, lastStage, firstCycle, lastCycle } // index650OS << " { " << Intinerary.NumMicroOps << ", " << Intinerary.FirstStage651<< ", " << Intinerary.LastStage << ", " << Intinerary.FirstOperandCycle652<< ", " << Intinerary.LastOperandCycle << " }"653<< ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";654}655// End processor itinerary table656OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }"657"// end marker\n";658OS << "};\n";659}660}661662// Emit either the value defined in the TableGen Record, or the default663// value defined in the C++ header. The Record is null if the processor does not664// define a model.665void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R,666StringRef Name, char Separator) {667OS << " ";668int V = R ? R->getValueAsInt(Name) : -1;669if (V >= 0)670OS << V << Separator << " // " << Name;671else672OS << "MCSchedModel::Default" << Name << Separator;673OS << '\n';674}675676void SubtargetEmitter::EmitProcessorResourceSubUnits(677const CodeGenProcModel &ProcModel, raw_ostream &OS) {678OS << "\nstatic const unsigned " << ProcModel.ModelName679<< "ProcResourceSubUnits[] = {\n"680<< " 0, // Invalid\n";681682for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {683Record *PRDef = ProcModel.ProcResourceDefs[i];684if (!PRDef->isSubClassOf("ProcResGroup"))685continue;686RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");687for (Record *RUDef : ResUnits) {688Record *const RU =689SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc());690for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) {691OS << " " << ProcModel.getProcResourceIdx(RU) << ", ";692}693}694OS << " // " << PRDef->getName() << "\n";695}696OS << "};\n";697}698699static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel,700raw_ostream &OS) {701int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0;702if (Record *RCU = ProcModel.RetireControlUnit) {703ReorderBufferSize =704std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize"));705MaxRetirePerCycle =706std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle"));707}708709OS << ReorderBufferSize << ", // ReorderBufferSize\n ";710OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n ";711}712713static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel,714unsigned NumRegisterFiles,715unsigned NumCostEntries, raw_ostream &OS) {716if (NumRegisterFiles)717OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles);718else719OS << "nullptr,\n 0";720721OS << ", // Number of register files.\n ";722if (NumCostEntries)723OS << ProcModel.ModelName << "RegisterCosts,\n ";724else725OS << "nullptr,\n ";726OS << NumCostEntries << ", // Number of register cost entries.\n";727}728729unsigned730SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel,731raw_ostream &OS) {732if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) {733return RF.hasDefaultCosts();734}))735return 0;736737// Print the RegisterCost table first.738OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n";739OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName740<< "RegisterCosts"741<< "[] = {\n";742743for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) {744// Skip register files with a default cost table.745if (RF.hasDefaultCosts())746continue;747// Add entries to the cost table.748for (const CodeGenRegisterCost &RC : RF.Costs) {749OS << " { ";750Record *Rec = RC.RCDef;751if (Rec->getValue("Namespace"))752OS << Rec->getValueAsString("Namespace") << "::";753OS << Rec->getName() << "RegClassID, " << RC.Cost << ", "754<< RC.AllowMoveElimination << "},\n";755}756}757OS << "};\n";758759// Now generate a table with register file info.760OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, "761<< "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n";762OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName763<< "RegisterFiles"764<< "[] = {\n"765<< " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n";766unsigned CostTblIndex = 0;767768for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) {769OS << " { ";770OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", ";771unsigned NumCostEntries = RD.Costs.size();772OS << NumCostEntries << ", " << CostTblIndex << ", "773<< RD.MaxMovesEliminatedPerCycle << ", "774<< RD.AllowZeroMoveEliminationOnly << "},\n";775CostTblIndex += NumCostEntries;776}777OS << "};\n";778779return CostTblIndex;780}781782void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,783raw_ostream &OS) {784unsigned QueueID = 0;785if (ProcModel.LoadQueue) {786const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor");787QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),788find(ProcModel.ProcResourceDefs, Queue));789}790OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n";791792QueueID = 0;793if (ProcModel.StoreQueue) {794const Record *Queue =795ProcModel.StoreQueue->getValueAsDef("QueueDescriptor");796QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),797find(ProcModel.ProcResourceDefs, Queue));798}799OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n";800}801802void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,803raw_ostream &OS) {804// Generate a table of register file descriptors (one entry per each user805// defined register file), and a table of register costs.806unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS);807808// Now generate a table for the extra processor info.809OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName810<< "ExtraInfo = {\n ";811812// Add information related to the retire control unit.813EmitRetireControlUnitInfo(ProcModel, OS);814815// Add information related to the register files (i.e. where to find register816// file descriptors and register costs).817EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(),818NumCostEntries, OS);819820// Add information about load/store queues.821EmitLoadStoreQueueInfo(ProcModel, OS);822823OS << "};\n";824}825826void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,827raw_ostream &OS) {828EmitProcessorResourceSubUnits(ProcModel, OS);829830OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n";831OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName832<< "ProcResources"833<< "[] = {\n"834<< " {\"InvalidUnit\", 0, 0, 0, 0},\n";835836unsigned SubUnitsOffset = 1;837for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {838Record *PRDef = ProcModel.ProcResourceDefs[i];839840Record *SuperDef = nullptr;841unsigned SuperIdx = 0;842unsigned NumUnits = 0;843const unsigned SubUnitsBeginOffset = SubUnitsOffset;844int BufferSize = PRDef->getValueAsInt("BufferSize");845if (PRDef->isSubClassOf("ProcResGroup")) {846RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");847for (Record *RU : ResUnits) {848NumUnits += RU->getValueAsInt("NumUnits");849SubUnitsOffset += RU->getValueAsInt("NumUnits");850}851} else {852// Find the SuperIdx853if (PRDef->getValueInit("Super")->isComplete()) {854SuperDef = SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"),855ProcModel, PRDef->getLoc());856SuperIdx = ProcModel.getProcResourceIdx(SuperDef);857}858NumUnits = PRDef->getValueAsInt("NumUnits");859}860// Emit the ProcResourceDesc861OS << " {\"" << PRDef->getName() << "\", ";862if (PRDef->getName().size() < 15)863OS.indent(15 - PRDef->getName().size());864OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", ";865if (SubUnitsBeginOffset != SubUnitsOffset) {866OS << ProcModel.ModelName << "ProcResourceSubUnits + "867<< SubUnitsBeginOffset;868} else {869OS << "nullptr";870}871OS << "}, // #" << i + 1;872if (SuperDef)873OS << ", Super=" << SuperDef->getName();874OS << "\n";875}876OS << "};\n";877}878879// Find the WriteRes Record that defines processor resources for this880// SchedWrite.881Record *882SubtargetEmitter::FindWriteResources(const CodeGenSchedRW &SchedWrite,883const CodeGenProcModel &ProcModel) {884885// Check if the SchedWrite is already subtarget-specific and directly886// specifies a set of processor resources.887if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))888return SchedWrite.TheDef;889890Record *AliasDef = nullptr;891for (Record *A : SchedWrite.Aliases) {892const CodeGenSchedRW &AliasRW =893SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));894if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {895Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");896if (&SchedModels.getProcModel(ModelDef) != &ProcModel)897continue;898}899if (AliasDef)900PrintFatalError(AliasRW.TheDef->getLoc(),901"Multiple aliases "902"defined for processor " +903ProcModel.ModelName +904" Ensure only one SchedAlias exists per RW.");905AliasDef = AliasRW.TheDef;906}907if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))908return AliasDef;909910// Check this processor's list of write resources.911Record *ResDef = nullptr;912for (Record *WR : ProcModel.WriteResDefs) {913if (!WR->isSubClassOf("WriteRes"))914continue;915Record *WRDef = WR->getValueAsDef("WriteType");916if (AliasDef == WRDef || SchedWrite.TheDef == WRDef) {917if (ResDef) {918PrintFatalError(WR->getLoc(), "Resources are defined for both "919"SchedWrite and its alias on processor " +920ProcModel.ModelName);921}922ResDef = WR;923// If there is no AliasDef and we find a match, we can early exit since924// there is no need to verify whether there are resources defined for both925// SchedWrite and its alias.926if (!AliasDef)927break;928}929}930// TODO: If ProcModel has a base model (previous generation processor),931// then call FindWriteResources recursively with that model here.932if (!ResDef) {933PrintFatalError(ProcModel.ModelDef->getLoc(),934Twine("Processor does not define resources for ") +935SchedWrite.TheDef->getName());936}937return ResDef;938}939940/// Find the ReadAdvance record for the given SchedRead on this processor or941/// return NULL.942Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,943const CodeGenProcModel &ProcModel) {944// Check for SchedReads that directly specify a ReadAdvance.945if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))946return SchedRead.TheDef;947948// Check this processor's list of aliases for SchedRead.949Record *AliasDef = nullptr;950for (Record *A : SchedRead.Aliases) {951const CodeGenSchedRW &AliasRW =952SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));953if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {954Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");955if (&SchedModels.getProcModel(ModelDef) != &ProcModel)956continue;957}958if (AliasDef)959PrintFatalError(AliasRW.TheDef->getLoc(),960"Multiple aliases "961"defined for processor " +962ProcModel.ModelName +963" Ensure only one SchedAlias exists per RW.");964AliasDef = AliasRW.TheDef;965}966if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))967return AliasDef;968969// Check this processor's ReadAdvanceList.970Record *ResDef = nullptr;971for (Record *RA : ProcModel.ReadAdvanceDefs) {972if (!RA->isSubClassOf("ReadAdvance"))973continue;974Record *RADef = RA->getValueAsDef("ReadType");975if (AliasDef == RADef || SchedRead.TheDef == RADef) {976if (ResDef) {977PrintFatalError(RA->getLoc(), "Resources are defined for both "978"SchedRead and its alias on processor " +979ProcModel.ModelName);980}981ResDef = RA;982// If there is no AliasDef and we find a match, we can early exit since983// there is no need to verify whether there are resources defined for both984// SchedRead and its alias.985if (!AliasDef)986break;987}988}989// TODO: If ProcModel has a base model (previous generation processor),990// then call FindReadAdvance recursively with that model here.991if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {992PrintFatalError(ProcModel.ModelDef->getLoc(),993Twine("Processor does not define resources for ") +994SchedRead.TheDef->getName());995}996return ResDef;997}998999// Expand an explicit list of processor resources into a full list of implied1000// resource groups and super resources that cover them.1001void SubtargetEmitter::ExpandProcResources(1002RecVec &PRVec, std::vector<int64_t> &ReleaseAtCycles,1003std::vector<int64_t> &AcquireAtCycles, const CodeGenProcModel &PM) {1004assert(PRVec.size() == ReleaseAtCycles.size() && "failed precondition");1005for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {1006Record *PRDef = PRVec[i];1007RecVec SubResources;1008if (PRDef->isSubClassOf("ProcResGroup"))1009SubResources = PRDef->getValueAsListOfDefs("Resources");1010else {1011SubResources.push_back(PRDef);1012PRDef = SchedModels.findProcResUnits(PRDef, PM, PRDef->getLoc());1013for (Record *SubDef = PRDef;1014SubDef->getValueInit("Super")->isComplete();) {1015if (SubDef->isSubClassOf("ProcResGroup")) {1016// Disallow this for simplicitly.1017PrintFatalError(SubDef->getLoc(), "Processor resource group "1018" cannot be a super resources.");1019}1020Record *SuperDef = SchedModels.findProcResUnits(1021SubDef->getValueAsDef("Super"), PM, SubDef->getLoc());1022PRVec.push_back(SuperDef);1023ReleaseAtCycles.push_back(ReleaseAtCycles[i]);1024AcquireAtCycles.push_back(AcquireAtCycles[i]);1025SubDef = SuperDef;1026}1027}1028for (Record *PR : PM.ProcResourceDefs) {1029if (PR == PRDef || !PR->isSubClassOf("ProcResGroup"))1030continue;1031RecVec SuperResources = PR->getValueAsListOfDefs("Resources");1032RecIter SubI = SubResources.begin(), SubE = SubResources.end();1033for (; SubI != SubE; ++SubI) {1034if (!is_contained(SuperResources, *SubI)) {1035break;1036}1037}1038if (SubI == SubE) {1039PRVec.push_back(PR);1040ReleaseAtCycles.push_back(ReleaseAtCycles[i]);1041AcquireAtCycles.push_back(AcquireAtCycles[i]);1042}1043}1044}1045}10461047// Generate the SchedClass table for this processor and update global1048// tables. Must be called for each processor in order.1049void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,1050SchedClassTables &SchedTables) {1051std::vector<MCSchedClassDesc> &SCTab =1052SchedTables.ProcSchedClasses.emplace_back();1053if (!ProcModel.hasInstrSchedModel())1054return;10551056LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n");1057for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {1058LLVM_DEBUG(SC.dump(&SchedModels));10591060MCSchedClassDesc &SCDesc = SCTab.emplace_back();1061// SCDesc.Name is guarded by NDEBUG1062SCDesc.NumMicroOps = 0;1063SCDesc.BeginGroup = false;1064SCDesc.EndGroup = false;1065SCDesc.RetireOOO = false;1066SCDesc.WriteProcResIdx = 0;1067SCDesc.WriteLatencyIdx = 0;1068SCDesc.ReadAdvanceIdx = 0;10691070// A Variant SchedClass has no resources of its own.1071bool HasVariants = false;1072for (const CodeGenSchedTransition &CGT :1073make_range(SC.Transitions.begin(), SC.Transitions.end())) {1074if (CGT.ProcIndex == ProcModel.Index) {1075HasVariants = true;1076break;1077}1078}1079if (HasVariants) {1080SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;1081continue;1082}10831084// Determine if the SchedClass is actually reachable on this processor. If1085// not don't try to locate the processor resources, it will fail.1086// If ProcIndices contains 0, this class applies to all processors.1087assert(!SC.ProcIndices.empty() && "expect at least one procidx");1088if (SC.ProcIndices[0] != 0) {1089if (!is_contained(SC.ProcIndices, ProcModel.Index))1090continue;1091}1092IdxVec Writes = SC.Writes;1093IdxVec Reads = SC.Reads;1094if (!SC.InstRWs.empty()) {1095// This class has a default ReadWrite list which can be overridden by1096// InstRW definitions.1097Record *RWDef = nullptr;1098for (Record *RW : SC.InstRWs) {1099Record *RWModelDef = RW->getValueAsDef("SchedModel");1100if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {1101RWDef = RW;1102break;1103}1104}1105if (RWDef) {1106Writes.clear();1107Reads.clear();1108SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),1109Writes, Reads);1110}1111}1112if (Writes.empty()) {1113// Check this processor's itinerary class resources.1114for (Record *I : ProcModel.ItinRWDefs) {1115RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses");1116if (is_contained(Matched, SC.ItinClassDef)) {1117SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"),1118Writes, Reads);1119break;1120}1121}1122if (Writes.empty()) {1123LLVM_DEBUG(dbgs() << ProcModel.ModelName1124<< " does not have resources for class " << SC.Name1125<< '\n');1126SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;1127}1128}1129// Sum resources across all operand writes.1130std::vector<MCWriteProcResEntry> WriteProcResources;1131std::vector<MCWriteLatencyEntry> WriteLatencies;1132std::vector<std::string> WriterNames;1133std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;1134for (unsigned W : Writes) {1135IdxVec WriteSeq;1136SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, ProcModel);11371138// For each operand, create a latency entry.1139MCWriteLatencyEntry WLEntry;1140WLEntry.Cycles = 0;1141unsigned WriteID = WriteSeq.back();1142WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);1143// If this Write is not referenced by a ReadAdvance, don't distinguish it1144// from other WriteLatency entries.1145if (!ProcModel.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef))1146WriteID = 0;1147WLEntry.WriteResourceID = WriteID;11481149for (unsigned WS : WriteSeq) {11501151Record *WriteRes =1152FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);11531154// Mark the parent class as invalid for unsupported write types.1155if (WriteRes->getValueAsBit("Unsupported")) {1156SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;1157break;1158}1159WLEntry.Cycles += WriteRes->getValueAsInt("Latency");1160SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");1161SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");1162SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");1163SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue");1164SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue");1165SCDesc.RetireOOO |= WriteRes->getValueAsBit("RetireOOO");11661167// Create an entry for each ProcResource listed in WriteRes.1168RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");1169std::vector<int64_t> ReleaseAtCycles =1170WriteRes->getValueAsListOfInts("ReleaseAtCycles");11711172std::vector<int64_t> AcquireAtCycles =1173WriteRes->getValueAsListOfInts("AcquireAtCycles");11741175// Check consistency of the two vectors carrying the start and1176// stop cycles of the resources.1177if (!ReleaseAtCycles.empty() &&1178ReleaseAtCycles.size() != PRVec.size()) {1179// If ReleaseAtCycles is provided, check consistency.1180PrintFatalError(1181WriteRes->getLoc(),1182Twine("Inconsistent release at cycles: size(ReleaseAtCycles) != "1183"size(ProcResources): ")1184.concat(Twine(PRVec.size()))1185.concat(" vs ")1186.concat(Twine(ReleaseAtCycles.size())));1187}11881189if (!AcquireAtCycles.empty() &&1190AcquireAtCycles.size() != PRVec.size()) {1191PrintFatalError(1192WriteRes->getLoc(),1193Twine("Inconsistent resource cycles: size(AcquireAtCycles) != "1194"size(ProcResources): ")1195.concat(Twine(AcquireAtCycles.size()))1196.concat(" vs ")1197.concat(Twine(PRVec.size())));1198}11991200if (ReleaseAtCycles.empty()) {1201// If ReleaseAtCycles is not provided, default to one cycle1202// per resource.1203ReleaseAtCycles.resize(PRVec.size(), 1);1204}12051206if (AcquireAtCycles.empty()) {1207// If AcquireAtCycles is not provided, reserve the resource1208// starting from cycle 0.1209AcquireAtCycles.resize(PRVec.size(), 0);1210}12111212assert(AcquireAtCycles.size() == ReleaseAtCycles.size());12131214ExpandProcResources(PRVec, ReleaseAtCycles, AcquireAtCycles, ProcModel);1215assert(AcquireAtCycles.size() == ReleaseAtCycles.size());12161217for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd;1218++PRIdx) {1219MCWriteProcResEntry WPREntry;1220WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);1221assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");1222WPREntry.ReleaseAtCycle = ReleaseAtCycles[PRIdx];1223WPREntry.AcquireAtCycle = AcquireAtCycles[PRIdx];1224if (AcquireAtCycles[PRIdx] > ReleaseAtCycles[PRIdx]) {1225PrintFatalError(1226WriteRes->getLoc(),1227Twine("Inconsistent resource cycles: AcquireAtCycles "1228"< ReleaseAtCycles must hold."));1229}1230if (AcquireAtCycles[PRIdx] < 0) {1231PrintFatalError(WriteRes->getLoc(),1232Twine("Invalid value: AcquireAtCycle "1233"must be a non-negative value."));1234}1235// If this resource is already used in this sequence, add the current1236// entry's cycles so that the same resource appears to be used1237// serially, rather than multiple parallel uses. This is important for1238// in-order machine where the resource consumption is a hazard.1239unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();1240for (; WPRIdx != WPREnd; ++WPRIdx) {1241if (WriteProcResources[WPRIdx].ProcResourceIdx ==1242WPREntry.ProcResourceIdx) {1243// TODO: multiple use of the same resources would1244// require either 1. thinking of how to handle multiple1245// intervals for the same resource in1246// `<Target>WriteProcResTable` (see1247// `SubtargetEmitter::EmitSchedClassTables`), or1248// 2. thinking how to merge multiple intervals into a1249// single interval.1250assert(WPREntry.AcquireAtCycle == 0 &&1251"multiple use ofthe same resource is not yet handled");1252WriteProcResources[WPRIdx].ReleaseAtCycle +=1253WPREntry.ReleaseAtCycle;1254break;1255}1256}1257if (WPRIdx == WPREnd)1258WriteProcResources.push_back(WPREntry);1259}1260}1261WriteLatencies.push_back(WLEntry);1262}1263// Create an entry for each operand Read in this SchedClass.1264// Entries must be sorted first by UseIdx then by WriteResourceID.1265for (unsigned UseIdx = 0, EndIdx = Reads.size(); UseIdx != EndIdx;1266++UseIdx) {1267Record *ReadAdvance =1268FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);1269if (!ReadAdvance)1270continue;12711272// Mark the parent class as invalid for unsupported write types.1273if (ReadAdvance->getValueAsBit("Unsupported")) {1274SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;1275break;1276}1277RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");1278IdxVec WriteIDs;1279if (ValidWrites.empty())1280WriteIDs.push_back(0);1281else {1282for (Record *VW : ValidWrites) {1283unsigned WriteID = SchedModels.getSchedRWIdx(VW, /*IsRead=*/false);1284assert(WriteID != 0 &&1285"Expected a valid SchedRW in the list of ValidWrites");1286WriteIDs.push_back(WriteID);1287}1288}1289llvm::sort(WriteIDs);1290for (unsigned W : WriteIDs) {1291MCReadAdvanceEntry RAEntry;1292RAEntry.UseIdx = UseIdx;1293RAEntry.WriteResourceID = W;1294RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");1295ReadAdvanceEntries.push_back(RAEntry);1296}1297}1298if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {1299WriteProcResources.clear();1300WriteLatencies.clear();1301ReadAdvanceEntries.clear();1302}1303// Add the information for this SchedClass to the global tables using basic1304// compression.1305//1306// WritePrecRes entries are sorted by ProcResIdx.1307llvm::sort(WriteProcResources, LessWriteProcResources());13081309SCDesc.NumWriteProcResEntries = WriteProcResources.size();1310std::vector<MCWriteProcResEntry>::iterator WPRPos =1311std::search(SchedTables.WriteProcResources.begin(),1312SchedTables.WriteProcResources.end(),1313WriteProcResources.begin(), WriteProcResources.end());1314if (WPRPos != SchedTables.WriteProcResources.end())1315SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();1316else {1317SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();1318SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),1319WriteProcResources.end());1320}1321// Latency entries must remain in operand order.1322SCDesc.NumWriteLatencyEntries = WriteLatencies.size();1323std::vector<MCWriteLatencyEntry>::iterator WLPos = std::search(1324SchedTables.WriteLatencies.begin(), SchedTables.WriteLatencies.end(),1325WriteLatencies.begin(), WriteLatencies.end());1326if (WLPos != SchedTables.WriteLatencies.end()) {1327unsigned idx = WLPos - SchedTables.WriteLatencies.begin();1328SCDesc.WriteLatencyIdx = idx;1329for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)1330if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==1331std::string::npos) {1332SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];1333}1334} else {1335SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();1336llvm::append_range(SchedTables.WriteLatencies, WriteLatencies);1337llvm::append_range(SchedTables.WriterNames, WriterNames);1338}1339// ReadAdvanceEntries must remain in operand order.1340SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();1341std::vector<MCReadAdvanceEntry>::iterator RAPos =1342std::search(SchedTables.ReadAdvanceEntries.begin(),1343SchedTables.ReadAdvanceEntries.end(),1344ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());1345if (RAPos != SchedTables.ReadAdvanceEntries.end())1346SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();1347else {1348SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();1349llvm::append_range(SchedTables.ReadAdvanceEntries, ReadAdvanceEntries);1350}1351}1352}13531354// Emit SchedClass tables for all processors and associated global tables.1355void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,1356raw_ostream &OS) {1357// Emit global WriteProcResTable.1358OS << "\n// {ProcResourceIdx, ReleaseAtCycle, AcquireAtCycle}\n"1359<< "extern const llvm::MCWriteProcResEntry " << Target1360<< "WriteProcResTable[] = {\n"1361<< " { 0, 0, 0 }, // Invalid\n";1362for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();1363WPRIdx != WPREnd; ++WPRIdx) {1364MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];1365OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "1366<< format("%2d", WPREntry.ReleaseAtCycle) << ", "1367<< format("%2d", WPREntry.AcquireAtCycle) << "}";1368if (WPRIdx + 1 < WPREnd)1369OS << ',';1370OS << " // #" << WPRIdx << '\n';1371}1372OS << "}; // " << Target << "WriteProcResTable\n";13731374// Emit global WriteLatencyTable.1375OS << "\n// {Cycles, WriteResourceID}\n"1376<< "extern const llvm::MCWriteLatencyEntry " << Target1377<< "WriteLatencyTable[] = {\n"1378<< " { 0, 0}, // Invalid\n";1379for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();1380WLIdx != WLEnd; ++WLIdx) {1381MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];1382OS << " {" << format("%2d", WLEntry.Cycles) << ", "1383<< format("%2d", WLEntry.WriteResourceID) << "}";1384if (WLIdx + 1 < WLEnd)1385OS << ',';1386OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';1387}1388OS << "}; // " << Target << "WriteLatencyTable\n";13891390// Emit global ReadAdvanceTable.1391OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"1392<< "extern const llvm::MCReadAdvanceEntry " << Target1393<< "ReadAdvanceTable[] = {\n"1394<< " {0, 0, 0}, // Invalid\n";1395for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();1396RAIdx != RAEnd; ++RAIdx) {1397MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];1398OS << " {" << RAEntry.UseIdx << ", "1399<< format("%2d", RAEntry.WriteResourceID) << ", "1400<< format("%2d", RAEntry.Cycles) << "}";1401if (RAIdx + 1 < RAEnd)1402OS << ',';1403OS << " // #" << RAIdx << '\n';1404}1405OS << "}; // " << Target << "ReadAdvanceTable\n";14061407// Emit a SchedClass table for each processor.1408for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),1409PE = SchedModels.procModelEnd();1410PI != PE; ++PI) {1411if (!PI->hasInstrSchedModel())1412continue;14131414std::vector<MCSchedClassDesc> &SCTab =1415SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];14161417OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"1418<< " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";1419OS << "static const llvm::MCSchedClassDesc " << PI->ModelName1420<< "SchedClasses[] = {\n";14211422// The first class is always invalid. We no way to distinguish it except by1423// name and position.1424assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" &&1425"invalid class not first");1426OS << " {DBGFIELD(\"InvalidSchedClass\") "1427<< MCSchedClassDesc::InvalidNumMicroOps1428<< ", false, false, false, 0, 0, 0, 0, 0, 0},\n";14291430for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {1431MCSchedClassDesc &MCDesc = SCTab[SCIdx];1432const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);1433OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";1434if (SchedClass.Name.size() < 18)1435OS.indent(18 - SchedClass.Name.size());1436OS << MCDesc.NumMicroOps << ", " << (MCDesc.BeginGroup ? "true" : "false")1437<< ", " << (MCDesc.EndGroup ? "true" : "false") << ", "1438<< (MCDesc.RetireOOO ? "true" : "false") << ", "1439<< format("%2d", MCDesc.WriteProcResIdx) << ", "1440<< MCDesc.NumWriteProcResEntries << ", "1441<< format("%2d", MCDesc.WriteLatencyIdx) << ", "1442<< MCDesc.NumWriteLatencyEntries << ", "1443<< format("%2d", MCDesc.ReadAdvanceIdx) << ", "1444<< MCDesc.NumReadAdvanceEntries << "}, // #" << SCIdx << '\n';1445}1446OS << "}; // " << PI->ModelName << "SchedClasses\n";1447}1448}14491450void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {1451// For each processor model.1452for (const CodeGenProcModel &PM : SchedModels.procModels()) {1453// Emit extra processor info if available.1454if (PM.hasExtraProcessorInfo())1455EmitExtraProcessorInfo(PM, OS);1456// Emit processor resource table.1457if (PM.hasInstrSchedModel())1458EmitProcessorResources(PM, OS);1459else if (!PM.ProcResourceDefs.empty())1460PrintFatalError(PM.ModelDef->getLoc(),1461"SchedMachineModel defines "1462"ProcResources without defining WriteRes SchedWriteRes");14631464// Begin processor itinerary properties1465OS << "\n";1466OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n";1467EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ',');1468EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ',');1469EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ',');1470EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ',');1471EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ',');1472EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');14731474bool PostRAScheduler =1475(PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);14761477OS << " " << (PostRAScheduler ? "true" : "false") << ", // "1478<< "PostRAScheduler\n";14791480bool CompleteModel =1481(PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);14821483OS << " " << (CompleteModel ? "true" : "false") << ", // "1484<< "CompleteModel\n";14851486bool EnableIntervals =1487(PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false);14881489OS << " " << (EnableIntervals ? "true" : "false") << ", // "1490<< "EnableIntervals\n";14911492OS << " " << PM.Index << ", // Processor ID\n";1493if (PM.hasInstrSchedModel())1494OS << " " << PM.ModelName << "ProcResources"1495<< ",\n"1496<< " " << PM.ModelName << "SchedClasses"1497<< ",\n"1498<< " " << PM.ProcResourceDefs.size() + 1 << ",\n"1499<< " "1500<< (SchedModels.schedClassEnd() - SchedModels.schedClassBegin())1501<< ",\n";1502else1503OS << " nullptr, nullptr, 0, 0,"1504<< " // No instruction-level machine model.\n";1505if (PM.hasItineraries())1506OS << " " << PM.ItinsDef->getName() << ",\n";1507else1508OS << " nullptr, // No Itinerary\n";1509if (PM.hasExtraProcessorInfo())1510OS << " &" << PM.ModelName << "ExtraInfo,\n";1511else1512OS << " nullptr // No extra processor descriptor\n";1513OS << "};\n";1514}1515}15161517//1518// EmitSchedModel - Emits all scheduling model tables, folding common patterns.1519//1520void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {1521OS << "#ifdef DBGFIELD\n"1522<< "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n"1523<< "#endif\n"1524<< "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n"1525<< "#define DBGFIELD(x) x,\n"1526<< "#else\n"1527<< "#define DBGFIELD(x)\n"1528<< "#endif\n";15291530if (SchedModels.hasItineraries()) {1531std::vector<std::vector<InstrItinerary>> ProcItinLists;1532// Emit the stage data1533EmitStageAndOperandCycleData(OS, ProcItinLists);1534EmitItineraries(OS, ProcItinLists);1535}1536OS << "\n// ===============================================================\n"1537<< "// Data tables for the new per-operand machine model.\n";15381539SchedClassTables SchedTables;1540for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {1541GenSchedClassTables(ProcModel, SchedTables);1542}1543EmitSchedClassTables(SchedTables, OS);15441545OS << "\n#undef DBGFIELD\n";15461547// Emit the processor machine model1548EmitProcessorModels(OS);1549}15501551static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {1552std::string Buffer;1553raw_string_ostream Stream(Buffer);15541555// Collect all the PredicateProlog records and print them to the output1556// stream.1557std::vector<Record *> Prologs =1558Records.getAllDerivedDefinitions("PredicateProlog");1559llvm::sort(Prologs, LessRecord());1560for (Record *P : Prologs)1561Stream << P->getValueAsString("Code") << '\n';15621563OS << Buffer;1564}15651566static bool isTruePredicate(const Record *Rec) {1567return Rec->isSubClassOf("MCSchedPredicate") &&1568Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");1569}15701571static void emitPredicates(const CodeGenSchedTransition &T,1572const CodeGenSchedClass &SC, PredicateExpander &PE,1573raw_ostream &OS) {1574std::string Buffer;1575raw_string_ostream SS(Buffer);15761577// If not all predicates are MCTrue, then we need an if-stmt.1578unsigned NumNonTruePreds =1579T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate);15801581SS.indent(PE.getIndentLevel() * 2);15821583if (NumNonTruePreds) {1584bool FirstNonTruePredicate = true;1585SS << "if (";15861587PE.setIndentLevel(PE.getIndentLevel() + 2);15881589for (const Record *Rec : T.PredTerm) {1590// Skip predicates that evaluate to "true".1591if (isTruePredicate(Rec))1592continue;15931594if (FirstNonTruePredicate) {1595FirstNonTruePredicate = false;1596} else {1597SS << "\n";1598SS.indent(PE.getIndentLevel() * 2);1599SS << "&& ";1600}16011602if (Rec->isSubClassOf("MCSchedPredicate")) {1603PE.expandPredicate(SS, Rec->getValueAsDef("Pred"));1604continue;1605}16061607// Expand this legacy predicate and wrap it around braces if there is more1608// than one predicate to expand.1609SS << ((NumNonTruePreds > 1) ? "(" : "")1610<< Rec->getValueAsString("Predicate")1611<< ((NumNonTruePreds > 1) ? ")" : "");1612}16131614SS << ")\n"; // end of if-stmt1615PE.decreaseIndentLevel();1616SS.indent(PE.getIndentLevel() * 2);1617PE.decreaseIndentLevel();1618}16191620SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n';1621OS << Buffer;1622}16231624// Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate1625// epilogue code for the auto-generated helper.1626static void emitSchedModelHelperEpilogue(raw_ostream &OS,1627bool ShouldReturnZero) {1628if (ShouldReturnZero) {1629OS << " // Don't know how to resolve this scheduling class.\n"1630<< " return 0;\n";1631return;1632}16331634OS << " report_fatal_error(\"Expected a variant SchedClass\");\n";1635}16361637static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {1638return all_of(T.PredTerm, [](const Record *Rec) {1639return Rec->isSubClassOf("MCSchedPredicate");1640});1641}16421643static void collectVariantClasses(const CodeGenSchedModels &SchedModels,1644IdxVec &VariantClasses,1645bool OnlyExpandMCInstPredicates) {1646for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {1647// Ignore non-variant scheduling classes.1648if (SC.Transitions.empty())1649continue;16501651if (OnlyExpandMCInstPredicates) {1652// Ignore this variant scheduling class no transitions use any meaningful1653// MCSchedPredicate definitions.1654if (llvm::none_of(SC.Transitions, hasMCSchedPredicates))1655continue;1656}16571658VariantClasses.push_back(SC.Index);1659}1660}16611662static void collectProcessorIndices(const CodeGenSchedClass &SC,1663IdxVec &ProcIndices) {1664// A variant scheduling class may define transitions for multiple1665// processors. This function identifies wich processors are associated with1666// transition rules specified by variant class `SC`.1667for (const CodeGenSchedTransition &T : SC.Transitions) {1668IdxVec PI;1669std::set_union(&T.ProcIndex, &T.ProcIndex + 1, ProcIndices.begin(),1670ProcIndices.end(), std::back_inserter(PI));1671ProcIndices = std::move(PI);1672}1673}16741675static bool isAlwaysTrue(const CodeGenSchedTransition &T) {1676return llvm::all_of(T.PredTerm, isTruePredicate);1677}16781679void SubtargetEmitter::emitSchedModelHelpersImpl(1680raw_ostream &OS, bool OnlyExpandMCInstPredicates) {1681IdxVec VariantClasses;1682collectVariantClasses(SchedModels, VariantClasses,1683OnlyExpandMCInstPredicates);16841685if (VariantClasses.empty()) {1686emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);1687return;1688}16891690// Construct a switch statement where the condition is a check on the1691// scheduling class identifier. There is a `case` for every variant class1692// defined by the processor models of this target.1693// Each `case` implements a number of rules to resolve (i.e. to transition1694// from) a variant scheduling class to another scheduling class. Rules are1695// described by instances of CodeGenSchedTransition. Note that transitions may1696// not be valid for all processors.1697OS << " switch (SchedClass) {\n";1698for (unsigned VC : VariantClasses) {1699IdxVec ProcIndices;1700const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC);1701collectProcessorIndices(SC, ProcIndices);17021703OS << " case " << VC << ": // " << SC.Name << '\n';17041705PredicateExpander PE(Target);1706PE.setByRef(false);1707PE.setExpandForMC(OnlyExpandMCInstPredicates);1708for (unsigned PI : ProcIndices) {1709OS << " ";17101711// Emit a guard on the processor ID.1712if (PI != 0) {1713OS << (OnlyExpandMCInstPredicates1714? "if (CPUID == "1715: "if (SchedModel->getProcessorID() == ");1716OS << PI << ") ";1717OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n';1718}17191720// Now emit transitions associated with processor PI.1721const CodeGenSchedTransition *FinalT = nullptr;1722for (const CodeGenSchedTransition &T : SC.Transitions) {1723if (PI != 0 && T.ProcIndex != PI)1724continue;17251726// Emit only transitions based on MCSchedPredicate, if it's the case.1727// At least the transition specified by NoSchedPred is emitted,1728// which becomes the default transition for those variants otherwise1729// not based on MCSchedPredicate.1730// FIXME: preferably, llvm-mca should instead assume a reasonable1731// default when a variant transition is not based on MCSchedPredicate1732// for a given processor.1733if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))1734continue;17351736// If transition is folded to 'return X' it should be the last one.1737if (isAlwaysTrue(T)) {1738FinalT = &T;1739continue;1740}1741PE.setIndentLevel(3);1742emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);1743}1744if (FinalT)1745emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx),1746PE, OS);17471748OS << " }\n";17491750if (PI == 0)1751break;1752}17531754if (SC.isInferred())1755OS << " return " << SC.Index << ";\n";1756OS << " break;\n";1757}17581759OS << " };\n";17601761emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);1762}17631764void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,1765raw_ostream &OS) {1766OS << "unsigned " << ClassName1767<< "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"1768<< " const TargetSchedModel *SchedModel) const {\n";17691770// Emit the predicate prolog code.1771emitPredicateProlog(Records, OS);17721773// Emit target predicates.1774emitSchedModelHelpersImpl(OS);17751776OS << "} // " << ClassName << "::resolveSchedClass\n\n";17771778OS << "unsigned " << ClassName1779<< "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"1780<< " const MCInstrInfo *MCII, unsigned CPUID) const {\n"1781<< " return " << Target << "_MC"1782<< "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"1783<< "} // " << ClassName << "::resolveVariantSchedClass\n\n";17841785STIPredicateExpander PE(Target);1786PE.setClassPrefix(ClassName);1787PE.setExpandDefinition(true);1788PE.setByRef(false);1789PE.setIndentLevel(0);17901791for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())1792PE.expandSTIPredicate(OS, Fn);1793}17941795void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,1796raw_ostream &OS) {1797const CodeGenHwModes &CGH = TGT.getHwModes();1798assert(CGH.getNumModeIds() > 0);1799if (CGH.getNumModeIds() == 1)1800return;18011802// Collect all HwModes and related features defined in the TD files,1803// and store them as a bit set.1804unsigned ValueTypeModes = 0;1805unsigned RegInfoModes = 0;1806unsigned EncodingInfoModes = 0;1807for (const auto &MS : CGH.getHwModeSelects()) {1808for (const HwModeSelect::PairType &P : MS.second.Items) {1809if (P.first == DefaultMode)1810continue;1811if (P.second->isSubClassOf("ValueType")) {1812ValueTypeModes |= (1 << (P.first - 1));1813} else if (P.second->isSubClassOf("RegInfo") ||1814P.second->isSubClassOf("SubRegRange")) {1815RegInfoModes |= (1 << (P.first - 1));1816} else if (P.second->isSubClassOf("InstructionEncoding")) {1817EncodingInfoModes |= (1 << (P.first - 1));1818}1819}1820}18211822// Start emitting for getHwModeSet().1823OS << "unsigned " << ClassName << "::getHwModeSet() const {\n";1824OS << " // Collect HwModes and store them as a bit set.\n";1825OS << " unsigned Modes = 0;\n";1826for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {1827const HwMode &HM = CGH.getMode(M);1828OS << " if (checkFeatures(\"" << HM.Features << "\")) Modes |= (1 << "1829<< (M - 1) << ");\n";1830}1831OS << " return Modes;\n}\n";1832// End emitting for getHwModeSet().18331834auto handlePerMode = [&](std::string ModeType, unsigned ModeInBitSet) {1835OS << " case HwMode_" << ModeType << ":\n"1836<< " Modes &= " << ModeInBitSet << ";\n"1837<< " if (!Modes)\n return Modes;\n"1838<< " if (!llvm::has_single_bit<unsigned>(Modes))\n"1839<< " llvm_unreachable(\"Two or more HwModes for " << ModeType1840<< " were found!\");\n"1841<< " return llvm::countr_zero(Modes) + 1;\n";1842};18431844// Start emitting for getHwMode().1845OS << "unsigned " << ClassName1846<< "::getHwMode(enum HwModeType type) const {\n";1847OS << " unsigned Modes = getHwModeSet();\n\n";1848OS << " if (!Modes)\n return Modes;\n\n";1849OS << " switch (type) {\n";1850OS << " case HwMode_Default:\n return llvm::countr_zero(Modes) + 1;\n";1851handlePerMode("ValueType", ValueTypeModes);1852handlePerMode("RegInfo", RegInfoModes);1853handlePerMode("EncodingInfo", EncodingInfoModes);1854OS << " }\n";1855OS << " llvm_unreachable(\"unexpected HwModeType\");\n"1856<< " return 0; // should not get here\n}\n";1857// End emitting for getHwMode().1858}18591860void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName,1861raw_ostream &OS) {1862if (!TGT.hasMacroFusion())1863return;18641865OS << "std::vector<MacroFusionPredTy> " << ClassName1866<< "::getMacroFusions() const {\n";1867OS.indent(2) << "std::vector<MacroFusionPredTy> Fusions;\n";1868for (auto *Fusion : TGT.getMacroFusions()) {1869std::string Name = Fusion->getNameInitAsString();1870OS.indent(2) << "if (hasFeature(" << Target << "::" << Name1871<< ")) Fusions.push_back(llvm::is" << Name << ");\n";1872}18731874OS.indent(2) << "return Fusions;\n";1875OS << "}\n";1876}18771878// Produces a subtarget specific function for parsing1879// the subtarget features string.1880void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {1881std::vector<Record *> Features =1882Records.getAllDerivedDefinitions("SubtargetFeature");1883llvm::sort(Features, LessRecord());18841885OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"1886<< "// subtarget options.\n"1887<< "void llvm::";1888OS << Target;1889OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, "1890<< "StringRef FS) {\n"1891<< " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"1892<< " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n"1893<< " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n";18941895if (Features.empty()) {1896OS << "}\n";1897return;1898}18991900if (Target == "AArch64")1901OS << " CPU = AArch64::resolveCPUAlias(CPU);\n"1902<< " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";19031904OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n"1905<< " const FeatureBitset &Bits = getFeatureBits();\n";19061907for (Record *R : Features) {1908// Next record1909StringRef Instance = R->getName();1910StringRef Value = R->getValueAsString("Value");1911StringRef FieldName = R->getValueAsString("FieldName");19121913if (Value == "true" || Value == "false")1914OS << " if (Bits[" << Target << "::" << Instance << "]) " << FieldName1915<< " = " << Value << ";\n";1916else1917OS << " if (Bits[" << Target << "::" << Instance << "] && " << FieldName1918<< " < " << Value << ") " << FieldName << " = " << Value << ";\n";1919}19201921OS << "}\n";1922}19231924void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {1925OS << "namespace " << Target << "_MC {\n"1926<< "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"1927<< " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n";1928emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);1929OS << "}\n";1930OS << "} // end namespace " << Target << "_MC\n\n";19311932OS << "struct " << Target1933<< "GenMCSubtargetInfo : public MCSubtargetInfo {\n";1934OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT,\n"1935<< " StringRef CPU, StringRef TuneCPU, StringRef FS,\n"1936<< " ArrayRef<SubtargetFeatureKV> PF,\n"1937<< " ArrayRef<SubtargetSubTypeKV> PD,\n"1938<< " const MCWriteProcResEntry *WPR,\n"1939<< " const MCWriteLatencyEntry *WL,\n"1940<< " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n"1941<< " const unsigned *OC, const unsigned *FP) :\n"1942<< " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n"1943<< " WPR, WL, RA, IS, OC, FP) { }\n\n"1944<< " unsigned resolveVariantSchedClass(unsigned SchedClass,\n"1945<< " const MCInst *MI, const MCInstrInfo *MCII,\n"1946<< " unsigned CPUID) const override {\n"1947<< " return " << Target << "_MC"1948<< "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n";1949OS << " }\n";1950if (TGT.getHwModes().getNumModeIds() > 1) {1951OS << " unsigned getHwModeSet() const override;\n";1952OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const "1953"override;\n";1954}1955if (Target == "AArch64")1956OS << " bool isCPUStringValid(StringRef CPU) const override {\n"1957<< " CPU = AArch64::resolveCPUAlias(CPU);\n"1958<< " return MCSubtargetInfo::isCPUStringValid(CPU);\n"1959<< " }\n";1960OS << "};\n";1961EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);1962}19631964void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) {1965OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n";1966OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";19671968STIPredicateExpander PE(Target);1969PE.setExpandForMC(true);1970PE.setByRef(true);1971for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())1972PE.expandSTIPredicate(OS, Fn);19731974OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";19751976OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n";1977OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";19781979std::string ClassPrefix = Target + "MCInstrAnalysis";1980PE.setExpandDefinition(true);1981PE.setClassPrefix(ClassPrefix);1982PE.setIndentLevel(0);1983for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())1984PE.expandSTIPredicate(OS, Fn);19851986OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";1987}19881989//1990// SubtargetEmitter::run - Main subtarget enumeration emitter.1991//1992void SubtargetEmitter::run(raw_ostream &OS) {1993emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);19941995OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";1996OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";19971998DenseMap<Record *, unsigned> FeatureMap;19992000OS << "namespace llvm {\n";2001Enumeration(OS, FeatureMap);2002OS << "} // end namespace llvm\n\n";2003OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";20042005EmitSubtargetInfoMacroCalls(OS);20062007OS << "namespace llvm {\n";2008#if 02009OS << "namespace {\n";2010#endif2011unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap);2012OS << "\n";2013EmitSchedModel(OS);2014OS << "\n";2015unsigned NumProcs = CPUKeyValues(OS, FeatureMap);2016OS << "\n";2017#if 02018OS << "} // end anonymous namespace\n\n";2019#endif20202021// MCInstrInfo initialization routine.2022emitGenMCSubtargetInfo(OS);20232024OS << "\nstatic inline MCSubtargetInfo *create" << Target2025<< "MCSubtargetInfoImpl("2026<< "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n";2027if (Target == "AArch64")2028OS << " CPU = AArch64::resolveCPUAlias(CPU);\n"2029<< " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";2030OS << " return new " << Target2031<< "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, ";2032if (NumFeatures)2033OS << Target << "FeatureKV, ";2034else2035OS << "std::nullopt, ";2036if (NumProcs)2037OS << Target << "SubTypeKV, ";2038else2039OS << "std::nullopt, ";2040OS << '\n';2041OS.indent(22);2042OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "2043<< Target << "ReadAdvanceTable, ";2044OS << '\n';2045OS.indent(22);2046if (SchedModels.hasItineraries()) {2047OS << Target << "Stages, " << Target << "OperandCycles, " << Target2048<< "ForwardingPaths";2049} else2050OS << "nullptr, nullptr, nullptr";2051OS << ");\n}\n\n";20522053OS << "} // end namespace llvm\n\n";20542055OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";20562057OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";2058OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";20592060OS << "#include \"llvm/Support/Debug.h\"\n";2061OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";2062if (Target == "AArch64")2063OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";2064ParseFeaturesFunction(OS);20652066OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";20672068// Create a TargetSubtargetInfo subclass to hide the MC layer initialization.2069OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";2070OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";20712072std::string ClassName = Target + "GenSubtargetInfo";2073OS << "namespace llvm {\n";2074OS << "class DFAPacketizer;\n";2075OS << "namespace " << Target << "_MC {\n"2076<< "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"2077<< " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n"2078<< "} // end namespace " << Target << "_MC\n\n";2079OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"2080<< " explicit " << ClassName << "(const Triple &TT, StringRef CPU, "2081<< "StringRef TuneCPU, StringRef FS);\n"2082<< "public:\n"2083<< " unsigned resolveSchedClass(unsigned SchedClass, "2084<< " const MachineInstr *DefMI,"2085<< " const TargetSchedModel *SchedModel) const override;\n"2086<< " unsigned resolveVariantSchedClass(unsigned SchedClass,"2087<< " const MCInst *MI, const MCInstrInfo *MCII,"2088<< " unsigned CPUID) const override;\n"2089<< " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"2090<< " const;\n";2091if (TGT.getHwModes().getNumModeIds() > 1) {2092OS << " unsigned getHwModeSet() const override;\n";2093OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const "2094"override;\n";2095}2096if (TGT.hasMacroFusion())2097OS << " std::vector<MacroFusionPredTy> getMacroFusions() const "2098"override;\n";20992100STIPredicateExpander PE(Target);2101PE.setByRef(false);2102for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())2103PE.expandSTIPredicate(OS, Fn);21042105OS << "};\n"2106<< "} // end namespace llvm\n\n";21072108OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";21092110OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";2111OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";21122113OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";2114OS << "namespace llvm {\n";2115OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";2116OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";2117OS << "extern const llvm::MCWriteProcResEntry " << Target2118<< "WriteProcResTable[];\n";2119OS << "extern const llvm::MCWriteLatencyEntry " << Target2120<< "WriteLatencyTable[];\n";2121OS << "extern const llvm::MCReadAdvanceEntry " << Target2122<< "ReadAdvanceTable[];\n";21232124if (SchedModels.hasItineraries()) {2125OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";2126OS << "extern const unsigned " << Target << "OperandCycles[];\n";2127OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";2128}21292130OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "2131<< "StringRef TuneCPU, StringRef FS)\n";21322133if (Target == "AArch64")2134OS << " : TargetSubtargetInfo(TT, AArch64::resolveCPUAlias(CPU),\n"2135<< " AArch64::resolveCPUAlias(TuneCPU), FS, ";2136else2137OS << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";2138if (NumFeatures)2139OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";2140else2141OS << "std::nullopt, ";2142if (NumProcs)2143OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";2144else2145OS << "std::nullopt, ";2146OS << '\n';2147OS.indent(24);2148OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "2149<< Target << "ReadAdvanceTable, ";2150OS << '\n';2151OS.indent(24);2152if (SchedModels.hasItineraries()) {2153OS << Target << "Stages, " << Target << "OperandCycles, " << Target2154<< "ForwardingPaths";2155} else2156OS << "nullptr, nullptr, nullptr";2157OS << ") {}\n\n";21582159EmitSchedModelHelpers(ClassName, OS);2160EmitHwModeCheck(ClassName, OS);2161emitGetMacroFusions(ClassName, OS);21622163OS << "} // end namespace llvm\n\n";21642165OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";21662167EmitMCInstrAnalysisPredicateFunctions(OS);2168}21692170static TableGen::Emitter::OptClass<SubtargetEmitter>2171X("gen-subtarget", "Generate subtarget enumerations");217221732174