[InstCombine] Signed saturation patterns
[llvm-complete.git] / utils / TableGen / SubtargetEmitter.cpp
blob9b094adb7d5ced321bfcc2c3b8fecb8dac987c64
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');
1060 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1063 // Sum resources across all operand writes.
1064 std::vector<MCWriteProcResEntry> WriteProcResources;
1065 std::vector<MCWriteLatencyEntry> WriteLatencies;
1066 std::vector<std::string> WriterNames;
1067 std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
1068 for (unsigned W : Writes) {
1069 IdxVec WriteSeq;
1070 SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false,
1071 ProcModel);
1073 // For each operand, create a latency entry.
1074 MCWriteLatencyEntry WLEntry;
1075 WLEntry.Cycles = 0;
1076 unsigned WriteID = WriteSeq.back();
1077 WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
1078 // If this Write is not referenced by a ReadAdvance, don't distinguish it
1079 // from other WriteLatency entries.
1080 if (!SchedModels.hasReadOfWrite(
1081 SchedModels.getSchedWrite(WriteID).TheDef)) {
1082 WriteID = 0;
1084 WLEntry.WriteResourceID = WriteID;
1086 for (unsigned WS : WriteSeq) {
1088 Record *WriteRes =
1089 FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
1091 // Mark the parent class as invalid for unsupported write types.
1092 if (WriteRes->getValueAsBit("Unsupported")) {
1093 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1094 break;
1096 WLEntry.Cycles += WriteRes->getValueAsInt("Latency");
1097 SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");
1098 SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");
1099 SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");
1100 SCDesc.BeginGroup |= WriteRes->getValueAsBit("SingleIssue");
1101 SCDesc.EndGroup |= WriteRes->getValueAsBit("SingleIssue");
1103 // Create an entry for each ProcResource listed in WriteRes.
1104 RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
1105 std::vector<int64_t> Cycles =
1106 WriteRes->getValueAsListOfInts("ResourceCycles");
1108 if (Cycles.empty()) {
1109 // If ResourceCycles is not provided, default to one cycle per
1110 // resource.
1111 Cycles.resize(PRVec.size(), 1);
1112 } else if (Cycles.size() != PRVec.size()) {
1113 // If ResourceCycles is provided, check consistency.
1114 PrintFatalError(
1115 WriteRes->getLoc(),
1116 Twine("Inconsistent resource cycles: !size(ResourceCycles) != "
1117 "!size(ProcResources): ")
1118 .concat(Twine(PRVec.size()))
1119 .concat(" vs ")
1120 .concat(Twine(Cycles.size())));
1123 ExpandProcResources(PRVec, Cycles, ProcModel);
1125 for (unsigned PRIdx = 0, PREnd = PRVec.size();
1126 PRIdx != PREnd; ++PRIdx) {
1127 MCWriteProcResEntry WPREntry;
1128 WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
1129 assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
1130 WPREntry.Cycles = Cycles[PRIdx];
1131 // If this resource is already used in this sequence, add the current
1132 // entry's cycles so that the same resource appears to be used
1133 // serially, rather than multiple parallel uses. This is important for
1134 // in-order machine where the resource consumption is a hazard.
1135 unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
1136 for( ; WPRIdx != WPREnd; ++WPRIdx) {
1137 if (WriteProcResources[WPRIdx].ProcResourceIdx
1138 == WPREntry.ProcResourceIdx) {
1139 WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
1140 break;
1143 if (WPRIdx == WPREnd)
1144 WriteProcResources.push_back(WPREntry);
1147 WriteLatencies.push_back(WLEntry);
1149 // Create an entry for each operand Read in this SchedClass.
1150 // Entries must be sorted first by UseIdx then by WriteResourceID.
1151 for (unsigned UseIdx = 0, EndIdx = Reads.size();
1152 UseIdx != EndIdx; ++UseIdx) {
1153 Record *ReadAdvance =
1154 FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
1155 if (!ReadAdvance)
1156 continue;
1158 // Mark the parent class as invalid for unsupported write types.
1159 if (ReadAdvance->getValueAsBit("Unsupported")) {
1160 SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1161 break;
1163 RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");
1164 IdxVec WriteIDs;
1165 if (ValidWrites.empty())
1166 WriteIDs.push_back(0);
1167 else {
1168 for (Record *VW : ValidWrites) {
1169 WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false));
1172 llvm::sort(WriteIDs);
1173 for(unsigned W : WriteIDs) {
1174 MCReadAdvanceEntry RAEntry;
1175 RAEntry.UseIdx = UseIdx;
1176 RAEntry.WriteResourceID = W;
1177 RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
1178 ReadAdvanceEntries.push_back(RAEntry);
1181 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
1182 WriteProcResources.clear();
1183 WriteLatencies.clear();
1184 ReadAdvanceEntries.clear();
1186 // Add the information for this SchedClass to the global tables using basic
1187 // compression.
1189 // WritePrecRes entries are sorted by ProcResIdx.
1190 llvm::sort(WriteProcResources, LessWriteProcResources());
1192 SCDesc.NumWriteProcResEntries = WriteProcResources.size();
1193 std::vector<MCWriteProcResEntry>::iterator WPRPos =
1194 std::search(SchedTables.WriteProcResources.begin(),
1195 SchedTables.WriteProcResources.end(),
1196 WriteProcResources.begin(), WriteProcResources.end());
1197 if (WPRPos != SchedTables.WriteProcResources.end())
1198 SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
1199 else {
1200 SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();
1201 SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),
1202 WriteProcResources.end());
1204 // Latency entries must remain in operand order.
1205 SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
1206 std::vector<MCWriteLatencyEntry>::iterator WLPos =
1207 std::search(SchedTables.WriteLatencies.begin(),
1208 SchedTables.WriteLatencies.end(),
1209 WriteLatencies.begin(), WriteLatencies.end());
1210 if (WLPos != SchedTables.WriteLatencies.end()) {
1211 unsigned idx = WLPos - SchedTables.WriteLatencies.begin();
1212 SCDesc.WriteLatencyIdx = idx;
1213 for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)
1214 if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==
1215 std::string::npos) {
1216 SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];
1219 else {
1220 SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
1221 SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(),
1222 WriteLatencies.begin(),
1223 WriteLatencies.end());
1224 SchedTables.WriterNames.insert(SchedTables.WriterNames.end(),
1225 WriterNames.begin(), WriterNames.end());
1227 // ReadAdvanceEntries must remain in operand order.
1228 SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
1229 std::vector<MCReadAdvanceEntry>::iterator RAPos =
1230 std::search(SchedTables.ReadAdvanceEntries.begin(),
1231 SchedTables.ReadAdvanceEntries.end(),
1232 ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
1233 if (RAPos != SchedTables.ReadAdvanceEntries.end())
1234 SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
1235 else {
1236 SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
1237 SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(),
1238 ReadAdvanceEntries.end());
1243 // Emit SchedClass tables for all processors and associated global tables.
1244 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
1245 raw_ostream &OS) {
1246 // Emit global WriteProcResTable.
1247 OS << "\n// {ProcResourceIdx, Cycles}\n"
1248 << "extern const llvm::MCWriteProcResEntry "
1249 << Target << "WriteProcResTable[] = {\n"
1250 << " { 0, 0}, // Invalid\n";
1251 for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
1252 WPRIdx != WPREnd; ++WPRIdx) {
1253 MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
1254 OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
1255 << format("%2d", WPREntry.Cycles) << "}";
1256 if (WPRIdx + 1 < WPREnd)
1257 OS << ',';
1258 OS << " // #" << WPRIdx << '\n';
1260 OS << "}; // " << Target << "WriteProcResTable\n";
1262 // Emit global WriteLatencyTable.
1263 OS << "\n// {Cycles, WriteResourceID}\n"
1264 << "extern const llvm::MCWriteLatencyEntry "
1265 << Target << "WriteLatencyTable[] = {\n"
1266 << " { 0, 0}, // Invalid\n";
1267 for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
1268 WLIdx != WLEnd; ++WLIdx) {
1269 MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
1270 OS << " {" << format("%2d", WLEntry.Cycles) << ", "
1271 << format("%2d", WLEntry.WriteResourceID) << "}";
1272 if (WLIdx + 1 < WLEnd)
1273 OS << ',';
1274 OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
1276 OS << "}; // " << Target << "WriteLatencyTable\n";
1278 // Emit global ReadAdvanceTable.
1279 OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
1280 << "extern const llvm::MCReadAdvanceEntry "
1281 << Target << "ReadAdvanceTable[] = {\n"
1282 << " {0, 0, 0}, // Invalid\n";
1283 for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
1284 RAIdx != RAEnd; ++RAIdx) {
1285 MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
1286 OS << " {" << RAEntry.UseIdx << ", "
1287 << format("%2d", RAEntry.WriteResourceID) << ", "
1288 << format("%2d", RAEntry.Cycles) << "}";
1289 if (RAIdx + 1 < RAEnd)
1290 OS << ',';
1291 OS << " // #" << RAIdx << '\n';
1293 OS << "}; // " << Target << "ReadAdvanceTable\n";
1295 // Emit a SchedClass table for each processor.
1296 for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1297 PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1298 if (!PI->hasInstrSchedModel())
1299 continue;
1301 std::vector<MCSchedClassDesc> &SCTab =
1302 SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
1304 OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup,"
1305 << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
1306 OS << "static const llvm::MCSchedClassDesc "
1307 << PI->ModelName << "SchedClasses[] = {\n";
1309 // The first class is always invalid. We no way to distinguish it except by
1310 // name and position.
1311 assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
1312 && "invalid class not first");
1313 OS << " {DBGFIELD(\"InvalidSchedClass\") "
1314 << MCSchedClassDesc::InvalidNumMicroOps
1315 << ", false, false, 0, 0, 0, 0, 0, 0},\n";
1317 for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
1318 MCSchedClassDesc &MCDesc = SCTab[SCIdx];
1319 const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
1320 OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";
1321 if (SchedClass.Name.size() < 18)
1322 OS.indent(18 - SchedClass.Name.size());
1323 OS << MCDesc.NumMicroOps
1324 << ", " << ( MCDesc.BeginGroup ? "true" : "false" )
1325 << ", " << ( MCDesc.EndGroup ? "true" : "false" )
1326 << ", " << format("%2d", MCDesc.WriteProcResIdx)
1327 << ", " << MCDesc.NumWriteProcResEntries
1328 << ", " << format("%2d", MCDesc.WriteLatencyIdx)
1329 << ", " << MCDesc.NumWriteLatencyEntries
1330 << ", " << format("%2d", MCDesc.ReadAdvanceIdx)
1331 << ", " << MCDesc.NumReadAdvanceEntries
1332 << "}, // #" << SCIdx << '\n';
1334 OS << "}; // " << PI->ModelName << "SchedClasses\n";
1338 void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
1339 // For each processor model.
1340 for (const CodeGenProcModel &PM : SchedModels.procModels()) {
1341 // Emit extra processor info if available.
1342 if (PM.hasExtraProcessorInfo())
1343 EmitExtraProcessorInfo(PM, OS);
1344 // Emit processor resource table.
1345 if (PM.hasInstrSchedModel())
1346 EmitProcessorResources(PM, OS);
1347 else if(!PM.ProcResourceDefs.empty())
1348 PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines "
1349 "ProcResources without defining WriteRes SchedWriteRes");
1351 // Begin processor itinerary properties
1352 OS << "\n";
1353 OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n";
1354 EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ',');
1355 EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ',');
1356 EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ',');
1357 EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ',');
1358 EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ',');
1359 EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');
1361 bool PostRAScheduler =
1362 (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
1364 OS << " " << (PostRAScheduler ? "true" : "false") << ", // "
1365 << "PostRAScheduler\n";
1367 bool CompleteModel =
1368 (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
1370 OS << " " << (CompleteModel ? "true" : "false") << ", // "
1371 << "CompleteModel\n";
1373 OS << " " << PM.Index << ", // Processor ID\n";
1374 if (PM.hasInstrSchedModel())
1375 OS << " " << PM.ModelName << "ProcResources" << ",\n"
1376 << " " << PM.ModelName << "SchedClasses" << ",\n"
1377 << " " << PM.ProcResourceDefs.size()+1 << ",\n"
1378 << " " << (SchedModels.schedClassEnd()
1379 - SchedModels.schedClassBegin()) << ",\n";
1380 else
1381 OS << " nullptr, nullptr, 0, 0,"
1382 << " // No instruction-level machine model.\n";
1383 if (PM.hasItineraries())
1384 OS << " " << PM.ItinsDef->getName() << ",\n";
1385 else
1386 OS << " nullptr, // No Itinerary\n";
1387 if (PM.hasExtraProcessorInfo())
1388 OS << " &" << PM.ModelName << "ExtraInfo,\n";
1389 else
1390 OS << " nullptr // No extra processor descriptor\n";
1391 OS << "};\n";
1396 // EmitSchedModel - Emits all scheduling model tables, folding common patterns.
1398 void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
1399 OS << "#ifdef DBGFIELD\n"
1400 << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n"
1401 << "#endif\n"
1402 << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n"
1403 << "#define DBGFIELD(x) x,\n"
1404 << "#else\n"
1405 << "#define DBGFIELD(x)\n"
1406 << "#endif\n";
1408 if (SchedModels.hasItineraries()) {
1409 std::vector<std::vector<InstrItinerary>> ProcItinLists;
1410 // Emit the stage data
1411 EmitStageAndOperandCycleData(OS, ProcItinLists);
1412 EmitItineraries(OS, ProcItinLists);
1414 OS << "\n// ===============================================================\n"
1415 << "// Data tables for the new per-operand machine model.\n";
1417 SchedClassTables SchedTables;
1418 for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
1419 GenSchedClassTables(ProcModel, SchedTables);
1421 EmitSchedClassTables(SchedTables, OS);
1423 OS << "\n#undef DBGFIELD\n";
1425 // Emit the processor machine model
1426 EmitProcessorModels(OS);
1429 static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {
1430 std::string Buffer;
1431 raw_string_ostream Stream(Buffer);
1433 // Collect all the PredicateProlog records and print them to the output
1434 // stream.
1435 std::vector<Record *> Prologs =
1436 Records.getAllDerivedDefinitions("PredicateProlog");
1437 llvm::sort(Prologs, LessRecord());
1438 for (Record *P : Prologs)
1439 Stream << P->getValueAsString("Code") << '\n';
1441 Stream.flush();
1442 OS << Buffer;
1445 static void emitPredicates(const CodeGenSchedTransition &T,
1446 const CodeGenSchedClass &SC, PredicateExpander &PE,
1447 raw_ostream &OS) {
1448 std::string Buffer;
1449 raw_string_ostream SS(Buffer);
1451 auto IsTruePredicate = [](const Record *Rec) {
1452 return Rec->isSubClassOf("MCSchedPredicate") &&
1453 Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
1456 // If not all predicates are MCTrue, then we need an if-stmt.
1457 unsigned NumNonTruePreds =
1458 T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate);
1460 SS.indent(PE.getIndentLevel() * 2);
1462 if (NumNonTruePreds) {
1463 bool FirstNonTruePredicate = true;
1464 SS << "if (";
1466 PE.setIndentLevel(PE.getIndentLevel() + 2);
1468 for (const Record *Rec : T.PredTerm) {
1469 // Skip predicates that evaluate to "true".
1470 if (IsTruePredicate(Rec))
1471 continue;
1473 if (FirstNonTruePredicate) {
1474 FirstNonTruePredicate = false;
1475 } else {
1476 SS << "\n";
1477 SS.indent(PE.getIndentLevel() * 2);
1478 SS << "&& ";
1481 if (Rec->isSubClassOf("MCSchedPredicate")) {
1482 PE.expandPredicate(SS, Rec->getValueAsDef("Pred"));
1483 continue;
1486 // Expand this legacy predicate and wrap it around braces if there is more
1487 // than one predicate to expand.
1488 SS << ((NumNonTruePreds > 1) ? "(" : "")
1489 << Rec->getValueAsString("Predicate")
1490 << ((NumNonTruePreds > 1) ? ")" : "");
1493 SS << ")\n"; // end of if-stmt
1494 PE.decreaseIndentLevel();
1495 SS.indent(PE.getIndentLevel() * 2);
1496 PE.decreaseIndentLevel();
1499 SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n';
1500 SS.flush();
1501 OS << Buffer;
1504 // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate
1505 // epilogue code for the auto-generated helper.
1506 void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) {
1507 if (ShouldReturnZero) {
1508 OS << " // Don't know how to resolve this scheduling class.\n"
1509 << " return 0;\n";
1510 return;
1513 OS << " report_fatal_error(\"Expected a variant SchedClass\");\n";
1516 bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
1517 return all_of(T.PredTerm, [](const Record *Rec) {
1518 return Rec->isSubClassOf("MCSchedPredicate");
1522 void collectVariantClasses(const CodeGenSchedModels &SchedModels,
1523 IdxVec &VariantClasses,
1524 bool OnlyExpandMCInstPredicates) {
1525 for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
1526 // Ignore non-variant scheduling classes.
1527 if (SC.Transitions.empty())
1528 continue;
1530 if (OnlyExpandMCInstPredicates) {
1531 // Ignore this variant scheduling class no transitions use any meaningful
1532 // MCSchedPredicate definitions.
1533 if (!any_of(SC.Transitions, [](const CodeGenSchedTransition &T) {
1534 return hasMCSchedPredicates(T);
1536 continue;
1539 VariantClasses.push_back(SC.Index);
1543 void collectProcessorIndices(const CodeGenSchedClass &SC, IdxVec &ProcIndices) {
1544 // A variant scheduling class may define transitions for multiple
1545 // processors. This function identifies wich processors are associated with
1546 // transition rules specified by variant class `SC`.
1547 for (const CodeGenSchedTransition &T : SC.Transitions) {
1548 IdxVec PI;
1549 std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(),
1550 ProcIndices.begin(), ProcIndices.end(),
1551 std::back_inserter(PI));
1552 ProcIndices.swap(PI);
1556 void SubtargetEmitter::emitSchedModelHelpersImpl(
1557 raw_ostream &OS, bool OnlyExpandMCInstPredicates) {
1558 IdxVec VariantClasses;
1559 collectVariantClasses(SchedModels, VariantClasses,
1560 OnlyExpandMCInstPredicates);
1562 if (VariantClasses.empty()) {
1563 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
1564 return;
1567 // Construct a switch statement where the condition is a check on the
1568 // scheduling class identifier. There is a `case` for every variant class
1569 // defined by the processor models of this target.
1570 // Each `case` implements a number of rules to resolve (i.e. to transition from)
1571 // a variant scheduling class to another scheduling class. Rules are
1572 // described by instances of CodeGenSchedTransition. Note that transitions may
1573 // not be valid for all processors.
1574 OS << " switch (SchedClass) {\n";
1575 for (unsigned VC : VariantClasses) {
1576 IdxVec ProcIndices;
1577 const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC);
1578 collectProcessorIndices(SC, ProcIndices);
1580 OS << " case " << VC << ": // " << SC.Name << '\n';
1582 PredicateExpander PE(Target);
1583 PE.setByRef(false);
1584 PE.setExpandForMC(OnlyExpandMCInstPredicates);
1585 for (unsigned PI : ProcIndices) {
1586 OS << " ";
1588 // Emit a guard on the processor ID.
1589 if (PI != 0) {
1590 OS << (OnlyExpandMCInstPredicates
1591 ? "if (CPUID == "
1592 : "if (SchedModel->getProcessorID() == ");
1593 OS << PI << ") ";
1594 OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n';
1597 // Now emit transitions associated with processor PI.
1598 for (const CodeGenSchedTransition &T : SC.Transitions) {
1599 if (PI != 0 && !count(T.ProcIndices, PI))
1600 continue;
1602 // Emit only transitions based on MCSchedPredicate, if it's the case.
1603 // At least the transition specified by NoSchedPred is emitted,
1604 // which becomes the default transition for those variants otherwise
1605 // not based on MCSchedPredicate.
1606 // FIXME: preferably, llvm-mca should instead assume a reasonable
1607 // default when a variant transition is not based on MCSchedPredicate
1608 // for a given processor.
1609 if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))
1610 continue;
1612 PE.setIndentLevel(3);
1613 emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);
1616 OS << " }\n";
1618 if (PI == 0)
1619 break;
1622 if (SC.isInferred())
1623 OS << " return " << SC.Index << ";\n";
1624 OS << " break;\n";
1627 OS << " };\n";
1629 emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates);
1632 void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
1633 raw_ostream &OS) {
1634 OS << "unsigned " << ClassName
1635 << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"
1636 << " const TargetSchedModel *SchedModel) const {\n";
1638 // Emit the predicate prolog code.
1639 emitPredicateProlog(Records, OS);
1641 // Emit target predicates.
1642 emitSchedModelHelpersImpl(OS);
1644 OS << "} // " << ClassName << "::resolveSchedClass\n\n";
1646 OS << "unsigned " << ClassName
1647 << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"
1648 << " unsigned CPUID) const {\n"
1649 << " return " << Target << "_MC"
1650 << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n"
1651 << "} // " << ClassName << "::resolveVariantSchedClass\n\n";
1653 STIPredicateExpander PE(Target);
1654 PE.setClassPrefix(ClassName);
1655 PE.setExpandDefinition(true);
1656 PE.setByRef(false);
1657 PE.setIndentLevel(0);
1659 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1660 PE.expandSTIPredicate(OS, Fn);
1663 void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
1664 raw_ostream &OS) {
1665 const CodeGenHwModes &CGH = TGT.getHwModes();
1666 assert(CGH.getNumModeIds() > 0);
1667 if (CGH.getNumModeIds() == 1)
1668 return;
1670 OS << "unsigned " << ClassName << "::getHwMode() const {\n";
1671 for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
1672 const HwMode &HM = CGH.getMode(M);
1673 OS << " if (checkFeatures(\"" << HM.Features
1674 << "\")) return " << M << ";\n";
1676 OS << " return 0;\n}\n";
1680 // ParseFeaturesFunction - Produces a subtarget specific function for parsing
1681 // the subtarget features string.
1683 void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
1684 unsigned NumFeatures,
1685 unsigned NumProcs) {
1686 std::vector<Record*> Features =
1687 Records.getAllDerivedDefinitions("SubtargetFeature");
1688 llvm::sort(Features, LessRecord());
1690 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
1691 << "// subtarget options.\n"
1692 << "void llvm::";
1693 OS << Target;
1694 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n"
1695 << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
1696 << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n";
1698 if (Features.empty()) {
1699 OS << "}\n";
1700 return;
1703 OS << " InitMCProcessorInfo(CPU, FS);\n"
1704 << " const FeatureBitset& Bits = getFeatureBits();\n";
1706 for (Record *R : Features) {
1707 // Next record
1708 StringRef Instance = R->getName();
1709 StringRef Value = R->getValueAsString("Value");
1710 StringRef Attribute = R->getValueAsString("Attribute");
1712 if (Value=="true" || Value=="false")
1713 OS << " if (Bits[" << Target << "::"
1714 << Instance << "]) "
1715 << Attribute << " = " << Value << ";\n";
1716 else
1717 OS << " if (Bits[" << Target << "::"
1718 << Instance << "] && "
1719 << Attribute << " < " << Value << ") "
1720 << Attribute << " = " << Value << ";\n";
1723 OS << "}\n";
1726 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
1727 OS << "namespace " << Target << "_MC {\n"
1728 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
1729 << " const MCInst *MI, unsigned CPUID) {\n";
1730 emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
1731 OS << "}\n";
1732 OS << "} // end namespace " << Target << "_MC\n\n";
1734 OS << "struct " << Target
1735 << "GenMCSubtargetInfo : public MCSubtargetInfo {\n";
1736 OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT, \n"
1737 << " StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF,\n"
1738 << " ArrayRef<SubtargetSubTypeKV> PD,\n"
1739 << " const MCWriteProcResEntry *WPR,\n"
1740 << " const MCWriteLatencyEntry *WL,\n"
1741 << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n"
1742 << " const unsigned *OC, const unsigned *FP) :\n"
1743 << " MCSubtargetInfo(TT, CPU, FS, PF, PD,\n"
1744 << " WPR, WL, RA, IS, OC, FP) { }\n\n"
1745 << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
1746 << " const MCInst *MI, unsigned CPUID) const override {\n"
1747 << " return " << Target << "_MC"
1748 << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n";
1749 OS << " }\n";
1750 if (TGT.getHwModes().getNumModeIds() > 1)
1751 OS << " unsigned getHwMode() const override;\n";
1752 OS << "};\n";
1753 EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
1756 void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) {
1757 OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n";
1758 OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
1760 STIPredicateExpander PE(Target);
1761 PE.setExpandForMC(true);
1762 PE.setByRef(true);
1763 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1764 PE.expandSTIPredicate(OS, Fn);
1766 OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
1768 OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n";
1769 OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
1771 std::string ClassPrefix = Target + "MCInstrAnalysis";
1772 PE.setExpandDefinition(true);
1773 PE.setClassPrefix(ClassPrefix);
1774 PE.setIndentLevel(0);
1775 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1776 PE.expandSTIPredicate(OS, Fn);
1778 OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
1782 // SubtargetEmitter::run - Main subtarget enumeration emitter.
1784 void SubtargetEmitter::run(raw_ostream &OS) {
1785 emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
1787 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
1788 OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";
1790 DenseMap<Record *, unsigned> FeatureMap;
1792 OS << "namespace llvm {\n";
1793 Enumeration(OS, FeatureMap);
1794 OS << "} // end namespace llvm\n\n";
1795 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
1797 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
1798 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";
1800 OS << "namespace llvm {\n";
1801 #if 0
1802 OS << "namespace {\n";
1803 #endif
1804 unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap);
1805 OS << "\n";
1806 EmitSchedModel(OS);
1807 OS << "\n";
1808 unsigned NumProcs = CPUKeyValues(OS, FeatureMap);
1809 OS << "\n";
1810 #if 0
1811 OS << "} // end anonymous namespace\n\n";
1812 #endif
1814 // MCInstrInfo initialization routine.
1815 emitGenMCSubtargetInfo(OS);
1817 OS << "\nstatic inline MCSubtargetInfo *create" << Target
1818 << "MCSubtargetInfoImpl("
1819 << "const Triple &TT, StringRef CPU, StringRef FS) {\n";
1820 OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, ";
1821 if (NumFeatures)
1822 OS << Target << "FeatureKV, ";
1823 else
1824 OS << "None, ";
1825 if (NumProcs)
1826 OS << Target << "SubTypeKV, ";
1827 else
1828 OS << "None, ";
1829 OS << '\n'; OS.indent(22);
1830 OS << Target << "WriteProcResTable, "
1831 << Target << "WriteLatencyTable, "
1832 << Target << "ReadAdvanceTable, ";
1833 OS << '\n'; OS.indent(22);
1834 if (SchedModels.hasItineraries()) {
1835 OS << Target << "Stages, "
1836 << Target << "OperandCycles, "
1837 << Target << "ForwardingPaths";
1838 } else
1839 OS << "nullptr, nullptr, nullptr";
1840 OS << ");\n}\n\n";
1842 OS << "} // end namespace llvm\n\n";
1844 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
1846 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
1847 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";
1849 OS << "#include \"llvm/Support/Debug.h\"\n";
1850 OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";
1851 ParseFeaturesFunction(OS, NumFeatures, NumProcs);
1853 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
1855 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
1856 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
1857 OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";
1859 std::string ClassName = Target + "GenSubtargetInfo";
1860 OS << "namespace llvm {\n";
1861 OS << "class DFAPacketizer;\n";
1862 OS << "namespace " << Target << "_MC {\n"
1863 << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
1864 << " const MCInst *MI, unsigned CPUID);\n"
1865 << "} // end namespace " << Target << "_MC\n\n";
1866 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
1867 << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
1868 << "StringRef FS);\n"
1869 << "public:\n"
1870 << " unsigned resolveSchedClass(unsigned SchedClass, "
1871 << " const MachineInstr *DefMI,"
1872 << " const TargetSchedModel *SchedModel) const override;\n"
1873 << " unsigned resolveVariantSchedClass(unsigned SchedClass,"
1874 << " const MCInst *MI, unsigned CPUID) const override;\n"
1875 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
1876 << " const;\n";
1877 if (TGT.getHwModes().getNumModeIds() > 1)
1878 OS << " unsigned getHwMode() const override;\n";
1880 STIPredicateExpander PE(Target);
1881 PE.setByRef(false);
1882 for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
1883 PE.expandSTIPredicate(OS, Fn);
1885 OS << "};\n"
1886 << "} // end namespace llvm\n\n";
1888 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
1890 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
1891 OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";
1893 OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
1894 OS << "namespace llvm {\n";
1895 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
1896 OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
1897 OS << "extern const llvm::MCWriteProcResEntry "
1898 << Target << "WriteProcResTable[];\n";
1899 OS << "extern const llvm::MCWriteLatencyEntry "
1900 << Target << "WriteLatencyTable[];\n";
1901 OS << "extern const llvm::MCReadAdvanceEntry "
1902 << Target << "ReadAdvanceTable[];\n";
1904 if (SchedModels.hasItineraries()) {
1905 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
1906 OS << "extern const unsigned " << Target << "OperandCycles[];\n";
1907 OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
1910 OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
1911 << "StringRef FS)\n"
1912 << " : TargetSubtargetInfo(TT, CPU, FS, ";
1913 if (NumFeatures)
1914 OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
1915 else
1916 OS << "None, ";
1917 if (NumProcs)
1918 OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
1919 else
1920 OS << "None, ";
1921 OS << '\n'; OS.indent(24);
1922 OS << Target << "WriteProcResTable, "
1923 << Target << "WriteLatencyTable, "
1924 << Target << "ReadAdvanceTable, ";
1925 OS << '\n'; OS.indent(24);
1926 if (SchedModels.hasItineraries()) {
1927 OS << Target << "Stages, "
1928 << Target << "OperandCycles, "
1929 << Target << "ForwardingPaths";
1930 } else
1931 OS << "nullptr, nullptr, nullptr";
1932 OS << ") {}\n\n";
1934 EmitSchedModelHelpers(ClassName, OS);
1935 EmitHwModeCheck(ClassName, OS);
1937 OS << "} // end namespace llvm\n\n";
1939 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
1941 EmitMCInstrAnalysisPredicateFunctions(OS);
1944 namespace llvm {
1946 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
1947 CodeGenTarget CGTarget(RK);
1948 SubtargetEmitter(RK, CGTarget).run(OS);
1951 } // end namespace llvm