Mercurial > hg > CbC > CbC_llvm
diff utils/TableGen/SubtargetEmitter.cpp @ 147:c2174574ed3a
LLVM 10
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 16:55:33 +0900 |
parents | 3a76565eade5 |
children |
line wrap: on
line diff
--- a/utils/TableGen/SubtargetEmitter.cpp Sat Feb 17 09:57:20 2018 +0900 +++ b/utils/TableGen/SubtargetEmitter.cpp Wed Aug 14 16:55:33 2019 +0900 @@ -1,9 +1,8 @@ //===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -13,6 +12,7 @@ #include "CodeGenTarget.h" #include "CodeGenSchedule.h" +#include "PredicateExpander.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -73,9 +73,11 @@ CodeGenSchedModels &SchedModels; std::string Target; - void Enumeration(raw_ostream &OS); - unsigned FeatureKeyValues(raw_ostream &OS); - unsigned CPUKeyValues(raw_ostream &OS); + void Enumeration(raw_ostream &OS, DenseMap<Record *, unsigned> &FeatureMap); + unsigned FeatureKeyValues(raw_ostream &OS, + const DenseMap<Record *, unsigned> &FeatureMap); + unsigned CPUKeyValues(raw_ostream &OS, + const DenseMap<Record *, unsigned> &FeatureMap); void FormItineraryStageString(const std::string &Names, Record *ItinData, std::string &ItinString, unsigned &NStages); @@ -90,6 +92,12 @@ void EmitItineraries(raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists); + unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel, + raw_ostream &OS); + void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS); + void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS); void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name, char Separator); void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel, @@ -108,6 +116,11 @@ void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); + void emitSchedModelHelpersImpl(raw_ostream &OS, + bool OnlyExpandMCInstPredicates = false); + void emitGenMCSubtargetInfo(raw_ostream &OS); + void EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS); + void EmitSchedModel(raw_ostream &OS); void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, @@ -126,16 +139,17 @@ // // Enumeration - Emit the specified class as an enumeration. // -void SubtargetEmitter::Enumeration(raw_ostream &OS) { +void SubtargetEmitter::Enumeration(raw_ostream &OS, + DenseMap<Record *, unsigned> &FeatureMap) { // Get all records of class and sort std::vector<Record*> DefList = Records.getAllDerivedDefinitions("SubtargetFeature"); - std::sort(DefList.begin(), DefList.end(), LessRecord()); + llvm::sort(DefList, LessRecord()); unsigned N = DefList.size(); if (N == 0) return; - if (N > MAX_SUBTARGET_FEATURES) + if (N + 1 > MAX_SUBTARGET_FEATURES) PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); OS << "namespace " << Target << " {\n"; @@ -150,18 +164,42 @@ // Get and emit name OS << " " << Def->getName() << " = " << i << ",\n"; + + // Save the index for this feature. + FeatureMap[Def] = i; } + OS << " " + << "NumSubtargetFeatures = " << N << "\n"; + // Close enumeration and namespace OS << "};\n"; OS << "} // end namespace " << Target << "\n"; } +static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList, + const DenseMap<Record *, unsigned> &FeatureMap) { + std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {}; + for (unsigned j = 0, M = FeatureList.size(); j < M; ++j) { + unsigned Bit = FeatureMap.lookup(FeatureList[j]); + Mask[Bit / 64] |= 1ULL << (Bit % 64); + } + + OS << "{ { { "; + for (unsigned i = 0; i != Mask.size(); ++i) { + OS << "0x"; + OS.write_hex(Mask[i]); + OS << "ULL, "; + } + OS << "} } }"; +} + // // FeatureKeyValues - Emit data of all the subtarget features. Used by the // command line. // -unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) { +unsigned SubtargetEmitter::FeatureKeyValues( + raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap) { // Gather and sort all the features std::vector<Record*> FeatureList = Records.getAllDerivedDefinitions("SubtargetFeature"); @@ -169,7 +207,7 @@ if (FeatureList.empty()) return 0; - std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName()); + llvm::sort(FeatureList, LessRecordFieldName()); // Begin feature table OS << "// Sorted (by key) array of values for CPU features.\n" @@ -192,17 +230,13 @@ OS << " { " << "\"" << CommandLineName << "\", " << "\"" << Desc << "\", " - << "{ " << Target << "::" << Name << " }, "; + << Target << "::" << Name << ", "; - const std::vector<Record*> &ImpliesList = - Feature->getValueAsListOfDefs("Implies"); + RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies"); - OS << "{"; - for (unsigned j = 0, M = ImpliesList.size(); j < M;) { - OS << " " << Target << "::" << ImpliesList[j]->getName(); - if (++j < M) OS << ","; - } - OS << " } },\n"; + printFeatureMask(OS, ImpliesList, FeatureMap); + + OS << " },\n"; ++NumFeatures; } @@ -216,35 +250,34 @@ // CPUKeyValues - Emit data of all the subtarget processors. Used by command // line. // -unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { +unsigned +SubtargetEmitter::CPUKeyValues(raw_ostream &OS, + const DenseMap<Record *, unsigned> &FeatureMap) { // Gather and sort processor information std::vector<Record*> ProcessorList = Records.getAllDerivedDefinitions("Processor"); - std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); + llvm::sort(ProcessorList, LessRecordFieldName()); // Begin processor table OS << "// Sorted (by key) array of values for CPU subtype.\n" - << "extern const llvm::SubtargetFeatureKV " << Target + << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[] = {\n"; // For each processor for (Record *Processor : ProcessorList) { StringRef Name = Processor->getValueAsString("Name"); - const std::vector<Record*> &FeatureList = - Processor->getValueAsListOfDefs("Features"); + RecVec FeatureList = Processor->getValueAsListOfDefs("Features"); - // Emit as { "cpu", "description", { f1 , f2 , ... fn } }, - OS << " { " - << "\"" << Name << "\", " - << "\"Select the " << Name << " processor\", "; + // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } }, + OS << " { " + << "\"" << Name << "\", "; - OS << "{"; - for (unsigned j = 0, M = FeatureList.size(); j < M;) { - OS << " " << Target << "::" << FeatureList[j]->getName(); - if (++j < M) OS << ","; - } - // The { } is for the "implies" section of this data structure. - OS << " }, { } },\n"; + printFeatureMask(OS, FeatureList, FeatureMap); + + // Emit the scheduler model pointer. + const std::string &ProcModelName = + SchedModels.getModelForProc(Processor).ModelName; + OS << ", &" << ProcModelName << " },\n"; } // End processor table @@ -263,8 +296,7 @@ std::string &ItinString, unsigned &NStages) { // Get states list - const std::vector<Record*> &StageList = - ItinData->getValueAsListOfDefs("Stages"); + RecVec StageList = ItinData->getValueAsListOfDefs("Stages"); // For each stage unsigned N = NStages = StageList.size(); @@ -277,7 +309,7 @@ ItinString += " { " + itostr(Cycles) + ", "; // Get unit list - const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units"); + RecVec UnitList = Stage->getValueAsListOfDefs("Units"); // For each unit for (unsigned j = 0, M = UnitList.size(); j < M;) { @@ -306,7 +338,7 @@ void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) { // Get operand cycle list - const std::vector<int64_t> &OperandCycleList = + std::vector<int64_t> OperandCycleList = ItinData->getValueAsListOfInts("OperandCycles"); // For each operand cycle @@ -324,8 +356,7 @@ Record *ItinData, std::string &ItinString, unsigned NOperandCycles) { - const std::vector<Record*> &BypassList = - ItinData->getValueAsListOfDefs("Bypasses"); + RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses"); unsigned N = BypassList.size(); unsigned i = 0; for (; i < N;) { @@ -356,7 +387,7 @@ if (!ItinsDefSet.insert(ProcModel.ItinsDef).second) continue; - std::vector<Record*> FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); + RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); if (FUs.empty()) continue; @@ -370,9 +401,9 @@ OS << "} // end namespace " << Name << "FU\n"; - std::vector<Record*> BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); + RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); if (!BPs.empty()) { - OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name + OS << "\n// Pipeline forwarding paths for itineraries \"" << Name << "\"\n" << "namespace " << Name << "Bypass {\n"; OS << " const unsigned NoBypass = 0;\n"; @@ -444,7 +475,7 @@ } // Check to see if stage already exists and create if it doesn't - unsigned FindStage = 0; + uint16_t FindStage = 0; if (NStages > 0) { FindStage = ItinStageMap[ItinStageString]; if (FindStage == 0) { @@ -460,7 +491,7 @@ } // Check to see if operand cycle already exists and create if it doesn't - unsigned FindOperandCycle = 0; + uint16_t FindOperandCycle = 0; if (NOperandCycles > 0) { std::string ItinOperandString = ItinOperandCycleString+ItinBypassString; FindOperandCycle = ItinOperandMap[ItinOperandString]; @@ -482,10 +513,14 @@ } // Set up itinerary as location and location + stage count - int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; - InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, - FindOperandCycle, - FindOperandCycle + NOperandCycles }; + int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; + InstrItinerary Intinerary = { + NumUOps, + FindStage, + uint16_t(FindStage + NStages), + FindOperandCycle, + uint16_t(FindOperandCycle + NOperandCycles), + }; // Inject - empty slots will be 0, 0 ItinList[SchedClassIdx] = Intinerary; @@ -561,7 +596,8 @@ ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; } // End processor itinerary table - OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n"; + OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }" + "// end marker\n"; OS << "};\n"; } } @@ -603,15 +639,146 @@ OS << "};\n"; } +static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0; + if (Record *RCU = ProcModel.RetireControlUnit) { + ReorderBufferSize = + std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize")); + MaxRetirePerCycle = + std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle")); + } + + OS << ReorderBufferSize << ", // ReorderBufferSize\n "; + OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n "; +} + +static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel, + unsigned NumRegisterFiles, + unsigned NumCostEntries, raw_ostream &OS) { + if (NumRegisterFiles) + OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles); + else + OS << "nullptr,\n 0"; + + OS << ", // Number of register files.\n "; + if (NumCostEntries) + OS << ProcModel.ModelName << "RegisterCosts,\n "; + else + OS << "nullptr,\n "; + OS << NumCostEntries << ", // Number of register cost entries.\n"; +} + +unsigned +SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) { + return RF.hasDefaultCosts(); + })) + return 0; + + // Print the RegisterCost table first. + OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n"; + OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName + << "RegisterCosts" + << "[] = {\n"; + + for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) { + // Skip register files with a default cost table. + if (RF.hasDefaultCosts()) + continue; + // Add entries to the cost table. + for (const CodeGenRegisterCost &RC : RF.Costs) { + OS << " { "; + Record *Rec = RC.RCDef; + if (Rec->getValue("Namespace")) + OS << Rec->getValueAsString("Namespace") << "::"; + OS << Rec->getName() << "RegClassID, " << RC.Cost << ", " + << RC.AllowMoveElimination << "},\n"; + } + } + OS << "};\n"; + + // Now generate a table with register file info. + OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, " + << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n"; + OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName + << "RegisterFiles" + << "[] = {\n" + << " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n"; + unsigned CostTblIndex = 0; + + for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) { + OS << " { "; + OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", "; + unsigned NumCostEntries = RD.Costs.size(); + OS << NumCostEntries << ", " << CostTblIndex << ", " + << RD.MaxMovesEliminatedPerCycle << ", " + << RD.AllowZeroMoveEliminationOnly << "},\n"; + CostTblIndex += NumCostEntries; + } + OS << "};\n"; + + return CostTblIndex; +} + +void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + unsigned QueueID = 0; + if (ProcModel.LoadQueue) { + const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor"); + QueueID = + 1 + std::distance(ProcModel.ProcResourceDefs.begin(), + std::find(ProcModel.ProcResourceDefs.begin(), + ProcModel.ProcResourceDefs.end(), Queue)); + } + OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n"; + + QueueID = 0; + if (ProcModel.StoreQueue) { + const Record *Queue = + ProcModel.StoreQueue->getValueAsDef("QueueDescriptor"); + QueueID = + 1 + std::distance(ProcModel.ProcResourceDefs.begin(), + std::find(ProcModel.ProcResourceDefs.begin(), + ProcModel.ProcResourceDefs.end(), Queue)); + } + OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n"; +} + +void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + // Generate a table of register file descriptors (one entry per each user + // defined register file), and a table of register costs. + unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS); + + // Now generate a table for the extra processor info. + OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName + << "ExtraInfo = {\n "; + + // Add information related to the retire control unit. + EmitRetireControlUnitInfo(ProcModel, OS); + + // Add information related to the register files (i.e. where to find register + // file descriptors and register costs). + EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), + NumCostEntries, OS); + + // Add information about load/store queues. + EmitLoadStoreQueueInfo(ProcModel, OS); + + OS << "};\n"; +} + void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, raw_ostream &OS) { EmitProcessorResourceSubUnits(ProcModel, OS); - OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered, SubUnitsIdxBegin}\n"; + OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n"; OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName << "ProcResources" << "[] = {\n" - << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0, 0},\n"; + << " {\"InvalidUnit\", 0, 0, 0, 0},\n"; unsigned SubUnitsOffset = 1; for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { @@ -640,7 +807,7 @@ NumUnits = PRDef->getValueAsInt("NumUnits"); } // Emit the ProcResourceDesc - OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; + OS << " {\"" << PRDef->getName() << "\", "; if (PRDef->getName().size() < 15) OS.indent(15 - PRDef->getName().size()); OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", "; @@ -768,8 +935,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, const CodeGenProcModel &PM) { - // Default to 1 resource cycle. - Cycles.resize(PRVec.size(), 1); + assert(PRVec.size() == Cycles.size() && "failed precondition"); for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { Record *PRDef = PRVec[i]; RecVec SubResources; @@ -820,9 +986,9 @@ return; std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); - DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n"); + LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n"); for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { - DEBUG(SC.dump(&SchedModels)); + LLVM_DEBUG(SC.dump(&SchedModels)); SCTab.resize(SCTab.size() + 1); MCSchedClassDesc &SCDesc = SCTab.back(); @@ -860,7 +1026,7 @@ IdxVec Writes = SC.Writes; IdxVec Reads = SC.Reads; if (!SC.InstRWs.empty()) { - // This class has a default ReadWrite list which can be overriden by + // This class has a default ReadWrite list which can be overridden by // InstRW definitions. Record *RWDef = nullptr; for (Record *RW : SC.InstRWs) { @@ -888,8 +1054,9 @@ } } if (Writes.empty()) { - DEBUG(dbgs() << ProcModel.ModelName - << " does not have resources for class " << SC.Name << '\n'); + LLVM_DEBUG(dbgs() << ProcModel.ModelName + << " does not have resources for class " << SC.Name + << '\n'); } } // Sum resources across all operand writes. @@ -937,6 +1104,21 @@ std::vector<int64_t> Cycles = WriteRes->getValueAsListOfInts("ResourceCycles"); + if (Cycles.empty()) { + // If ResourceCycles is not provided, default to one cycle per + // resource. + Cycles.resize(PRVec.size(), 1); + } else if (Cycles.size() != PRVec.size()) { + // If ResourceCycles is provided, check consistency. + PrintFatalError( + WriteRes->getLoc(), + Twine("Inconsistent resource cycles: !size(ResourceCycles) != " + "!size(ProcResources): ") + .concat(Twine(PRVec.size())) + .concat(" vs ") + .concat(Twine(Cycles.size()))); + } + ExpandProcResources(PRVec, Cycles, ProcModel); for (unsigned PRIdx = 0, PREnd = PRVec.size(); @@ -986,7 +1168,7 @@ WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false)); } } - std::sort(WriteIDs.begin(), WriteIDs.end()); + llvm::sort(WriteIDs); for(unsigned W : WriteIDs) { MCReadAdvanceEntry RAEntry; RAEntry.UseIdx = UseIdx; @@ -1004,8 +1186,7 @@ // compression. // // WritePrecRes entries are sorted by ProcResIdx. - std::sort(WriteProcResources.begin(), WriteProcResources.end(), - LessWriteProcResources()); + llvm::sort(WriteProcResources, LessWriteProcResources()); SCDesc.NumWriteProcResEntries = WriteProcResources.size(); std::vector<MCWriteProcResEntry>::iterator WPRPos = @@ -1156,6 +1337,9 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { // For each processor model. for (const CodeGenProcModel &PM : SchedModels.procModels()) { + // Emit extra processor info if available. + if (PM.hasExtraProcessorInfo()) + EmitExtraProcessorInfo(PM, OS); // Emit processor resource table. if (PM.hasInstrSchedModel()) EmitProcessorResources(PM, OS); @@ -1196,43 +1380,18 @@ OS << " nullptr, nullptr, 0, 0," << " // No instruction-level machine model.\n"; if (PM.hasItineraries()) - OS << " " << PM.ItinsDef->getName() << "\n"; + OS << " " << PM.ItinsDef->getName() << ",\n"; else - OS << " nullptr // No Itinerary\n"; + OS << " nullptr, // No Itinerary\n"; + if (PM.hasExtraProcessorInfo()) + OS << " &" << PM.ModelName << "ExtraInfo,\n"; + else + OS << " nullptr // No extra processor descriptor\n"; OS << "};\n"; } } // -// EmitProcessorLookup - generate cpu name to itinerary lookup table. -// -void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { - // Gather and sort processor information - std::vector<Record*> ProcessorList = - Records.getAllDerivedDefinitions("Processor"); - std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); - - // Begin processor table - OS << "\n"; - OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" - << "extern const llvm::SubtargetInfoKV " - << Target << "ProcSchedKV[] = {\n"; - - // For each processor - for (Record *Processor : ProcessorList) { - StringRef Name = Processor->getValueAsString("Name"); - const std::string &ProcModelName = - SchedModels.getModelForProc(Processor).ModelName; - - // Emit as { "cpu", procinit }, - OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " },\n"; - } - - // End processor table - OS << "};\n"; -} - -// // EmitSchedModel - Emits all scheduling model tables, folding common patterns. // void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { @@ -1260,12 +1419,213 @@ } EmitSchedClassTables(SchedTables, OS); + OS << "\n#undef DBGFIELD\n"; + // Emit the processor machine model EmitProcessorModels(OS); - // Emit the processor lookup data - EmitProcessorLookup(OS); +} + +static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + + // Collect all the PredicateProlog records and print them to the output + // stream. + std::vector<Record *> Prologs = + Records.getAllDerivedDefinitions("PredicateProlog"); + llvm::sort(Prologs, LessRecord()); + for (Record *P : Prologs) + Stream << P->getValueAsString("Code") << '\n'; + + Stream.flush(); + OS << Buffer; +} + +static void emitPredicates(const CodeGenSchedTransition &T, + const CodeGenSchedClass &SC, PredicateExpander &PE, + raw_ostream &OS) { + std::string Buffer; + raw_string_ostream SS(Buffer); + + auto IsTruePredicate = [](const Record *Rec) { + return Rec->isSubClassOf("MCSchedPredicate") && + Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue"); + }; + + // If not all predicates are MCTrue, then we need an if-stmt. + unsigned NumNonTruePreds = + T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate); + + SS.indent(PE.getIndentLevel() * 2); + + if (NumNonTruePreds) { + bool FirstNonTruePredicate = true; + SS << "if ("; + + PE.setIndentLevel(PE.getIndentLevel() + 2); + + for (const Record *Rec : T.PredTerm) { + // Skip predicates that evaluate to "true". + if (IsTruePredicate(Rec)) + continue; + + if (FirstNonTruePredicate) { + FirstNonTruePredicate = false; + } else { + SS << "\n"; + SS.indent(PE.getIndentLevel() * 2); + SS << "&& "; + } + + if (Rec->isSubClassOf("MCSchedPredicate")) { + PE.expandPredicate(SS, Rec->getValueAsDef("Pred")); + continue; + } + + // Expand this legacy predicate and wrap it around braces if there is more + // than one predicate to expand. + SS << ((NumNonTruePreds > 1) ? "(" : "") + << Rec->getValueAsString("Predicate") + << ((NumNonTruePreds > 1) ? ")" : ""); + } + + SS << ")\n"; // end of if-stmt + PE.decreaseIndentLevel(); + SS.indent(PE.getIndentLevel() * 2); + PE.decreaseIndentLevel(); + } + + SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; + SS.flush(); + OS << Buffer; +} + +// Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate +// epilogue code for the auto-generated helper. +void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) { + if (ShouldReturnZero) { + OS << " // Don't know how to resolve this scheduling class.\n" + << " return 0;\n"; + return; + } + + OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; +} + +bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { + return all_of(T.PredTerm, [](const Record *Rec) { + return Rec->isSubClassOf("MCSchedPredicate"); + }); +} - OS << "\n#undef DBGFIELD"; +void collectVariantClasses(const CodeGenSchedModels &SchedModels, + IdxVec &VariantClasses, + bool OnlyExpandMCInstPredicates) { + for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { + // Ignore non-variant scheduling classes. + if (SC.Transitions.empty()) + continue; + + if (OnlyExpandMCInstPredicates) { + // Ignore this variant scheduling class no transitions use any meaningful + // MCSchedPredicate definitions. + if (!any_of(SC.Transitions, [](const CodeGenSchedTransition &T) { + return hasMCSchedPredicates(T); + })) + continue; + } + + VariantClasses.push_back(SC.Index); + } +} + +void collectProcessorIndices(const CodeGenSchedClass &SC, IdxVec &ProcIndices) { + // A variant scheduling class may define transitions for multiple + // processors. This function identifies wich processors are associated with + // transition rules specified by variant class `SC`. + for (const CodeGenSchedTransition &T : SC.Transitions) { + IdxVec PI; + std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), + ProcIndices.begin(), ProcIndices.end(), + std::back_inserter(PI)); + ProcIndices.swap(PI); + } +} + +void SubtargetEmitter::emitSchedModelHelpersImpl( + raw_ostream &OS, bool OnlyExpandMCInstPredicates) { + IdxVec VariantClasses; + collectVariantClasses(SchedModels, VariantClasses, + OnlyExpandMCInstPredicates); + + if (VariantClasses.empty()) { + emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); + return; + } + + // Construct a switch statement where the condition is a check on the + // scheduling class identifier. There is a `case` for every variant class + // defined by the processor models of this target. + // Each `case` implements a number of rules to resolve (i.e. to transition from) + // a variant scheduling class to another scheduling class. Rules are + // described by instances of CodeGenSchedTransition. Note that transitions may + // not be valid for all processors. + OS << " switch (SchedClass) {\n"; + for (unsigned VC : VariantClasses) { + IdxVec ProcIndices; + const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); + collectProcessorIndices(SC, ProcIndices); + + OS << " case " << VC << ": // " << SC.Name << '\n'; + + PredicateExpander PE(Target); + PE.setByRef(false); + PE.setExpandForMC(OnlyExpandMCInstPredicates); + for (unsigned PI : ProcIndices) { + OS << " "; + + // Emit a guard on the processor ID. + if (PI != 0) { + OS << (OnlyExpandMCInstPredicates + ? "if (CPUID == " + : "if (SchedModel->getProcessorID() == "); + OS << PI << ") "; + OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n'; + } + + // Now emit transitions associated with processor PI. + for (const CodeGenSchedTransition &T : SC.Transitions) { + if (PI != 0 && !count(T.ProcIndices, PI)) + continue; + + // Emit only transitions based on MCSchedPredicate, if it's the case. + // At least the transition specified by NoSchedPred is emitted, + // which becomes the default transition for those variants otherwise + // not based on MCSchedPredicate. + // FIXME: preferably, llvm-mca should instead assume a reasonable + // default when a variant transition is not based on MCSchedPredicate + // for a given processor. + if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T)) + continue; + + PE.setIndentLevel(3); + emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); + } + + OS << " }\n"; + + if (PI == 0) + break; + } + + if (SC.isInferred()) + OS << " return " << SC.Index << ";\n"; + OS << " break;\n"; + } + + OS << " };\n"; + + emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); } void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, @@ -1274,64 +1634,29 @@ << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," << " const TargetSchedModel *SchedModel) const {\n"; - std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); - std::sort(Prologs.begin(), Prologs.end(), LessRecord()); - for (Record *P : Prologs) { - OS << P->getValueAsString("Code") << '\n'; - } - IdxVec VariantClasses; - for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { - if (SC.Transitions.empty()) - continue; - VariantClasses.push_back(SC.Index); - } - if (!VariantClasses.empty()) { - OS << " switch (SchedClass) {\n"; - for (unsigned VC : VariantClasses) { - const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); - OS << " case " << VC << ": // " << SC.Name << '\n'; - IdxVec ProcIndices; - for (const CodeGenSchedTransition &T : SC.Transitions) { - IdxVec PI; - std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), - ProcIndices.begin(), ProcIndices.end(), - std::back_inserter(PI)); - ProcIndices.swap(PI); - } - for (unsigned PI : ProcIndices) { - OS << " "; - if (PI != 0) - OS << "if (SchedModel->getProcessorID() == " << PI << ") "; - OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName - << '\n'; - for (const CodeGenSchedTransition &T : SC.Transitions) { - if (PI != 0 && !std::count(T.ProcIndices.begin(), - T.ProcIndices.end(), PI)) { - continue; - } - OS << " if ("; - for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end(); - RI != RE; ++RI) { - if (RI != T.PredTerm.begin()) - OS << "\n && "; - OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; - } - OS << ")\n" - << " return " << T.ToClassIdx << "; // " - << SchedModels.getSchedClass(T.ToClassIdx).Name << '\n'; - } - OS << " }\n"; - if (PI == 0) - break; - } - if (SC.isInferred()) - OS << " return " << SC.Index << ";\n"; - OS << " break;\n"; - } - OS << " };\n"; - } - OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" - << "} // " << ClassName << "::resolveSchedClass\n"; + // Emit the predicate prolog code. + emitPredicateProlog(Records, OS); + + // Emit target predicates. + emitSchedModelHelpersImpl(OS); + + OS << "} // " << ClassName << "::resolveSchedClass\n\n"; + + OS << "unsigned " << ClassName + << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," + << " unsigned CPUID) const {\n" + << " return " << Target << "_MC" + << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n" + << "} // " << ClassName << "::resolveVariantSchedClass\n\n"; + + STIPredicateExpander PE(Target); + PE.setClassPrefix(ClassName); + PE.setExpandDefinition(true); + PE.setByRef(false); + PE.setIndentLevel(0); + + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE.expandSTIPredicate(OS, Fn); } void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName, @@ -1359,15 +1684,15 @@ unsigned NumProcs) { std::vector<Record*> Features = Records.getAllDerivedDefinitions("SubtargetFeature"); - std::sort(Features.begin(), Features.end(), LessRecord()); + llvm::sort(Features, LessRecord()); OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" << "// subtarget options.\n" << "void llvm::"; OS << Target; OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" - << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" - << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; + << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" + << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; if (Features.empty()) { OS << "}\n"; @@ -1397,6 +1722,58 @@ OS << "}\n"; } +void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { + OS << "namespace " << Target << "_MC {\n" + << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" + << " const MCInst *MI, unsigned CPUID) {\n"; + emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true); + OS << "}\n"; + OS << "} // end of namespace " << Target << "_MC\n\n"; + + OS << "struct " << Target + << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; + OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT, \n" + << " StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF,\n" + << " ArrayRef<SubtargetSubTypeKV> PD,\n" + << " const MCWriteProcResEntry *WPR,\n" + << " const MCWriteLatencyEntry *WL,\n" + << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" + << " const unsigned *OC, const unsigned *FP) :\n" + << " MCSubtargetInfo(TT, CPU, FS, PF, PD,\n" + << " WPR, WL, RA, IS, OC, FP) { }\n\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" + << " const MCInst *MI, unsigned CPUID) const override {\n" + << " return " << Target << "_MC" + << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n"; + OS << " }\n"; + OS << "};\n"; +} + +void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) { + OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n"; + OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; + + STIPredicateExpander PE(Target); + PE.setExpandForMC(true); + PE.setByRef(true); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE.expandSTIPredicate(OS, Fn); + + OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; + + OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n"; + OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; + + std::string ClassPrefix = Target + "MCInstrAnalysis"; + PE.setExpandDefinition(true); + PE.setClassPrefix(ClassPrefix); + PE.setIndentLevel(0); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE.expandSTIPredicate(OS, Fn); + + OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; +} + // // SubtargetEmitter::run - Main subtarget enumeration emitter. // @@ -1406,8 +1783,10 @@ OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; OS << "#undef GET_SUBTARGETINFO_ENUM\n\n"; + DenseMap<Record *, unsigned> FeatureMap; + OS << "namespace llvm {\n"; - Enumeration(OS); + Enumeration(OS, FeatureMap); OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; @@ -1418,21 +1797,23 @@ #if 0 OS << "namespace {\n"; #endif - unsigned NumFeatures = FeatureKeyValues(OS); - OS << "\n"; - unsigned NumProcs = CPUKeyValues(OS); + unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap); OS << "\n"; EmitSchedModel(OS); OS << "\n"; + unsigned NumProcs = CPUKeyValues(OS, FeatureMap); + OS << "\n"; #if 0 OS << "} // end anonymous namespace\n\n"; #endif // MCInstrInfo initialization routine. + emitGenMCSubtargetInfo(OS); + OS << "\nstatic inline MCSubtargetInfo *create" << Target << "MCSubtargetInfoImpl(" << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; - OS << " return new MCSubtargetInfo(TT, CPU, FS, "; + OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, "; if (NumFeatures) OS << Target << "FeatureKV, "; else @@ -1442,8 +1823,7 @@ else OS << "None, "; OS << '\n'; OS.indent(22); - OS << Target << "ProcSchedKV, " - << Target << "WriteProcResTable, " + OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; OS << '\n'; OS.indent(22); @@ -1475,6 +1855,10 @@ std::string ClassName = Target + "GenSubtargetInfo"; OS << "namespace llvm {\n"; OS << "class DFAPacketizer;\n"; + OS << "namespace " << Target << "_MC {\n" + << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," + << " const MCInst *MI, unsigned CPUID);\n" + << "}\n\n"; OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " << "StringRef FS);\n" @@ -1482,10 +1866,18 @@ << " unsigned resolveSchedClass(unsigned SchedClass, " << " const MachineInstr *DefMI," << " const TargetSchedModel *SchedModel) const override;\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass," + << " const MCInst *MI, unsigned CPUID) const override;\n" << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n"; if (TGT.getHwModes().getNumModeIds() > 1) OS << " unsigned getHwMode() const override;\n"; + + STIPredicateExpander PE(Target); + PE.setByRef(false); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE.expandSTIPredicate(OS, Fn); + OS << "};\n" << "} // end namespace llvm\n\n"; @@ -1497,8 +1889,7 @@ OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; OS << "namespace llvm {\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; - OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; - OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; + OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n"; OS << "extern const llvm::MCWriteProcResEntry " << Target << "WriteProcResTable[];\n"; OS << "extern const llvm::MCWriteLatencyEntry " @@ -1524,8 +1915,7 @@ else OS << "None, "; OS << '\n'; OS.indent(24); - OS << Target << "ProcSchedKV, " - << Target << "WriteProcResTable, " + OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; OS << '\n'; OS.indent(24); @@ -1543,6 +1933,8 @@ OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; + + EmitMCInstrAnalysisPredicateFunctions(OS); } namespace llvm {