[yaml2obj/obj2yaml] - Add support for .stack_sizes sections.
[llvm-complete.git] / utils / TableGen / SubtargetEmitter.cpp
blobf970572365022c984e0cb662bdec644cfe078286
1 //===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend emits subtarget enumerations.
11 //===----------------------------------------------------------------------===//
13 #include "CodeGenTarget.h"
14 #include "CodeGenSchedule.h"
15 #include "PredicateExpander.h"
16 #include "llvm/ADT/SmallPtrSet.h"
17 #include "llvm/ADT/STLExtras.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/MC/SubtargetFeature.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/TableGen/Error.h"
27 #include "llvm/TableGen/Record.h"
28 #include "llvm/TableGen/TableGenBackend.h"
29 #include <algorithm>
30 #include <cassert>
31 #include <cstdint>
32 #include <iterator>
33 #include <map>
34 #include <string>
35 #include <vector>
37 using namespace llvm;
39 #define DEBUG_TYPE "subtarget-emitter"
41 namespace {
43 class SubtargetEmitter {
44 // Each processor has a SchedClassDesc table with an entry for each SchedClass.
45 // The SchedClassDesc table indexes into a global write resource table, write
46 // latency table, and read advance table.
47 struct SchedClassTables {
48 std::vector<std::vector<MCSchedClassDesc>> ProcSchedClasses;
49 std::vector<MCWriteProcResEntry> WriteProcResources;
50 std::vector<MCWriteLatencyEntry> WriteLatencies;
51 std::vector<std::string> WriterNames;
52 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
54 // Reserve an invalid entry at index 0
55 SchedClassTables() {
56 ProcSchedClasses.resize(1);
57 WriteProcResources.resize(1);
58 WriteLatencies.resize(1);
59 WriterNames.push_back("InvalidWrite");
60 ReadAdvanceEntries.resize(1);
64 struct LessWriteProcResources {
65 bool operator()(const MCWriteProcResEntry &LHS,
66 const MCWriteProcResEntry &RHS) {
67 return LHS.ProcResourceIdx < RHS.ProcResourceIdx;
71 const CodeGenTarget &TGT;
72 RecordKeeper &Records;
73 CodeGenSchedModels &SchedModels;
74 std::string Target;
76 void Enumeration(raw_ostream &OS, DenseMap<Record *, unsigned> &FeatureMap);
77 unsigned FeatureKeyValues(raw_ostream &OS,
78 const DenseMap<Record *, unsigned> &FeatureMap);
79 unsigned CPUKeyValues(raw_ostream &OS,
80 const DenseMap<Record *, unsigned> &FeatureMap);
81 void FormItineraryStageString(const std::string &Names,
82 Record *ItinData, std::string &ItinString,
83 unsigned &NStages);
84 void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
85 unsigned &NOperandCycles);
86 void FormItineraryBypassString(const std::string &Names,
87 Record *ItinData,
88 std::string &ItinString, unsigned NOperandCycles);
89 void EmitStageAndOperandCycleData(raw_ostream &OS,
90 std::vector<std::vector<InstrItinerary>>
91 &ProcItinLists);
92 void EmitItineraries(raw_ostream &OS,
93 std::vector<std::vector<InstrItinerary>>
94 &ProcItinLists);
95 unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
96 raw_ostream &OS);
97 void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
98 raw_ostream &OS);
99 void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,
100 raw_ostream &OS);
101 void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name,
102 char Separator);
103 void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel,
104 raw_ostream &OS);
105 void EmitProcessorResources(const CodeGenProcModel &ProcModel,
106 raw_ostream &OS);
107 Record *FindWriteResources(const CodeGenSchedRW &SchedWrite,
108 const CodeGenProcModel &ProcModel);
109 Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
110 const CodeGenProcModel &ProcModel);
111 void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
112 const CodeGenProcModel &ProcModel);
113 void GenSchedClassTables(const CodeGenProcModel &ProcModel,
114 SchedClassTables &SchedTables);
115 void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
116 void EmitProcessorModels(raw_ostream &OS);
117 void EmitProcessorLookup(raw_ostream &OS);
118 void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS);
119 void emitSchedModelHelpersImpl(raw_ostream &OS,
120 bool OnlyExpandMCInstPredicates = false);
121 void emitGenMCSubtargetInfo(raw_ostream &OS);
122 void EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS);
124 void EmitSchedModel(raw_ostream &OS);
125 void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS);
126 void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures,
127 unsigned NumProcs);
129 public:
130 SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT)
131 : TGT(TGT), Records(R), SchedModels(TGT.getSchedModels()),
132 Target(TGT.getName()) {}
134 void run(raw_ostream &o);
137 } // end anonymous namespace
140 // Enumeration - Emit the specified class as an enumeration.
142 void SubtargetEmitter::Enumeration(raw_ostream &OS,
143 DenseMap<Record *, unsigned> &FeatureMap) {
144 // Get all records of class and sort
145 std::vector<Record*> DefList =
146 Records.getAllDerivedDefinitions("SubtargetFeature");
147 llvm::sort(DefList, LessRecord());
149 unsigned N = DefList.size();
150 if (N == 0)
151 return;
152 if (N + 1 > MAX_SUBTARGET_FEATURES)
153 PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
155 OS << "namespace " << Target << " {\n";
157 // Open enumeration.
158 OS << "enum {\n";
160 // For each record
161 for (unsigned i = 0; i < N; ++i) {
162 // Next record
163 Record *Def = DefList[i];
165 // Get and emit name
166 OS << " " << Def->getName() << " = " << i << ",\n";
168 // Save the index for this feature.
169 FeatureMap[Def] = i;
172 OS << " "
173 << "NumSubtargetFeatures = " << N << "\n";
175 // Close enumeration and namespace
176 OS << "};\n";
177 OS << "} // end namespace " << Target << "\n";
180 static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList,
181 const DenseMap<Record *, unsigned> &FeatureMap) {
182 std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
183 for (unsigned j = 0, M = FeatureList.size(); j < M; ++j) {
184 unsigned Bit = FeatureMap.lookup(FeatureList[j]);
185 Mask[Bit / 64] |= 1ULL << (Bit % 64);
188 OS << "{ { { ";
189 for (unsigned i = 0; i != Mask.size(); ++i) {
190 OS << "0x";
191 OS.write_hex(Mask[i]);
192 OS << "ULL, ";
194 OS << "} } }";
198 // FeatureKeyValues - Emit data of all the subtarget features. Used by the
199 // command line.
201 unsigned SubtargetEmitter::FeatureKeyValues(
202 raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap) {
203 // Gather and sort all the features
204 std::vector<Record*> FeatureList =
205 Records.getAllDerivedDefinitions("SubtargetFeature");
207 if (FeatureList.empty())
208 return 0;
210 llvm::sort(FeatureList, LessRecordFieldName());
212 // Begin feature table
213 OS << "// Sorted (by key) array of values for CPU features.\n"
214 << "extern const llvm::SubtargetFeatureKV " << Target
215 << "FeatureKV[] = {\n";
217 // For each feature
218 unsigned NumFeatures = 0;
219 for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) {
220 // Next feature
221 Record *Feature = FeatureList[i];
223 StringRef Name = Feature->getName();
224 StringRef CommandLineName = Feature->getValueAsString("Name");
225 StringRef Desc = Feature->getValueAsString("Desc");
227 if (CommandLineName.empty()) continue;
229 // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } }
230 OS << " { "
231 << "\"" << CommandLineName << "\", "
232 << "\"" << Desc << "\", "
233 << Target << "::" << Name << ", ";
235 RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
237 printFeatureMask(OS, ImpliesList, FeatureMap);
239 OS << " },\n";
240 ++NumFeatures;
243 // End feature table
244 OS << "};\n";
246 return NumFeatures;
250 // CPUKeyValues - Emit data of all the subtarget processors. Used by command
251 // line.
253 unsigned
254 SubtargetEmitter::CPUKeyValues(raw_ostream &OS,
255 const DenseMap<Record *, unsigned> &FeatureMap) {
256 // Gather and sort processor information
257 std::vector<Record*> ProcessorList =
258 Records.getAllDerivedDefinitions("Processor");
259 llvm::sort(ProcessorList, LessRecordFieldName());
261 // Begin processor table
262 OS << "// Sorted (by key) array of values for CPU subtype.\n"
263 << "extern const llvm::SubtargetSubTypeKV " << Target
264 << "SubTypeKV[] = {\n";
266 // For each processor
267 for (Record *Processor : ProcessorList) {
268 StringRef Name = Processor->getValueAsString("Name");
269 RecVec FeatureList = Processor->getValueAsListOfDefs("Features");
271 // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } },
272 OS << " { "
273 << "\"" << Name << "\", ";
275 printFeatureMask(OS, FeatureList, FeatureMap);
277 // Emit the scheduler model pointer.
278 const std::string &ProcModelName =
279 SchedModels.getModelForProc(Processor).ModelName;
280 OS << ", &" << ProcModelName << " },\n";
283 // End processor table
284 OS << "};\n";
286 return ProcessorList.size();
290 // FormItineraryStageString - Compose a string containing the stage
291 // data initialization for the specified itinerary. N is the number
292 // of stages.
294 void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
295 Record *ItinData,
296 std::string &ItinString,
297 unsigned &NStages) {
298 // Get states list
299 RecVec StageList = ItinData->getValueAsListOfDefs("Stages");
301 // For each stage
302 unsigned N = NStages = StageList.size();
303 for (unsigned i = 0; i < N;) {
304 // Next stage
305 const Record *Stage = StageList[i];
307 // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }
308 int Cycles = Stage->getValueAsInt("Cycles");
309 ItinString += " { " + itostr(Cycles) + ", ";
311 // Get unit list
312 RecVec UnitList = Stage->getValueAsListOfDefs("Units");
314 // For each unit
315 for (unsigned j = 0, M = UnitList.size(); j < M;) {
316 // Add name and bitwise or
317 ItinString += Name + "FU::" + UnitList[j]->getName().str();
318 if (++j < M) ItinString += " | ";
321 int TimeInc = Stage->getValueAsInt("TimeInc");
322 ItinString += ", " + itostr(TimeInc);
324 int Kind = Stage->getValueAsInt("Kind");
325 ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);
327 // Close off stage
328 ItinString += " }";
329 if (++i < N) ItinString += ", ";
334 // FormItineraryOperandCycleString - Compose a string containing the
335 // operand cycle initialization for the specified itinerary. N is the
336 // number of operands that has cycles specified.
338 void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData,
339 std::string &ItinString, unsigned &NOperandCycles) {
340 // Get operand cycle list
341 std::vector<int64_t> OperandCycleList =
342 ItinData->getValueAsListOfInts("OperandCycles");
344 // For each operand cycle
345 unsigned N = NOperandCycles = OperandCycleList.size();
346 for (unsigned i = 0; i < N;) {
347 // Next operand cycle
348 const int OCycle = OperandCycleList[i];
350 ItinString += " " + itostr(OCycle);
351 if (++i < N) ItinString += ", ";
355 void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
356 Record *ItinData,
357 std::string &ItinString,
358 unsigned NOperandCycles) {
359 RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses");
360 unsigned N = BypassList.size();
361 unsigned i = 0;
362 for (; i < N;) {
363 ItinString += Name + "Bypass::" + BypassList[i]->getName().str();
364 if (++i < NOperandCycles) ItinString += ", ";
366 for (; i < NOperandCycles;) {
367 ItinString += " 0";
368 if (++i < NOperandCycles) ItinString += ", ";
373 // EmitStageAndOperandCycleData - Generate unique itinerary stages and operand
374 // cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed
375 // by CodeGenSchedClass::Index.
377 void SubtargetEmitter::
378 EmitStageAndOperandCycleData(raw_ostream &OS,
379 std::vector<std::vector<InstrItinerary>>
380 &ProcItinLists) {
381 // Multiple processor models may share an itinerary record. Emit it once.
382 SmallPtrSet<Record*, 8> ItinsDefSet;
384 // Emit functional units for all the itineraries.
385 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
387 if (!ItinsDefSet.insert(ProcModel.ItinsDef).second)
388 continue;
390 RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU");
391 if (FUs.empty())
392 continue;
394 StringRef Name = ProcModel.ItinsDef->getName();
395 OS << "\n// Functional units for \"" << Name << "\"\n"
396 << "namespace " << Name << "FU {\n";
398 for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
399 OS << " const unsigned " << FUs[j]->getName()
400 << " = 1 << " << j << ";\n";
402 OS << "} // end namespace " << Name << "FU\n";
404 RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");
405 if (!BPs.empty()) {
406 OS << "\n// Pipeline forwarding paths for itineraries \"" << Name
407 << "\"\n" << "namespace " << Name << "Bypass {\n";
409 OS << " const unsigned NoBypass = 0;\n";
410 for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
411 OS << " const unsigned " << BPs[j]->getName()
412 << " = 1 << " << j << ";\n";
414 OS << "} // end namespace " << Name << "Bypass\n";
418 // Begin stages table
419 std::string StageTable = "\nextern const llvm::InstrStage " + Target +
420 "Stages[] = {\n";
421 StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
423 // Begin operand cycle table
424 std::string OperandCycleTable = "extern const unsigned " + Target +
425 "OperandCycles[] = {\n";
426 OperandCycleTable += " 0, // No itinerary\n";
428 // Begin pipeline bypass table
429 std::string BypassTable = "extern const unsigned " + Target +
430 "ForwardingPaths[] = {\n";
431 BypassTable += " 0, // No itinerary\n";
433 // For each Itinerary across all processors, add a unique entry to the stages,
434 // operand cycles, and pipeline bypass tables. Then add the new Itinerary
435 // object with computed offsets to the ProcItinLists result.
436 unsigned StageCount = 1, OperandCycleCount = 1;
437 std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
438 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
439 // Add process itinerary to the list.
440 ProcItinLists.resize(ProcItinLists.size()+1);
442 // If this processor defines no itineraries, then leave the itinerary list
443 // empty.
444 std::vector<InstrItinerary> &ItinList = ProcItinLists.back();
445 if (!ProcModel.hasItineraries())
446 continue;
448 StringRef Name = ProcModel.ItinsDef->getName();
450 ItinList.resize(SchedModels.numInstrSchedClasses());
451 assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");
453 for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();
454 SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
456 // Next itinerary data
457 Record *ItinData = ProcModel.ItinDefList[SchedClassIdx];
459 // Get string and stage count
460 std::string ItinStageString;
461 unsigned NStages = 0;
462 if (ItinData)
463 FormItineraryStageString(Name, ItinData, ItinStageString, NStages);
465 // Get string and operand cycle count
466 std::string ItinOperandCycleString;
467 unsigned NOperandCycles = 0;
468 std::string ItinBypassString;
469 if (ItinData) {
470 FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
471 NOperandCycles);
473 FormItineraryBypassString(Name, ItinData, ItinBypassString,
474 NOperandCycles);
477 // Check to see if stage already exists and create if it doesn't
478 uint16_t FindStage = 0;
479 if (NStages > 0) {
480 FindStage = ItinStageMap[ItinStageString];
481 if (FindStage == 0) {
482 // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices
483 StageTable += ItinStageString + ", // " + itostr(StageCount);
484 if (NStages > 1)
485 StageTable += "-" + itostr(StageCount + NStages - 1);
486 StageTable += "\n";
487 // Record Itin class number.
488 ItinStageMap[ItinStageString] = FindStage = StageCount;
489 StageCount += NStages;
493 // Check to see if operand cycle already exists and create if it doesn't
494 uint16_t FindOperandCycle = 0;
495 if (NOperandCycles > 0) {
496 std::string ItinOperandString = ItinOperandCycleString+ItinBypassString;
497 FindOperandCycle = ItinOperandMap[ItinOperandString];
498 if (FindOperandCycle == 0) {
499 // Emit as cycle, // index
500 OperandCycleTable += ItinOperandCycleString + ", // ";
501 std::string OperandIdxComment = itostr(OperandCycleCount);
502 if (NOperandCycles > 1)
503 OperandIdxComment += "-"
504 + itostr(OperandCycleCount + NOperandCycles - 1);
505 OperandCycleTable += OperandIdxComment + "\n";
506 // Record Itin class number.
507 ItinOperandMap[ItinOperandCycleString] =
508 FindOperandCycle = OperandCycleCount;
509 // Emit as bypass, // index
510 BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";
511 OperandCycleCount += NOperandCycles;
515 // Set up itinerary as location and location + stage count
516 int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0;
517 InstrItinerary Intinerary = {
518 NumUOps,
519 FindStage,
520 uint16_t(FindStage + NStages),
521 FindOperandCycle,
522 uint16_t(FindOperandCycle + NOperandCycles),
525 // Inject - empty slots will be 0, 0
526 ItinList[SchedClassIdx] = Intinerary;
530 // Closing stage
531 StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n";
532 StageTable += "};\n";
534 // Closing operand cycles
535 OperandCycleTable += " 0 // End operand cycles\n";
536 OperandCycleTable += "};\n";
538 BypassTable += " 0 // End bypass tables\n";
539 BypassTable += "};\n";
541 // Emit tables.
542 OS << StageTable;
543 OS << OperandCycleTable;
544 OS << BypassTable;
548 // EmitProcessorData - Generate data for processor itineraries that were
549 // computed during EmitStageAndOperandCycleData(). ProcItinLists lists all
550 // Itineraries for each processor. The Itinerary lists are indexed on
551 // CodeGenSchedClass::Index.
553 void SubtargetEmitter::
554 EmitItineraries(raw_ostream &OS,
555 std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
556 // Multiple processor models may share an itinerary record. Emit it once.
557 SmallPtrSet<Record*, 8> ItinsDefSet;
559 // For each processor's machine model
560 std::vector<std::vector<InstrItinerary>>::iterator
561 ProcItinListsIter = ProcItinLists.begin();
562 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
563 PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) {
565 Record *ItinsDef = PI->ItinsDef;
566 if (!ItinsDefSet.insert(ItinsDef).second)
567 continue;
569 // Get the itinerary list for the processor.
570 assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator");
571 std::vector<InstrItinerary> &ItinList = *ProcItinListsIter;
573 // Empty itineraries aren't referenced anywhere in the tablegen output
574 // so don't emit them.
575 if (ItinList.empty())
576 continue;
578 OS << "\n";
579 OS << "static const llvm::InstrItinerary ";
581 // Begin processor itinerary table
582 OS << ItinsDef->getName() << "[] = {\n";
584 // For each itinerary class in CodeGenSchedClass::Index order.
585 for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {
586 InstrItinerary &Intinerary = ItinList[j];
588 // Emit Itinerary in the form of
589 // { firstStage, lastStage, firstCycle, lastCycle } // index
590 OS << " { " <<
591 Intinerary.NumMicroOps << ", " <<
592 Intinerary.FirstStage << ", " <<
593 Intinerary.LastStage << ", " <<
594 Intinerary.FirstOperandCycle << ", " <<
595 Intinerary.LastOperandCycle << " }" <<
596 ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
598 // End processor itinerary table
599 OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }"
600 "// end marker\n";
601 OS << "};\n";
605 // Emit either the value defined in the TableGen Record, or the default
606 // value defined in the C++ header. The Record is null if the processor does not
607 // define a model.
608 void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R,
609 StringRef Name, char Separator) {
610 OS << " ";
611 int V = R ? R->getValueAsInt(Name) : -1;
612 if (V >= 0)
613 OS << V << Separator << " // " << Name;
614 else
615 OS << "MCSchedModel::Default" << Name << Separator;
616 OS << '\n';
619 void SubtargetEmitter::EmitProcessorResourceSubUnits(
620 const CodeGenProcModel &ProcModel, raw_ostream &OS) {
621 OS << "\nstatic const unsigned " << ProcModel.ModelName
622 << "ProcResourceSubUnits[] = {\n"
623 << " 0, // Invalid\n";
625 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
626 Record *PRDef = ProcModel.ProcResourceDefs[i];
627 if (!PRDef->isSubClassOf("ProcResGroup"))
628 continue;
629 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
630 for (Record *RUDef : ResUnits) {
631 Record *const RU =
632 SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc());
633 for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) {
634 OS << " " << ProcModel.getProcResourceIdx(RU) << ", ";
637 OS << " // " << PRDef->getName() << "\n";
639 OS << "};\n";
642 static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel,
643 raw_ostream &OS) {
644 int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0;
645 if (Record *RCU = ProcModel.RetireControlUnit) {
646 ReorderBufferSize =
647 std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize"));
648 MaxRetirePerCycle =
649 std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle"));
652 OS << ReorderBufferSize << ", // ReorderBufferSize\n ";
653 OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n ";
656 static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel,
657 unsigned NumRegisterFiles,
658 unsigned NumCostEntries, raw_ostream &OS) {
659 if (NumRegisterFiles)
660 OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles);
661 else
662 OS << "nullptr,\n 0";
664 OS << ", // Number of register files.\n ";
665 if (NumCostEntries)
666 OS << ProcModel.ModelName << "RegisterCosts,\n ";
667 else
668 OS << "nullptr,\n ";
669 OS << NumCostEntries << ", // Number of register cost entries.\n";
672 unsigned
673 SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
674 raw_ostream &OS) {
675 if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) {
676 return RF.hasDefaultCosts();
678 return 0;
680 // Print the RegisterCost table first.
681 OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n";
682 OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName
683 << "RegisterCosts"
684 << "[] = {\n";
686 for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) {
687 // Skip register files with a default cost table.
688 if (RF.hasDefaultCosts())
689 continue;
690 // Add entries to the cost table.
691 for (const CodeGenRegisterCost &RC : RF.Costs) {
692 OS << " { ";
693 Record *Rec = RC.RCDef;
694 if (Rec->getValue("Namespace"))
695 OS << Rec->getValueAsString("Namespace") << "::";
696 OS << Rec->getName() << "RegClassID, " << RC.Cost << ", "
697 << RC.AllowMoveElimination << "},\n";
700 OS << "};\n";
702 // Now generate a table with register file info.
703 OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, "
704 << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n";
705 OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName
706 << "RegisterFiles"
707 << "[] = {\n"
708 << " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n";
709 unsigned CostTblIndex = 0;
711 for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) {
712 OS << " { ";
713 OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", ";
714 unsigned NumCostEntries = RD.Costs.size();
715 OS << NumCostEntries << ", " << CostTblIndex << ", "
716 << RD.MaxMovesEliminatedPerCycle << ", "
717 << RD.AllowZeroMoveEliminationOnly << "},\n";
718 CostTblIndex += NumCostEntries;
720 OS << "};\n";
722 return CostTblIndex;
725 void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
726 raw_ostream &OS) {
727 unsigned QueueID = 0;
728 if (ProcModel.LoadQueue) {
729 const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor");
730 QueueID =
731 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
732 std::find(ProcModel.ProcResourceDefs.begin(),
733 ProcModel.ProcResourceDefs.end(), Queue));
735 OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n";
737 QueueID = 0;
738 if (ProcModel.StoreQueue) {
739 const Record *Queue =
740 ProcModel.StoreQueue->getValueAsDef("QueueDescriptor");
741 QueueID =
742 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
743 std::find(ProcModel.ProcResourceDefs.begin(),
744 ProcModel.ProcResourceDefs.end(), Queue));
746 OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n";
749 void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel,
750 raw_ostream &OS) {
751 // Generate a table of register file descriptors (one entry per each user
752 // defined register file), and a table of register costs.
753 unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS);
755 // Now generate a table for the extra processor info.
756 OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName
757 << "ExtraInfo = {\n ";
759 // Add information related to the retire control unit.
760 EmitRetireControlUnitInfo(ProcModel, OS);
762 // Add information related to the register files (i.e. where to find register
763 // file descriptors and register costs).
764 EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(),
765 NumCostEntries, OS);
767 // Add information about load/store queues.
768 EmitLoadStoreQueueInfo(ProcModel, OS);
770 OS << "};\n";
773 void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
774 raw_ostream &OS) {
775 EmitProcessorResourceSubUnits(ProcModel, OS);
777 OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n";
778 OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName
779 << "ProcResources"
780 << "[] = {\n"
781 << " {\"InvalidUnit\", 0, 0, 0, 0},\n";
783 unsigned SubUnitsOffset = 1;
784 for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
785 Record *PRDef = ProcModel.ProcResourceDefs[i];
787 Record *SuperDef = nullptr;
788 unsigned SuperIdx = 0;
789 unsigned NumUnits = 0;
790 const unsigned SubUnitsBeginOffset = SubUnitsOffset;
791 int BufferSize = PRDef->getValueAsInt("BufferSize");
792 if (PRDef->isSubClassOf("ProcResGroup")) {
793 RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
794 for (Record *RU : ResUnits) {
795 NumUnits += RU->getValueAsInt("NumUnits");
796 SubUnitsOffset += RU->getValueAsInt("NumUnits");
799 else {
800 // Find the SuperIdx
801 if (PRDef->getValueInit("Super")->isComplete()) {
802 SuperDef =
803 SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"),
804 ProcModel, PRDef->getLoc());
805 SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
807 NumUnits = PRDef->getValueAsInt("NumUnits");
809 // Emit the ProcResourceDesc
810 OS << " {\"" << PRDef->getName() << "\", ";
811 if (PRDef->getName().size() < 15)
812 OS.indent(15 - PRDef->getName().size());
813 OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", ";
814 if (SubUnitsBeginOffset != SubUnitsOffset) {
815 OS << ProcModel.ModelName << "ProcResourceSubUnits + "
816 << SubUnitsBeginOffset;
817 } else {
818 OS << "nullptr";
820 OS << "}, // #" << i+1;
821 if (SuperDef)
822 OS << ", Super=" << SuperDef->getName();
823 OS << "\n";
825 OS << "};\n";
828 // Find the WriteRes Record that defines processor resources for this
829 // SchedWrite.
830 Record *SubtargetEmitter::FindWriteResources(
831 const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) {
833 // Check if the SchedWrite is already subtarget-specific and directly
834 // specifies a set of processor resources.
835 if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))
836 return SchedWrite.TheDef;
838 Record *AliasDef = nullptr;
839 for (Record *A : SchedWrite.Aliases) {
840 const CodeGenSchedRW &AliasRW =
841 SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
842 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
843 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
844 if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
845 continue;
847 if (AliasDef)
848 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
849 "defined for processor " + ProcModel.ModelName +
850 " Ensure only one SchedAlias exists per RW.");
851 AliasDef = AliasRW.TheDef;
853 if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))
854 return AliasDef;
856 // Check this processor's list of write resources.
857 Record *ResDef = nullptr;
858 for (Record *WR : ProcModel.WriteResDefs) {
859 if (!WR->isSubClassOf("WriteRes"))
860 continue;
861 if (AliasDef == WR->getValueAsDef("WriteType")
862 || SchedWrite.TheDef == WR->getValueAsDef("WriteType")) {
863 if (ResDef) {
864 PrintFatalError(WR->getLoc(), "Resources are defined for both "
865 "SchedWrite and its alias on processor " +
866 ProcModel.ModelName);
868 ResDef = WR;
871 // TODO: If ProcModel has a base model (previous generation processor),
872 // then call FindWriteResources recursively with that model here.
873 if (!ResDef) {
874 PrintFatalError(ProcModel.ModelDef->getLoc(),
875 Twine("Processor does not define resources for ") +
876 SchedWrite.TheDef->getName());
878 return ResDef;
881 /// Find the ReadAdvance record for the given SchedRead on this processor or
882 /// return NULL.
883 Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
884 const CodeGenProcModel &ProcModel) {
885 // Check for SchedReads that directly specify a ReadAdvance.
886 if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))
887 return SchedRead.TheDef;
889 // Check this processor's list of aliases for SchedRead.
890 Record *AliasDef = nullptr;
891 for (Record *A : SchedRead.Aliases) {
892 const CodeGenSchedRW &AliasRW =
893 SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
894 if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
895 Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
896 if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
897 continue;
899 if (AliasDef)
900 PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
901 "defined for processor " + ProcModel.ModelName +
902 " Ensure only one SchedAlias exists per RW.");
903 AliasDef = AliasRW.TheDef;
905 if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))
906 return AliasDef;
908 // Check this processor's ReadAdvanceList.
909 Record *ResDef = nullptr;
910 for (Record *RA : ProcModel.ReadAdvanceDefs) {
911 if (!RA->isSubClassOf("ReadAdvance"))
912 continue;
913 if (AliasDef == RA->getValueAsDef("ReadType")
914 || SchedRead.TheDef == RA->getValueAsDef("ReadType")) {
915 if (ResDef) {
916 PrintFatalError(RA->getLoc(), "Resources are defined for both "
917 "SchedRead and its alias on processor " +
918 ProcModel.ModelName);
920 ResDef = RA;
923 // TODO: If ProcModel has a base model (previous generation processor),
924 // then call FindReadAdvance recursively with that model here.
925 if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {
926 PrintFatalError(ProcModel.ModelDef->getLoc(),
927 Twine("Processor does not define resources for ") +
928 SchedRead.TheDef->getName());
930 return ResDef;
933 // Expand an explicit list of processor resources into a full list of implied
934 // resource groups and super resources that cover them.
935 void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
936 std::vector<int64_t> &Cycles,
937 const CodeGenProcModel &PM) {
938 assert(PRVec.size() == Cycles.size() && "failed precondition");
939 for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
940 Record *PRDef = PRVec[i];
941 RecVec SubResources;
942 if (PRDef->isSubClassOf("ProcResGroup"))
943 SubResources = PRDef->getValueAsListOfDefs("Resources");
944 else {
945 SubResources.push_back(PRDef);
946 PRDef = SchedModels.findProcResUnits(PRDef, PM, PRDef->getLoc());
947 for (Record *SubDef = PRDef;
948 SubDef->getValueInit("Super")->isComplete();) {
949 if (SubDef->isSubClassOf("ProcResGroup")) {
950 // Disallow this for simplicitly.
951 PrintFatalError(SubDef->getLoc(), "Processor resource group "
952 " cannot be a super resources.");
954 Record *SuperDef =
955 SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM,
956 SubDef->getLoc());
957 PRVec.push_back(SuperDef);
958 Cycles.push_back(Cycles[i]);
959 SubDef = SuperDef;
962 for (Record *PR : PM.ProcResourceDefs) {
963 if (PR == PRDef || !PR->isSubClassOf("ProcResGroup"))
964 continue;
965 RecVec SuperResources = PR->getValueAsListOfDefs("Resources");
966 RecIter SubI = SubResources.begin(), SubE = SubResources.end();
967 for( ; SubI != SubE; ++SubI) {
968 if (!is_contained(SuperResources, *SubI)) {
969 break;
972 if (SubI == SubE) {
973 PRVec.push_back(PR);
974 Cycles.push_back(Cycles[i]);
980 // Generate the SchedClass table for this processor and update global
981 // tables. Must be called for each processor in order.
982 void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
983 SchedClassTables &SchedTables) {
984 SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1);
985 if (!ProcModel.hasInstrSchedModel())
986 return;
988 std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back();
989 LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n");
990 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
991 LLVM_DEBUG(SC.dump(&SchedModels));
993 SCTab.resize(SCTab.size() + 1);
994 MCSchedClassDesc &SCDesc = SCTab.back();
995 // SCDesc.Name is guarded by NDEBUG
996 SCDesc.NumMicroOps = 0;
997 SCDesc.BeginGroup = false;
998 SCDesc.EndGroup = false;
999 SCDesc.WriteProcResIdx = 0;
1000 SCDesc.WriteLatencyIdx = 0;
1001 SCDesc.ReadAdvanceIdx = 0;
1003 // A Variant SchedClass has no resources of its own.
1004 bool HasVariants = false;
1005 for (const CodeGenSchedTransition &CGT :
1006 make_range(SC.Transitions.begin(), SC.Transitions.end())) {
1007 if (CGT.ProcIndices[0] == 0 ||
1008 is_contained(CGT.ProcIndices, ProcModel.Index)) {
1009 HasVariants = true;
1010 break;
1013 if (HasVariants) {
1014 SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;
1015 continue;
1018 // Determine if the SchedClass is actually reachable on this processor. If
1019 // not don't try to locate the processor resources, it will fail.
1020 // If ProcIndices contains 0, this class applies to all processors.
1021 assert(!SC.ProcIndices.empty() && "expect at least one procidx");
1022 if (SC.ProcIndices[0] != 0) {
1023 if (!is_contained(SC.ProcIndices, ProcModel.Index))
1024 continue;
1026 IdxVec Writes = SC.Writes;
1027 IdxVec Reads = SC.Reads;
1028 if (!SC.InstRWs.empty()) {
1029 // This class has a default ReadWrite list which can be overridden by
1030 // InstRW definitions.
1031 Record *RWDef = nullptr;
1032 for (Record *RW : SC.InstRWs) {
1033 Record *RWModelDef = RW->getValueAsDef("SchedModel");
1034 if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {
1035 RWDef = RW;
1036 break;
1039 if (RWDef) {
1040 Writes.clear();
1041 Reads.clear();
1042 SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
1043 Writes, Reads);
1046 if (Writes.empty()) {
1047 // Check this processor's itinerary class resources.
1048 for (Record *I : ProcModel.ItinRWDefs) {
1049 RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses");
1050 if (is_contained(Matched, SC.ItinClassDef)) {
1051 SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"),
1052 Writes, Reads);
1053 break;
1056 if (Writes.empty()) {
1057 LLVM_DEBUG(dbgs() << ProcModel.ModelName
1058 << " does not have resources for class " << SC.Name
1059 << '\n');
1062 // Sum resources across all operand writes.
1063 std::vector<MCWriteProcResEntry> WriteProcResources;
1064 std::vector<MCWriteLatencyEntry> WriteLatencies;
1065 std::vector<std::string> WriterNames;
1066 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
1067 for (unsigned W : Writes) {
1068 IdxVec WriteSeq;
1069 SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false,
1070 ProcModel);
1072 // For each operand, create a latency entry.
1073 MCWriteLatencyEntry WLEntry;
1074 WLEntry.Cycles = 0;
1075 unsigned WriteID = WriteSeq.back();
1076 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
1077 // If this Write is not referenced by a ReadAdvance, don't distinguish it
1078 // from other WriteLatency entries.
1079 if (!SchedModels.hasReadOfWrite(
1080 SchedModels.getSchedWrite(WriteID).TheDef)) {
1081 WriteID = 0;
1083 WLEntry.WriteResourceID = WriteID;
1085 for (unsigned WS : WriteSeq) {
1087 Record *WriteRes =
1088 FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
1090 // Mark the parent class as invalid for unsupported write types.
1091 if (WriteRes->getValueAsBit("Unsupported")) {
1092 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1093 break;
1095 WLEntry.Cycles += WriteRes->getValueAsInt("Latency");
1096 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");
1097 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");
1098 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");
1099 SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue");
1100 SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue");
1102 // Create an entry for each ProcResource listed in WriteRes.
1103 RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
1104 std::vector<int64_t> Cycles =
1105 WriteRes->getValueAsListOfInts("ResourceCycles");
1107 if (Cycles.empty()) {
1108 // If ResourceCycles is not provided, default to one cycle per
1109 // resource.
1110 Cycles.resize(PRVec.size(), 1);
1111 } else if (Cycles.size() != PRVec.size()) {
1112 // If ResourceCycles is provided, check consistency.
1113 PrintFatalError(
1114 WriteRes->getLoc(),
1115 Twine("Inconsistent resource cycles: !size(ResourceCycles) != "
1116 "!size(ProcResources): ")
1117 .concat(Twine(PRVec.size()))
1118 .concat(" vs ")
1119 .concat(Twine(Cycles.size())));
1122 ExpandProcResources(PRVec, Cycles, ProcModel);
1124 for (unsigned PRIdx = 0, PREnd = PRVec.size();
1125 PRIdx != PREnd; ++PRIdx) {
1126 MCWriteProcResEntry WPREntry;
1127 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
1128 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
1129 WPREntry.Cycles = Cycles[PRIdx];
1130 // If this resource is already used in this sequence, add the current
1131 // entry's cycles so that the same resource appears to be used
1132 // serially, rather than multiple parallel uses. This is important for
1133 // in-order machine where the resource consumption is a hazard.
1134 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
1135 for( ; WPRIdx != WPREnd; ++WPRIdx) {
1136 if (WriteProcResources[WPRIdx].ProcResourceIdx
1137 == WPREntry.ProcResourceIdx) {
1138 WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
1139 break;
1142 if (WPRIdx == WPREnd)
1143 WriteProcResources.push_back(WPREntry);
1146 WriteLatencies.push_back(WLEntry);
1148 // Create an entry for each operand Read in this SchedClass.
1149 // Entries must be sorted first by UseIdx then by WriteResourceID.
1150 for (unsigned UseIdx = 0, EndIdx = Reads.size();
1151 UseIdx != EndIdx; ++UseIdx) {
1152 Record *ReadAdvance =
1153 FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
1154 if (!ReadAdvance)
1155 continue;
1157 // Mark the parent class as invalid for unsupported write types.
1158 if (ReadAdvance->getValueAsBit("Unsupported")) {
1159 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1160 break;
1162 RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");
1163 IdxVec WriteIDs;
1164 if (ValidWrites.empty())
1165 WriteIDs.push_back(0);
1166 else {
1167 for (Record *VW : ValidWrites) {
1168 WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false));
1171 llvm::sort(WriteIDs);
1172 for(unsigned W : WriteIDs) {
1173 MCReadAdvanceEntry RAEntry;
1174 RAEntry.UseIdx = UseIdx;
1175 RAEntry.WriteResourceID = W;
1176 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
1177 ReadAdvanceEntries.push_back(RAEntry);
1180 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
1181 WriteProcResources.clear();
1182 WriteLatencies.clear();
1183 ReadAdvanceEntries.clear();
1185 // Add the information for this SchedClass to the global tables using basic
1186 // compression.
1188 // WritePrecRes entries are sorted by ProcResIdx.
1189 llvm::sort(WriteProcResources, LessWriteProcResources());
1191 SCDesc.NumWriteProcResEntries = WriteProcResources.size();
1192 std::vector<MCWriteProcResEntry>::iterator WPRPos =
1193 std::search(SchedTables.WriteProcResources.begin(),
1194 SchedTables.WriteProcResources.end(),
1195 WriteProcResources.begin(), WriteProcResources.end());
1196 if (WPRPos != SchedTables.WriteProcResources.end())
1197 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
1198 else {
1199 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();
1200 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),
1201 WriteProcResources.end());
1203 // Latency entries must remain in operand order.
1204 SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
1205 std::vector<MCWriteLatencyEntry>::iterator WLPos =
1206 std::search(SchedTables.WriteLatencies.begin(),
1207 SchedTables.WriteLatencies.end(),
1208 WriteLatencies.begin(), WriteLatencies.end());
1209 if (WLPos != SchedTables.WriteLatencies.end()) {
1210 unsigned idx = WLPos - SchedTables.WriteLatencies.begin();
1211 SCDesc.WriteLatencyIdx = idx;
1212 for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)
1213 if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==
1214 std::string::npos) {
1215 SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];
1218 else {
1219 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
1220 SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(),
1221 WriteLatencies.begin(),
1222 WriteLatencies.end());
1223 SchedTables.WriterNames.insert(SchedTables.WriterNames.end(),
1224 WriterNames.begin(), WriterNames.end());
1226 // ReadAdvanceEntries must remain in operand order.
1227 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
1228 std::vector<MCReadAdvanceEntry>::iterator RAPos =
1229 std::search(SchedTables.ReadAdvanceEntries.begin(),
1230 SchedTables.ReadAdvanceEntries.end(),
1231 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
1232 if (RAPos != SchedTables.ReadAdvanceEntries.end())
1233 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
1234 else {
1235 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
1236 SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(),
1237 ReadAdvanceEntries.end());
1242 // Emit SchedClass tables for all processors and associated global tables.
1243 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
1244 raw_ostream &OS) {
1245 // Emit global WriteProcResTable.
1246 OS << "\n// {ProcResourceIdx, Cycles}\n"
1247 << "extern const llvm::MCWriteProcResEntry "
1248 << Target << "WriteProcResTable[] = {\n"
1249 << " { 0, 0}, // Invalid\n";
1250 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
1251 WPRIdx != WPREnd; ++WPRIdx) {
1252 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
1253 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
1254 << format("%2d", WPREntry.Cycles) << "}";
1255 if (WPRIdx + 1 < WPREnd)
1256 OS << ',';
1257 OS << " // #" << WPRIdx << '\n';
1259 OS << "}; // " << Target << "WriteProcResTable\n";
1261 // Emit global WriteLatencyTable.
1262 OS << "\n// {Cycles, WriteResourceID}\n"
1263 << "extern const llvm::MCWriteLatencyEntry "
1264 << Target << "WriteLatencyTable[] = {\n"
1265 << " { 0, 0}, // Invalid\n";
1266 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
1267 WLIdx != WLEnd; ++WLIdx) {
1268 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
1269 OS << " {" << format("%2d", WLEntry.Cycles) << ", "
1270 << format("%2d", WLEntry.WriteResourceID) << "}";
1271 if (WLIdx + 1 < WLEnd)
1272 OS << ',';
1273 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
1275 OS << "}; // " << Target << "WriteLatencyTable\n";
1277 // Emit global ReadAdvanceTable.
1278 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
1279 << "extern const llvm::MCReadAdvanceEntry "
1280 << Target << "ReadAdvanceTable[] = {\n"
1281 << " {0, 0, 0}, // Invalid\n";
1282 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
1283 RAIdx != RAEnd; ++RAIdx) {
1284 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
1285 OS << " {" << RAEntry.UseIdx << ", "
1286 << format("%2d", RAEntry.WriteResourceID) << ", "
1287 << format("%2d", RAEntry.Cycles) << "}";
1288 if (RAIdx + 1 < RAEnd)
1289 OS << ',';
1290 OS << " // #" << RAIdx << '\n';
1292 OS << "}; // " << Target << "ReadAdvanceTable\n";
1294 // Emit a SchedClass table for each processor.
1295 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1296 PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1297 if (!PI->hasInstrSchedModel())
1298 continue;
1300 std::vector<MCSchedClassDesc> &SCTab =
1301 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
1303 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup,"
1304 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
1305 OS << "static const llvm::MCSchedClassDesc "
1306 << PI->ModelName << "SchedClasses[] = {\n";
1308 // The first class is always invalid. We no way to distinguish it except by
1309 // name and position.
1310 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
1311 && "invalid class not first");
1312 OS << " {DBGFIELD(\"InvalidSchedClass\") "
1313 << MCSchedClassDesc::InvalidNumMicroOps
1314 << ", false, false, 0, 0, 0, 0, 0, 0},\n";
1316 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
1317 MCSchedClassDesc &MCDesc = SCTab[SCIdx];
1318 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
1319 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";
1320 if (SchedClass.Name.size() < 18)
1321 OS.indent(18 - SchedClass.Name.size());
1322 OS << MCDesc.NumMicroOps
1323 << ", " << ( MCDesc.BeginGroup ? "true" : "false" )
1324 << ", " << ( MCDesc.EndGroup ? "true" : "false" )
1325 << ", " << format("%2d", MCDesc.WriteProcResIdx)
1326 << ", " << MCDesc.NumWriteProcResEntries
1327 << ", " << format("%2d", MCDesc.WriteLatencyIdx)
1328 << ", " << MCDesc.NumWriteLatencyEntries
1329 << ", " << format("%2d", MCDesc.ReadAdvanceIdx)
1330 << ", " << MCDesc.NumReadAdvanceEntries
1331 << "}, // #" << SCIdx << '\n';
1333 OS << "}; // " << PI->ModelName << "SchedClasses\n";
1337 void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
1338 // For each processor model.
1339 for (const CodeGenProcModel &PM : SchedModels.procModels()) {
1340 // Emit extra processor info if available.
1341 if (PM.hasExtraProcessorInfo())
1342 EmitExtraProcessorInfo(PM, OS);
1343 // Emit processor resource table.
1344 if (PM.hasInstrSchedModel())
1345 EmitProcessorResources(PM, OS);
1346 else if(!PM.ProcResourceDefs.empty())
1347 PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines "
1348 "ProcResources without defining WriteRes SchedWriteRes");
1350 // Begin processor itinerary properties
1351 OS << "\n";
1352 OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n";
1353 EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ',');
1354 EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ',');
1355 EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ',');
1356 EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ',');
1357 EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ',');
1358 EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');
1360 bool PostRAScheduler =
1361 (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
1363 OS << " " << (PostRAScheduler ? "true" : "false") << ", // "
1364 << "PostRAScheduler\n";
1366 bool CompleteModel =
1367 (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
1369 OS << " " << (CompleteModel ? "true" : "false") << ", // "
1370 << "CompleteModel\n";
1372 OS << " " << PM.Index << ", // Processor ID\n";
1373 if (PM.hasInstrSchedModel())
1374 OS << " " << PM.ModelName << "ProcResources" << ",\n"
1375 << " " << PM.ModelName << "SchedClasses" << ",\n"
1376 << " " << PM.ProcResourceDefs.size()+1 << ",\n"
1377 << " " << (SchedModels.schedClassEnd()
1378 - SchedModels.schedClassBegin()) << ",\n";
1379 else
1380 OS << " nullptr, nullptr, 0, 0,"
1381 << " // No instruction-level machine model.\n";
1382 if (PM.hasItineraries())
1383 OS << " " << PM.ItinsDef->getName() << ",\n";
1384 else
1385 OS << " nullptr, // No Itinerary\n";
1386 if (PM.hasExtraProcessorInfo())
1387 OS << " &" << PM.ModelName << "ExtraInfo,\n";
1388 else
1389 OS << " nullptr // No extra processor descriptor\n";
1390 OS << "};\n";
1395 // EmitSchedModel - Emits all scheduling model tables, folding common patterns.
1397 void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
1398 OS << "#ifdef DBGFIELD\n"
1399 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n"
1400 << "#endif\n"
1401 << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n"
1402 << "#define DBGFIELD(x) x,\n"
1403 << "#else\n"
1404 << "#define DBGFIELD(x)\n"
1405 << "#endif\n";
1407 if (SchedModels.hasItineraries()) {
1408 std::vector<std::vector<InstrItinerary>> ProcItinLists;
1409 // Emit the stage data
1410 EmitStageAndOperandCycleData(OS, ProcItinLists);
1411 EmitItineraries(OS, ProcItinLists);
1413 OS << "\n// ===============================================================\n"
1414 << "// Data tables for the new per-operand machine model.\n";
1416 SchedClassTables SchedTables;
1417 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
1418 GenSchedClassTables(ProcModel, SchedTables);
1420 EmitSchedClassTables(SchedTables, OS);
1422 OS << "\n#undef DBGFIELD\n";
1424 // Emit the processor machine model
1425 EmitProcessorModels(OS);
1428 static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {
1429 std::string Buffer;
1430 raw_string_ostream Stream(Buffer);
1432 // Collect all the PredicateProlog records and print them to the output
1433 // stream.
1434 std::vector<Record *> Prologs =
1435 Records.getAllDerivedDefinitions("PredicateProlog");
1436 llvm::sort(Prologs, LessRecord());
1437 for (Record *P : Prologs)
1438 Stream << P->getValueAsString("Code") << '\n';
1440 Stream.flush();
1441 OS << Buffer;
1444 static void emitPredicates(const CodeGenSchedTransition &T,
1445 const CodeGenSchedClass &SC, PredicateExpander &PE,
1446 raw_ostream &OS) {
1447 std::string Buffer;
1448 raw_string_ostream SS(Buffer);
1450 auto IsTruePredicate = [](const Record *Rec) {
1451 return Rec->isSubClassOf("MCSchedPredicate") &&
1452 Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
1455 // If not all predicates are MCTrue, then we need an if-stmt.
1456 unsigned NumNonTruePreds =
1457 T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate);
1459 SS.indent(PE.getIndentLevel() * 2);
1461 if (NumNonTruePreds) {
1462 bool FirstNonTruePredicate = true;
1463 SS << "if (";
1465 PE.setIndentLevel(PE.getIndentLevel() + 2);
1467 for (const Record *Rec : T.PredTerm) {
1468 // Skip predicates that evaluate to "true".
1469 if (IsTruePredicate(Rec))
1470 continue;
1472 if (FirstNonTruePredicate) {
1473 FirstNonTruePredicate = false;
1474 } else {
1475 SS << "\n";
1476 SS.indent(PE.getIndentLevel() * 2);
1477 SS << "&& ";
1480 if (Rec->isSubClassOf("MCSchedPredicate")) {
1481 PE.expandPredicate(SS, Rec->getValueAsDef("Pred"));
1482 continue;
1485 // Expand this legacy predicate and wrap it around braces if there is more
1486 // than one predicate to expand.
1487 SS << ((NumNonTruePreds > 1) ? "(" : "")
1488 << Rec->getValueAsString("Predicate")
1489 << ((NumNonTruePreds > 1) ? ")" : "");
1492 SS << ")\n"; // end of if-stmt
1493 PE.decreaseIndentLevel();
1494 SS.indent(PE.getIndentLevel() * 2);
1495 PE.decreaseIndentLevel();
1498 SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n';
1499 SS.flush();
1500 OS << Buffer;
1503 // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate
1504 // epilogue code for the auto-generated helper.
1505 void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) {
1506 if (ShouldReturnZero) {
1507 OS << " // Don't know how to resolve this scheduling class.\n"
1508 << " return 0;\n";
1509 return;
1512 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n";
1515 bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
1516 return all_of(T.PredTerm, [](const Record *Rec) {
1517 return Rec->isSubClassOf("MCSchedPredicate");
1521 void collectVariantClasses(const CodeGenSchedModels &SchedModels,
1522 IdxVec &VariantClasses,
1523 bool OnlyExpandMCInstPredicates) {
1524 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
1525 // Ignore non-variant scheduling classes.
1526 if (SC.Transitions.empty())
1527 continue;
1529 if (OnlyExpandMCInstPredicates) {
1530 // Ignore this variant scheduling class no transitions use any meaningful
1531 // MCSchedPredicate definitions.
1532 if (!any_of(SC.Transitions, [](const CodeGenSchedTransition &T) {
1533 return hasMCSchedPredicates(T);
1535 continue;
1538 VariantClasses.push_back(SC.Index);
1542 void collectProcessorIndices(const CodeGenSchedClass &SC, IdxVec &ProcIndices) {
1543 // A variant scheduling class may define transitions for multiple
1544 // processors. This function identifies wich processors are associated with
1545 // transition rules specified by variant class `SC`.
1546 for (const CodeGenSchedTransition &T : SC.Transitions) {
1547 IdxVec PI;
1548 std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(),
1549 ProcIndices.begin(), ProcIndices.end(),
1550 std::back_inserter(PI));
1551 ProcIndices.swap(PI);
1555 void SubtargetEmitter::emitSchedModelHelpersImpl(
1556 raw_ostream &OS, bool OnlyExpandMCInstPredicates) {
1557 IdxVec VariantClasses;
1558 collectVariantClasses(SchedModels, VariantClasses,
1559 OnlyExpandMCInstPredicates);
1561 if (VariantClasses.empty()) {
1562 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
1563 return;
1566 // Construct a switch statement where the condition is a check on the
1567 // scheduling class identifier. There is a `case` for every variant class
1568 // defined by the processor models of this target.
1569 // Each `case` implements a number of rules to resolve (i.e. to transition from)
1570 // a variant scheduling class to another scheduling class. Rules are
1571 // described by instances of CodeGenSchedTransition. Note that transitions may
1572 // not be valid for all processors.
1573 OS << " switch (SchedClass) {\n";
1574 for (unsigned VC : VariantClasses) {
1575 IdxVec ProcIndices;
1576 const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC);
1577 collectProcessorIndices(SC, ProcIndices);
1579 OS << " case " << VC << ": // " << SC.Name << '\n';
1581 PredicateExpander PE(Target);
1582 PE.setByRef(false);
1583 PE.setExpandForMC(OnlyExpandMCInstPredicates);
1584 for (unsigned PI : ProcIndices) {
1585 OS << " ";
1587 // Emit a guard on the processor ID.
1588 if (PI != 0) {
1589 OS << (OnlyExpandMCInstPredicates
1590 ? "if (CPUID == "
1591 : "if (SchedModel->getProcessorID() == ");
1592 OS << PI << ") ";
1593 OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n';
1596 // Now emit transitions associated with processor PI.
1597 for (const CodeGenSchedTransition &T : SC.Transitions) {
1598 if (PI != 0 && !count(T.ProcIndices, PI))
1599 continue;
1601 // Emit only transitions based on MCSchedPredicate, if it's the case.
1602 // At least the transition specified by NoSchedPred is emitted,
1603 // which becomes the default transition for those variants otherwise
1604 // not based on MCSchedPredicate.
1605 // FIXME: preferably, llvm-mca should instead assume a reasonable
1606 // default when a variant transition is not based on MCSchedPredicate
1607 // for a given processor.
1608 if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))
1609 continue;
1611 PE.setIndentLevel(3);
1612 emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);
1615 OS << " }\n";
1617 if (PI == 0)
1618 break;
1621 if (SC.isInferred())
1622 OS << " return " << SC.Index << ";\n";
1623 OS << " break;\n";
1626 OS << " };\n";
1628 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
1631 void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
1632 raw_ostream &OS) {
1633 OS << "unsigned " << ClassName
1634 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"
1635 << " const TargetSchedModel *SchedModel) const {\n";
1637 // Emit the predicate prolog code.
1638 emitPredicateProlog(Records, OS);
1640 // Emit target predicates.
1641 emitSchedModelHelpersImpl(OS);
1643 OS << "} // " << ClassName << "::resolveSchedClass\n\n";
1645 OS << "unsigned " << ClassName
1646 << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"
1647 << " unsigned CPUID) const {\n"
1648 << " return " << Target << "_MC"
1649 << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n"
1650 << "} // " << ClassName << "::resolveVariantSchedClass\n\n";
1652 STIPredicateExpander PE(Target);
1653 PE.setClassPrefix(ClassName);
1654 PE.setExpandDefinition(true);
1655 PE.setByRef(false);
1656 PE.setIndentLevel(0);
1658 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1659 PE.expandSTIPredicate(OS, Fn);
1662 void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
1663 raw_ostream &OS) {
1664 const CodeGenHwModes &CGH = TGT.getHwModes();
1665 assert(CGH.getNumModeIds() > 0);
1666 if (CGH.getNumModeIds() == 1)
1667 return;
1669 OS << "unsigned " << ClassName << "::getHwMode() const {\n";
1670 for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
1671 const HwMode &HM = CGH.getMode(M);
1672 OS << " if (checkFeatures(\"" << HM.Features
1673 << "\")) return " << M << ";\n";
1675 OS << " return 0;\n}\n";
1679 // ParseFeaturesFunction - Produces a subtarget specific function for parsing
1680 // the subtarget features string.
1682 void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
1683 unsigned NumFeatures,
1684 unsigned NumProcs) {
1685 std::vector<Record*> Features =
1686 Records.getAllDerivedDefinitions("SubtargetFeature");
1687 llvm::sort(Features, LessRecord());
1689 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
1690 << "// subtarget options.\n"
1691 << "void llvm::";
1692 OS << Target;
1693 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n"
1694 << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
1695 << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n";
1697 if (Features.empty()) {
1698 OS << "}\n";
1699 return;
1702 OS << " InitMCProcessorInfo(CPU, FS);\n"
1703 << " const FeatureBitset& Bits = getFeatureBits();\n";
1705 for (Record *R : Features) {
1706 // Next record
1707 StringRef Instance = R->getName();
1708 StringRef Value = R->getValueAsString("Value");
1709 StringRef Attribute = R->getValueAsString("Attribute");
1711 if (Value=="true" || Value=="false")
1712 OS << " if (Bits[" << Target << "::"
1713 << Instance << "]) "
1714 << Attribute << " = " << Value << ";\n";
1715 else
1716 OS << " if (Bits[" << Target << "::"
1717 << Instance << "] && "
1718 << Attribute << " < " << Value << ") "
1719 << Attribute << " = " << Value << ";\n";
1722 OS << "}\n";
1725 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
1726 OS << "namespace " << Target << "_MC {\n"
1727 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
1728 << " const MCInst *MI, unsigned CPUID) {\n";
1729 emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
1730 OS << "}\n";
1731 OS << "} // end namespace " << Target << "_MC\n\n";
1733 OS << "struct " << Target
1734 << "GenMCSubtargetInfo : public MCSubtargetInfo {\n";
1735 OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT, \n"
1736 << " StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF,\n"
1737 << " ArrayRef<SubtargetSubTypeKV> PD,\n"
1738 << " const MCWriteProcResEntry *WPR,\n"
1739 << " const MCWriteLatencyEntry *WL,\n"
1740 << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n"
1741 << " const unsigned *OC, const unsigned *FP) :\n"
1742 << " MCSubtargetInfo(TT, CPU, FS, PF, PD,\n"
1743 << " WPR, WL, RA, IS, OC, FP) { }\n\n"
1744 << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
1745 << " const MCInst *MI, unsigned CPUID) const override {\n"
1746 << " return " << Target << "_MC"
1747 << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n";
1748 OS << " }\n";
1749 if (TGT.getHwModes().getNumModeIds() > 1)
1750 OS << " unsigned getHwMode() const override;\n";
1751 OS << "};\n";
1752 EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
1755 void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) {
1756 OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n";
1757 OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
1759 STIPredicateExpander PE(Target);
1760 PE.setExpandForMC(true);
1761 PE.setByRef(true);
1762 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1763 PE.expandSTIPredicate(OS, Fn);
1765 OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
1767 OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n";
1768 OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
1770 std::string ClassPrefix = Target + "MCInstrAnalysis";
1771 PE.setExpandDefinition(true);
1772 PE.setClassPrefix(ClassPrefix);
1773 PE.setIndentLevel(0);
1774 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1775 PE.expandSTIPredicate(OS, Fn);
1777 OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
1781 // SubtargetEmitter::run - Main subtarget enumeration emitter.
1783 void SubtargetEmitter::run(raw_ostream &OS) {
1784 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
1786 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
1787 OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";
1789 DenseMap<Record *, unsigned> FeatureMap;
1791 OS << "namespace llvm {\n";
1792 Enumeration(OS, FeatureMap);
1793 OS << "} // end namespace llvm\n\n";
1794 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
1796 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
1797 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";
1799 OS << "namespace llvm {\n";
1800 #if 0
1801 OS << "namespace {\n";
1802 #endif
1803 unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap);
1804 OS << "\n";
1805 EmitSchedModel(OS);
1806 OS << "\n";
1807 unsigned NumProcs = CPUKeyValues(OS, FeatureMap);
1808 OS << "\n";
1809 #if 0
1810 OS << "} // end anonymous namespace\n\n";
1811 #endif
1813 // MCInstrInfo initialization routine.
1814 emitGenMCSubtargetInfo(OS);
1816 OS << "\nstatic inline MCSubtargetInfo *create" << Target
1817 << "MCSubtargetInfoImpl("
1818 << "const Triple &TT, StringRef CPU, StringRef FS) {\n";
1819 OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, ";
1820 if (NumFeatures)
1821 OS << Target << "FeatureKV, ";
1822 else
1823 OS << "None, ";
1824 if (NumProcs)
1825 OS << Target << "SubTypeKV, ";
1826 else
1827 OS << "None, ";
1828 OS << '\n'; OS.indent(22);
1829 OS << Target << "WriteProcResTable, "
1830 << Target << "WriteLatencyTable, "
1831 << Target << "ReadAdvanceTable, ";
1832 OS << '\n'; OS.indent(22);
1833 if (SchedModels.hasItineraries()) {
1834 OS << Target << "Stages, "
1835 << Target << "OperandCycles, "
1836 << Target << "ForwardingPaths";
1837 } else
1838 OS << "nullptr, nullptr, nullptr";
1839 OS << ");\n}\n\n";
1841 OS << "} // end namespace llvm\n\n";
1843 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
1845 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
1846 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";
1848 OS << "#include \"llvm/Support/Debug.h\"\n";
1849 OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";
1850 ParseFeaturesFunction(OS, NumFeatures, NumProcs);
1852 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
1854 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
1855 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
1856 OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";
1858 std::string ClassName = Target + "GenSubtargetInfo";
1859 OS << "namespace llvm {\n";
1860 OS << "class DFAPacketizer;\n";
1861 OS << "namespace " << Target << "_MC {\n"
1862 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
1863 << " const MCInst *MI, unsigned CPUID);\n"
1864 << "} // end namespace " << Target << "_MC\n\n";
1865 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
1866 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
1867 << "StringRef FS);\n"
1868 << "public:\n"
1869 << " unsigned resolveSchedClass(unsigned SchedClass, "
1870 << " const MachineInstr *DefMI,"
1871 << " const TargetSchedModel *SchedModel) const override;\n"
1872 << " unsigned resolveVariantSchedClass(unsigned SchedClass,"
1873 << " const MCInst *MI, unsigned CPUID) const override;\n"
1874 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
1875 << " const;\n";
1876 if (TGT.getHwModes().getNumModeIds() > 1)
1877 OS << " unsigned getHwMode() const override;\n";
1879 STIPredicateExpander PE(Target);
1880 PE.setByRef(false);
1881 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1882 PE.expandSTIPredicate(OS, Fn);
1884 OS << "};\n"
1885 << "} // end namespace llvm\n\n";
1887 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
1889 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
1890 OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";
1892 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
1893 OS << "namespace llvm {\n";
1894 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
1895 OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
1896 OS << "extern const llvm::MCWriteProcResEntry "
1897 << Target << "WriteProcResTable[];\n";
1898 OS << "extern const llvm::MCWriteLatencyEntry "
1899 << Target << "WriteLatencyTable[];\n";
1900 OS << "extern const llvm::MCReadAdvanceEntry "
1901 << Target << "ReadAdvanceTable[];\n";
1903 if (SchedModels.hasItineraries()) {
1904 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
1905 OS << "extern const unsigned " << Target << "OperandCycles[];\n";
1906 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
1909 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
1910 << "StringRef FS)\n"
1911 << " : TargetSubtargetInfo(TT, CPU, FS, ";
1912 if (NumFeatures)
1913 OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
1914 else
1915 OS << "None, ";
1916 if (NumProcs)
1917 OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
1918 else
1919 OS << "None, ";
1920 OS << '\n'; OS.indent(24);
1921 OS << Target << "WriteProcResTable, "
1922 << Target << "WriteLatencyTable, "
1923 << Target << "ReadAdvanceTable, ";
1924 OS << '\n'; OS.indent(24);
1925 if (SchedModels.hasItineraries()) {
1926 OS << Target << "Stages, "
1927 << Target << "OperandCycles, "
1928 << Target << "ForwardingPaths";
1929 } else
1930 OS << "nullptr, nullptr, nullptr";
1931 OS << ") {}\n\n";
1933 EmitSchedModelHelpers(ClassName, OS);
1934 EmitHwModeCheck(ClassName, OS);
1936 OS << "} // end namespace llvm\n\n";
1938 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
1940 EmitMCInstrAnalysisPredicateFunctions(OS);
1943 namespace llvm {
1945 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
1946 CodeGenTarget CGTarget(RK);
1947 SubtargetEmitter(RK, CGTarget).run(OS);
1950 } // end namespace llvm