1193323Sed//===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10193323Sed// This tablegen backend emits subtarget enumerations.
11193323Sed//
12193323Sed//===----------------------------------------------------------------------===//
13193323Sed
14243830Sdim#define DEBUG_TYPE "subtarget-emitter"
15243830Sdim
16193323Sed#include "CodeGenTarget.h"
17239462Sdim#include "CodeGenSchedule.h"
18249423Sdim#include "llvm/ADT/STLExtras.h"
19193323Sed#include "llvm/ADT/StringExtras.h"
20239462Sdim#include "llvm/MC/MCInstrItineraries.h"
21249423Sdim#include "llvm/Support/Debug.h"
22249423Sdim#include "llvm/Support/Format.h"
23243830Sdim#include "llvm/TableGen/Error.h"
24239462Sdim#include "llvm/TableGen/Record.h"
25239462Sdim#include "llvm/TableGen/TableGenBackend.h"
26193323Sed#include <algorithm>
27239462Sdim#include <map>
28239462Sdim#include <string>
29239462Sdim#include <vector>
30193323Sedusing namespace llvm;
31193323Sed
32239462Sdimnamespace {
33239462Sdimclass SubtargetEmitter {
34243830Sdim  // Each processor has a SchedClassDesc table with an entry for each SchedClass.
35243830Sdim  // The SchedClassDesc table indexes into a global write resource table, write
36243830Sdim  // latency table, and read advance table.
37243830Sdim  struct SchedClassTables {
38243830Sdim    std::vector<std::vector<MCSchedClassDesc> > ProcSchedClasses;
39243830Sdim    std::vector<MCWriteProcResEntry> WriteProcResources;
40243830Sdim    std::vector<MCWriteLatencyEntry> WriteLatencies;
41243830Sdim    std::vector<std::string> WriterNames;
42243830Sdim    std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
43239462Sdim
44243830Sdim    // Reserve an invalid entry at index 0
45243830Sdim    SchedClassTables() {
46243830Sdim      ProcSchedClasses.resize(1);
47243830Sdim      WriteProcResources.resize(1);
48243830Sdim      WriteLatencies.resize(1);
49243830Sdim      WriterNames.push_back("InvalidWrite");
50243830Sdim      ReadAdvanceEntries.resize(1);
51243830Sdim    }
52243830Sdim  };
53243830Sdim
54243830Sdim  struct LessWriteProcResources {
55243830Sdim    bool operator()(const MCWriteProcResEntry &LHS,
56243830Sdim                    const MCWriteProcResEntry &RHS) {
57243830Sdim      return LHS.ProcResourceIdx < RHS.ProcResourceIdx;
58243830Sdim    }
59243830Sdim  };
60243830Sdim
61239462Sdim  RecordKeeper &Records;
62239462Sdim  CodeGenSchedModels &SchedModels;
63239462Sdim  std::string Target;
64239462Sdim
65239462Sdim  void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits);
66239462Sdim  unsigned FeatureKeyValues(raw_ostream &OS);
67239462Sdim  unsigned CPUKeyValues(raw_ostream &OS);
68239462Sdim  void FormItineraryStageString(const std::string &Names,
69239462Sdim                                Record *ItinData, std::string &ItinString,
70239462Sdim                                unsigned &NStages);
71239462Sdim  void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
72239462Sdim                                       unsigned &NOperandCycles);
73239462Sdim  void FormItineraryBypassString(const std::string &Names,
74239462Sdim                                 Record *ItinData,
75239462Sdim                                 std::string &ItinString, unsigned NOperandCycles);
76239462Sdim  void EmitStageAndOperandCycleData(raw_ostream &OS,
77239462Sdim                                    std::vector<std::vector<InstrItinerary> >
78239462Sdim                                      &ProcItinLists);
79239462Sdim  void EmitItineraries(raw_ostream &OS,
80239462Sdim                       std::vector<std::vector<InstrItinerary> >
81239462Sdim                         &ProcItinLists);
82239462Sdim  void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name,
83239462Sdim                         char Separator);
84243830Sdim  void EmitProcessorResources(const CodeGenProcModel &ProcModel,
85243830Sdim                              raw_ostream &OS);
86243830Sdim  Record *FindWriteResources(const CodeGenSchedRW &SchedWrite,
87243830Sdim                             const CodeGenProcModel &ProcModel);
88243830Sdim  Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
89243830Sdim                          const CodeGenProcModel &ProcModel);
90249423Sdim  void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
91249423Sdim                           const CodeGenProcModel &ProcModel);
92243830Sdim  void GenSchedClassTables(const CodeGenProcModel &ProcModel,
93243830Sdim                           SchedClassTables &SchedTables);
94243830Sdim  void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
95239462Sdim  void EmitProcessorModels(raw_ostream &OS);
96239462Sdim  void EmitProcessorLookup(raw_ostream &OS);
97243830Sdim  void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS);
98239462Sdim  void EmitSchedModel(raw_ostream &OS);
99239462Sdim  void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures,
100239462Sdim                             unsigned NumProcs);
101239462Sdim
102239462Sdimpublic:
103239462Sdim  SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT):
104239462Sdim    Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {}
105239462Sdim
106239462Sdim  void run(raw_ostream &o);
107239462Sdim
108239462Sdim};
109239462Sdim} // End anonymous namespace
110239462Sdim
111193323Sed//
112193323Sed// Enumeration - Emit the specified class as an enumeration.
113193323Sed//
114195340Sedvoid SubtargetEmitter::Enumeration(raw_ostream &OS,
115193323Sed                                   const char *ClassName,
116193323Sed                                   bool isBits) {
117193323Sed  // Get all records of class and sort
118193323Sed  std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName);
119193323Sed  std::sort(DefList.begin(), DefList.end(), LessRecord());
120193323Sed
121221345Sdim  unsigned N = DefList.size();
122224145Sdim  if (N == 0)
123224145Sdim    return;
124221345Sdim  if (N > 64) {
125221345Sdim    errs() << "Too many (> 64) subtarget features!\n";
126221345Sdim    exit(1);
127221345Sdim  }
128221345Sdim
129224145Sdim  OS << "namespace " << Target << " {\n";
130224145Sdim
131234353Sdim  // For bit flag enumerations with more than 32 items, emit constants.
132234353Sdim  // Emit an enum for everything else.
133234353Sdim  if (isBits && N > 32) {
134234353Sdim    // For each record
135234353Sdim    for (unsigned i = 0; i < N; i++) {
136234353Sdim      // Next record
137234353Sdim      Record *Def = DefList[i];
138224145Sdim
139234353Sdim      // Get and emit name and expression (1 << i)
140234353Sdim      OS << "  const uint64_t " << Def->getName() << " = 1ULL << " << i << ";\n";
141234353Sdim    }
142234353Sdim  } else {
143234353Sdim    // Open enumeration
144234353Sdim    OS << "enum {\n";
145221345Sdim
146234353Sdim    // For each record
147234353Sdim    for (unsigned i = 0; i < N;) {
148234353Sdim      // Next record
149234353Sdim      Record *Def = DefList[i];
150221345Sdim
151234353Sdim      // Get and emit name
152234353Sdim      OS << "  " << Def->getName();
153193323Sed
154234353Sdim      // If bit flags then emit expression (1 << i)
155234353Sdim      if (isBits)  OS << " = " << " 1ULL << " << i;
156221345Sdim
157234353Sdim      // Depending on 'if more in the list' emit comma
158234353Sdim      if (++i < N) OS << ",";
159234353Sdim
160234353Sdim      OS << "\n";
161234353Sdim    }
162234353Sdim
163234353Sdim    // Close enumeration
164234353Sdim    OS << "};\n";
165193323Sed  }
166221345Sdim
167224145Sdim  OS << "}\n";
168193323Sed}
169193323Sed
170193323Sed//
171193323Sed// FeatureKeyValues - Emit data of all the subtarget features.  Used by the
172193323Sed// command line.
173193323Sed//
174224145Sdimunsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) {
175193323Sed  // Gather and sort all the features
176193323Sed  std::vector<Record*> FeatureList =
177193323Sed                           Records.getAllDerivedDefinitions("SubtargetFeature");
178224145Sdim
179224145Sdim  if (FeatureList.empty())
180224145Sdim    return 0;
181224145Sdim
182193323Sed  std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName());
183193323Sed
184193323Sed  // Begin feature table
185193323Sed  OS << "// Sorted (by key) array of values for CPU features.\n"
186234353Sdim     << "extern const llvm::SubtargetFeatureKV " << Target
187234353Sdim     << "FeatureKV[] = {\n";
188221345Sdim
189193323Sed  // For each feature
190224145Sdim  unsigned NumFeatures = 0;
191193323Sed  for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) {
192193323Sed    // Next feature
193193323Sed    Record *Feature = FeatureList[i];
194193323Sed
195193323Sed    const std::string &Name = Feature->getName();
196193323Sed    const std::string &CommandLineName = Feature->getValueAsString("Name");
197193323Sed    const std::string &Desc = Feature->getValueAsString("Desc");
198221345Sdim
199193323Sed    if (CommandLineName.empty()) continue;
200221345Sdim
201193323Sed    // Emit as { "feature", "description", featureEnum, i1 | i2 | ... | in }
202193323Sed    OS << "  { "
203193323Sed       << "\"" << CommandLineName << "\", "
204193323Sed       << "\"" << Desc << "\", "
205224145Sdim       << Target << "::" << Name << ", ";
206193323Sed
207221345Sdim    const std::vector<Record*> &ImpliesList =
208193323Sed      Feature->getValueAsListOfDefs("Implies");
209221345Sdim
210193323Sed    if (ImpliesList.empty()) {
211221345Sdim      OS << "0ULL";
212193323Sed    } else {
213193323Sed      for (unsigned j = 0, M = ImpliesList.size(); j < M;) {
214224145Sdim        OS << Target << "::" << ImpliesList[j]->getName();
215193323Sed        if (++j < M) OS << " | ";
216193323Sed      }
217193323Sed    }
218193323Sed
219193323Sed    OS << " }";
220224145Sdim    ++NumFeatures;
221221345Sdim
222193323Sed    // Depending on 'if more in the list' emit comma
223193323Sed    if ((i + 1) < N) OS << ",";
224221345Sdim
225193323Sed    OS << "\n";
226193323Sed  }
227221345Sdim
228193323Sed  // End feature table
229193323Sed  OS << "};\n";
230193323Sed
231224145Sdim  return NumFeatures;
232193323Sed}
233193323Sed
234193323Sed//
235193323Sed// CPUKeyValues - Emit data of all the subtarget processors.  Used by command
236193323Sed// line.
237193323Sed//
238224145Sdimunsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) {
239193323Sed  // Gather and sort processor information
240193323Sed  std::vector<Record*> ProcessorList =
241193323Sed                          Records.getAllDerivedDefinitions("Processor");
242193323Sed  std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
243193323Sed
244193323Sed  // Begin processor table
245193323Sed  OS << "// Sorted (by key) array of values for CPU subtype.\n"
246234353Sdim     << "extern const llvm::SubtargetFeatureKV " << Target
247234353Sdim     << "SubTypeKV[] = {\n";
248221345Sdim
249193323Sed  // For each processor
250193323Sed  for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
251193323Sed    // Next processor
252193323Sed    Record *Processor = ProcessorList[i];
253193323Sed
254193323Sed    const std::string &Name = Processor->getValueAsString("Name");
255221345Sdim    const std::vector<Record*> &FeatureList =
256193323Sed      Processor->getValueAsListOfDefs("Features");
257221345Sdim
258193323Sed    // Emit as { "cpu", "description", f1 | f2 | ... fn },
259193323Sed    OS << "  { "
260193323Sed       << "\"" << Name << "\", "
261193323Sed       << "\"Select the " << Name << " processor\", ";
262221345Sdim
263193323Sed    if (FeatureList.empty()) {
264221345Sdim      OS << "0ULL";
265193323Sed    } else {
266193323Sed      for (unsigned j = 0, M = FeatureList.size(); j < M;) {
267224145Sdim        OS << Target << "::" << FeatureList[j]->getName();
268193323Sed        if (++j < M) OS << " | ";
269193323Sed      }
270193323Sed    }
271221345Sdim
272193323Sed    // The "0" is for the "implies" section of this data structure.
273221345Sdim    OS << ", 0ULL }";
274221345Sdim
275193323Sed    // Depending on 'if more in the list' emit comma
276193323Sed    if (++i < N) OS << ",";
277221345Sdim
278193323Sed    OS << "\n";
279193323Sed  }
280221345Sdim
281193323Sed  // End processor table
282193323Sed  OS << "};\n";
283193323Sed
284224145Sdim  return ProcessorList.size();
285193323Sed}
286193323Sed
287193323Sed//
288198090Srdivacky// FormItineraryStageString - Compose a string containing the stage
289198090Srdivacky// data initialization for the specified itinerary.  N is the number
290198090Srdivacky// of stages.
291193323Sed//
292207618Srdivackyvoid SubtargetEmitter::FormItineraryStageString(const std::string &Name,
293207618Srdivacky                                                Record *ItinData,
294198090Srdivacky                                                std::string &ItinString,
295198090Srdivacky                                                unsigned &NStages) {
296193323Sed  // Get states list
297193323Sed  const std::vector<Record*> &StageList =
298193323Sed    ItinData->getValueAsListOfDefs("Stages");
299193323Sed
300193323Sed  // For each stage
301193323Sed  unsigned N = NStages = StageList.size();
302193323Sed  for (unsigned i = 0; i < N;) {
303193323Sed    // Next stage
304193323Sed    const Record *Stage = StageList[i];
305221345Sdim
306207618Srdivacky    // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }
307193323Sed    int Cycles = Stage->getValueAsInt("Cycles");
308193323Sed    ItinString += "  { " + itostr(Cycles) + ", ";
309221345Sdim
310193323Sed    // Get unit list
311193323Sed    const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units");
312221345Sdim
313193323Sed    // For each unit
314193323Sed    for (unsigned j = 0, M = UnitList.size(); j < M;) {
315193323Sed      // Add name and bitwise or
316207618Srdivacky      ItinString += Name + "FU::" + UnitList[j]->getName();
317193323Sed      if (++j < M) ItinString += " | ";
318193323Sed    }
319221345Sdim
320198090Srdivacky    int TimeInc = Stage->getValueAsInt("TimeInc");
321198090Srdivacky    ItinString += ", " + itostr(TimeInc);
322198090Srdivacky
323207618Srdivacky    int Kind = Stage->getValueAsInt("Kind");
324207618Srdivacky    ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);
325207618Srdivacky
326193323Sed    // Close off stage
327193323Sed    ItinString += " }";
328193323Sed    if (++i < N) ItinString += ", ";
329193323Sed  }
330193323Sed}
331193323Sed
332193323Sed//
333198090Srdivacky// FormItineraryOperandCycleString - Compose a string containing the
334198090Srdivacky// operand cycle initialization for the specified itinerary.  N is the
335198090Srdivacky// number of operands that has cycles specified.
336193323Sed//
337198090Srdivackyvoid SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData,
338198090Srdivacky                         std::string &ItinString, unsigned &NOperandCycles) {
339198090Srdivacky  // Get operand cycle list
340198090Srdivacky  const std::vector<int64_t> &OperandCycleList =
341198090Srdivacky    ItinData->getValueAsListOfInts("OperandCycles");
342198090Srdivacky
343198090Srdivacky  // For each operand cycle
344198090Srdivacky  unsigned N = NOperandCycles = OperandCycleList.size();
345198090Srdivacky  for (unsigned i = 0; i < N;) {
346198090Srdivacky    // Next operand cycle
347198090Srdivacky    const int OCycle = OperandCycleList[i];
348221345Sdim
349198090Srdivacky    ItinString += "  " + itostr(OCycle);
350198090Srdivacky    if (++i < N) ItinString += ", ";
351198090Srdivacky  }
352198090Srdivacky}
353198090Srdivacky
354218893Sdimvoid SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
355218893Sdim                                                 Record *ItinData,
356218893Sdim                                                 std::string &ItinString,
357218893Sdim                                                 unsigned NOperandCycles) {
358218893Sdim  const std::vector<Record*> &BypassList =
359218893Sdim    ItinData->getValueAsListOfDefs("Bypasses");
360218893Sdim  unsigned N = BypassList.size();
361218893Sdim  unsigned i = 0;
362218893Sdim  for (; i < N;) {
363218893Sdim    ItinString += Name + "Bypass::" + BypassList[i]->getName();
364218893Sdim    if (++i < NOperandCycles) ItinString += ", ";
365218893Sdim  }
366218893Sdim  for (; i < NOperandCycles;) {
367218893Sdim    ItinString += " 0";
368218893Sdim    if (++i < NOperandCycles) ItinString += ", ";
369218893Sdim  }
370218893Sdim}
371218893Sdim
372198090Srdivacky//
373239462Sdim// EmitStageAndOperandCycleData - Generate unique itinerary stages and operand
374239462Sdim// cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed
375239462Sdim// by CodeGenSchedClass::Index.
376198090Srdivacky//
377239462Sdimvoid SubtargetEmitter::
378239462SdimEmitStageAndOperandCycleData(raw_ostream &OS,
379239462Sdim                             std::vector<std::vector<InstrItinerary> >
380239462Sdim                               &ProcItinLists) {
381221345Sdim
382239462Sdim  // Multiple processor models may share an itinerary record. Emit it once.
383239462Sdim  SmallPtrSet<Record*, 8> ItinsDefSet;
384193323Sed
385207618Srdivacky  // Emit functional units for all the itineraries.
386239462Sdim  for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
387239462Sdim         PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
388207618Srdivacky
389239462Sdim    if (!ItinsDefSet.insert(PI->ItinsDef))
390239462Sdim      continue;
391239462Sdim
392239462Sdim    std::vector<Record*> FUs = PI->ItinsDef->getValueAsListOfDefs("FU");
393207618Srdivacky    if (FUs.empty())
394207618Srdivacky      continue;
395207618Srdivacky
396239462Sdim    const std::string &Name = PI->ItinsDef->getName();
397239462Sdim    OS << "\n// Functional units for \"" << Name << "\"\n"
398207618Srdivacky       << "namespace " << Name << "FU {\n";
399207618Srdivacky
400207618Srdivacky    for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
401207618Srdivacky      OS << "  const unsigned " << FUs[j]->getName()
402207618Srdivacky         << " = 1 << " << j << ";\n";
403207618Srdivacky
404207618Srdivacky    OS << "}\n";
405218893Sdim
406239462Sdim    std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP");
407218893Sdim    if (BPs.size()) {
408218893Sdim      OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name
409218893Sdim         << "\"\n" << "namespace " << Name << "Bypass {\n";
410218893Sdim
411234353Sdim      OS << "  const unsigned NoBypass = 0;\n";
412218893Sdim      for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
413234353Sdim        OS << "  const unsigned " << BPs[j]->getName()
414218893Sdim           << " = 1 << " << j << ";\n";
415218893Sdim
416218893Sdim      OS << "}\n";
417218893Sdim    }
418207618Srdivacky  }
419207618Srdivacky
420193323Sed  // Begin stages table
421234353Sdim  std::string StageTable = "\nextern const llvm::InstrStage " + Target +
422234353Sdim                           "Stages[] = {\n";
423207618Srdivacky  StageTable += "  { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
424221345Sdim
425198090Srdivacky  // Begin operand cycle table
426234353Sdim  std::string OperandCycleTable = "extern const unsigned " + Target +
427224145Sdim    "OperandCycles[] = {\n";
428198090Srdivacky  OperandCycleTable += "  0, // No itinerary\n";
429218893Sdim
430218893Sdim  // Begin pipeline bypass table
431234353Sdim  std::string BypassTable = "extern const unsigned " + Target +
432239462Sdim    "ForwardingPaths[] = {\n";
433239462Sdim  BypassTable += " 0, // No itinerary\n";
434221345Sdim
435239462Sdim  // For each Itinerary across all processors, add a unique entry to the stages,
436239462Sdim  // operand cycles, and pipepine bypess tables. Then add the new Itinerary
437239462Sdim  // object with computed offsets to the ProcItinLists result.
438198090Srdivacky  unsigned StageCount = 1, OperandCycleCount = 1;
439218893Sdim  std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
440239462Sdim  for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
441239462Sdim         PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
442239462Sdim    const CodeGenProcModel &ProcModel = *PI;
443221345Sdim
444239462Sdim    // Add process itinerary to the list.
445239462Sdim    ProcItinLists.resize(ProcItinLists.size()+1);
446221345Sdim
447239462Sdim    // If this processor defines no itineraries, then leave the itinerary list
448239462Sdim    // empty.
449239462Sdim    std::vector<InstrItinerary> &ItinList = ProcItinLists.back();
450249423Sdim    if (!ProcModel.hasItineraries())
451239462Sdim      continue;
452221345Sdim
453239462Sdim    const std::string &Name = ProcModel.ItinsDef->getName();
454221345Sdim
455249423Sdim    ItinList.resize(SchedModels.numInstrSchedClasses());
456249423Sdim    assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");
457249423Sdim
458249423Sdim    for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();
459239462Sdim         SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
460239462Sdim
461193323Sed      // Next itinerary data
462239462Sdim      Record *ItinData = ProcModel.ItinDefList[SchedClassIdx];
463221345Sdim
464193323Sed      // Get string and stage count
465198090Srdivacky      std::string ItinStageString;
466239462Sdim      unsigned NStages = 0;
467239462Sdim      if (ItinData)
468239462Sdim        FormItineraryStageString(Name, ItinData, ItinStageString, NStages);
469193323Sed
470198090Srdivacky      // Get string and operand cycle count
471198090Srdivacky      std::string ItinOperandCycleString;
472239462Sdim      unsigned NOperandCycles = 0;
473218893Sdim      std::string ItinBypassString;
474239462Sdim      if (ItinData) {
475239462Sdim        FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
476239462Sdim                                        NOperandCycles);
477218893Sdim
478239462Sdim        FormItineraryBypassString(Name, ItinData, ItinBypassString,
479239462Sdim                                  NOperandCycles);
480239462Sdim      }
481239462Sdim
482198090Srdivacky      // Check to see if stage already exists and create if it doesn't
483198090Srdivacky      unsigned FindStage = 0;
484198090Srdivacky      if (NStages > 0) {
485198090Srdivacky        FindStage = ItinStageMap[ItinStageString];
486198090Srdivacky        if (FindStage == 0) {
487221345Sdim          // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices
488221345Sdim          StageTable += ItinStageString + ", // " + itostr(StageCount);
489221345Sdim          if (NStages > 1)
490221345Sdim            StageTable += "-" + itostr(StageCount + NStages - 1);
491221345Sdim          StageTable += "\n";
492198090Srdivacky          // Record Itin class number.
493198090Srdivacky          ItinStageMap[ItinStageString] = FindStage = StageCount;
494198090Srdivacky          StageCount += NStages;
495198090Srdivacky        }
496198090Srdivacky      }
497221345Sdim
498198090Srdivacky      // Check to see if operand cycle already exists and create if it doesn't
499198090Srdivacky      unsigned FindOperandCycle = 0;
500198090Srdivacky      if (NOperandCycles > 0) {
501218893Sdim        std::string ItinOperandString = ItinOperandCycleString+ItinBypassString;
502218893Sdim        FindOperandCycle = ItinOperandMap[ItinOperandString];
503198090Srdivacky        if (FindOperandCycle == 0) {
504198090Srdivacky          // Emit as  cycle, // index
505221345Sdim          OperandCycleTable += ItinOperandCycleString + ", // ";
506221345Sdim          std::string OperandIdxComment = itostr(OperandCycleCount);
507221345Sdim          if (NOperandCycles > 1)
508221345Sdim            OperandIdxComment += "-"
509221345Sdim              + itostr(OperandCycleCount + NOperandCycles - 1);
510221345Sdim          OperandCycleTable += OperandIdxComment + "\n";
511198090Srdivacky          // Record Itin class number.
512221345Sdim          ItinOperandMap[ItinOperandCycleString] =
513198090Srdivacky            FindOperandCycle = OperandCycleCount;
514218893Sdim          // Emit as bypass, // index
515221345Sdim          BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";
516198090Srdivacky          OperandCycleCount += NOperandCycles;
517198090Srdivacky        }
518193323Sed      }
519221345Sdim
520218893Sdim      // Set up itinerary as location and location + stage count
521239462Sdim      int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0;
522218893Sdim      InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages,
523218893Sdim                                    FindOperandCycle,
524218893Sdim                                    FindOperandCycle + NOperandCycles};
525218893Sdim
526193323Sed      // Inject - empty slots will be 0, 0
527239462Sdim      ItinList[SchedClassIdx] = Intinerary;
528193323Sed    }
529193323Sed  }
530218893Sdim
531193323Sed  // Closing stage
532239462Sdim  StageTable += "  { 0, 0, 0, llvm::InstrStage::Required } // End stages\n";
533198090Srdivacky  StageTable += "};\n";
534198090Srdivacky
535198090Srdivacky  // Closing operand cycles
536239462Sdim  OperandCycleTable += "  0 // End operand cycles\n";
537198090Srdivacky  OperandCycleTable += "};\n";
538198090Srdivacky
539239462Sdim  BypassTable += " 0 // End bypass tables\n";
540218893Sdim  BypassTable += "};\n";
541218893Sdim
542198090Srdivacky  // Emit tables.
543198090Srdivacky  OS << StageTable;
544198090Srdivacky  OS << OperandCycleTable;
545218893Sdim  OS << BypassTable;
546193323Sed}
547193323Sed
548193323Sed//
549239462Sdim// EmitProcessorData - Generate data for processor itineraries that were
550239462Sdim// computed during EmitStageAndOperandCycleData(). ProcItinLists lists all
551239462Sdim// Itineraries for each processor. The Itinerary lists are indexed on
552239462Sdim// CodeGenSchedClass::Index.
553193323Sed//
554221345Sdimvoid SubtargetEmitter::
555239462SdimEmitItineraries(raw_ostream &OS,
556239462Sdim                std::vector<std::vector<InstrItinerary> > &ProcItinLists) {
557239462Sdim
558239462Sdim  // Multiple processor models may share an itinerary record. Emit it once.
559239462Sdim  SmallPtrSet<Record*, 8> ItinsDefSet;
560239462Sdim
561239462Sdim  // For each processor's machine model
562193323Sed  std::vector<std::vector<InstrItinerary> >::iterator
563239462Sdim      ProcItinListsIter = ProcItinLists.begin();
564239462Sdim  for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
565243830Sdim         PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) {
566221345Sdim
567239462Sdim    Record *ItinsDef = PI->ItinsDef;
568239462Sdim    if (!ItinsDefSet.insert(ItinsDef))
569239462Sdim      continue;
570193323Sed
571193323Sed    // Get processor itinerary name
572239462Sdim    const std::string &Name = ItinsDef->getName();
573221345Sdim
574239462Sdim    // Get the itinerary list for the processor.
575239462Sdim    assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator");
576243830Sdim    std::vector<InstrItinerary> &ItinList = *ProcItinListsIter;
577193323Sed
578193323Sed    OS << "\n";
579239462Sdim    OS << "static const llvm::InstrItinerary ";
580239462Sdim    if (ItinList.empty()) {
581239462Sdim      OS << '*' << Name << " = 0;\n";
582239462Sdim      continue;
583239462Sdim    }
584221345Sdim
585239462Sdim    // Begin processor itinerary table
586239462Sdim    OS << Name << "[] = {\n";
587239462Sdim
588239462Sdim    // For each itinerary class in CodeGenSchedClass::Index order.
589198090Srdivacky    for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {
590193323Sed      InstrItinerary &Intinerary = ItinList[j];
591221345Sdim
592239462Sdim      // Emit Itinerary in the form of
593198090Srdivacky      // { firstStage, lastStage, firstCycle, lastCycle } // index
594239462Sdim      OS << "  { " <<
595239462Sdim        Intinerary.NumMicroOps << ", " <<
596239462Sdim        Intinerary.FirstStage << ", " <<
597239462Sdim        Intinerary.LastStage << ", " <<
598239462Sdim        Intinerary.FirstOperandCycle << ", " <<
599239462Sdim        Intinerary.LastOperandCycle << " }" <<
600239462Sdim        ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
601193323Sed    }
602193323Sed    // End processor itinerary table
603239462Sdim    OS << "  { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n";
604193323Sed    OS << "};\n";
605193323Sed  }
606193323Sed}
607193323Sed
608239462Sdim// Emit either the value defined in the TableGen Record, or the default
609239462Sdim// value defined in the C++ header. The Record is null if the processor does not
610239462Sdim// define a model.
611239462Sdimvoid SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R,
612239462Sdim                                         const char *Name, char Separator) {
613239462Sdim  OS << "  ";
614239462Sdim  int V = R ? R->getValueAsInt(Name) : -1;
615239462Sdim  if (V >= 0)
616239462Sdim    OS << V << Separator << " // " << Name;
617239462Sdim  else
618239462Sdim    OS << "MCSchedModel::Default" << Name << Separator;
619239462Sdim  OS << '\n';
620239462Sdim}
621239462Sdim
622243830Sdimvoid SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
623243830Sdim                                              raw_ostream &OS) {
624243830Sdim  char Sep = ProcModel.ProcResourceDefs.empty() ? ' ' : ',';
625243830Sdim
626243830Sdim  OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n";
627243830Sdim  OS << "static const llvm::MCProcResourceDesc "
628243830Sdim     << ProcModel.ModelName << "ProcResources" << "[] = {\n"
629243830Sdim     << "  {DBGFIELD(\"InvalidUnit\")     0, 0, 0}" << Sep << "\n";
630243830Sdim
631243830Sdim  for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
632243830Sdim    Record *PRDef = ProcModel.ProcResourceDefs[i];
633243830Sdim
634249423Sdim    Record *SuperDef = 0;
635243830Sdim    unsigned SuperIdx = 0;
636249423Sdim    unsigned NumUnits = 0;
637263508Sdim    int BufferSize = PRDef->getValueAsInt("BufferSize");
638249423Sdim    if (PRDef->isSubClassOf("ProcResGroup")) {
639249423Sdim      RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
640249423Sdim      for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end();
641249423Sdim           RUI != RUE; ++RUI) {
642249423Sdim        NumUnits += (*RUI)->getValueAsInt("NumUnits");
643249423Sdim      }
644243830Sdim    }
645249423Sdim    else {
646249423Sdim      // Find the SuperIdx
647249423Sdim      if (PRDef->getValueInit("Super")->isComplete()) {
648249423Sdim        SuperDef = SchedModels.findProcResUnits(
649249423Sdim          PRDef->getValueAsDef("Super"), ProcModel);
650249423Sdim        SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
651249423Sdim      }
652249423Sdim      NumUnits = PRDef->getValueAsInt("NumUnits");
653249423Sdim    }
654243830Sdim    // Emit the ProcResourceDesc
655243830Sdim    if (i+1 == e)
656243830Sdim      Sep = ' ';
657243830Sdim    OS << "  {DBGFIELD(\"" << PRDef->getName() << "\") ";
658243830Sdim    if (PRDef->getName().size() < 15)
659243830Sdim      OS.indent(15 - PRDef->getName().size());
660249423Sdim    OS << NumUnits << ", " << SuperIdx << ", "
661263508Sdim       << BufferSize << "}" << Sep << " // #" << i+1;
662243830Sdim    if (SuperDef)
663243830Sdim      OS << ", Super=" << SuperDef->getName();
664243830Sdim    OS << "\n";
665243830Sdim  }
666243830Sdim  OS << "};\n";
667243830Sdim}
668243830Sdim
669243830Sdim// Find the WriteRes Record that defines processor resources for this
670243830Sdim// SchedWrite.
671243830SdimRecord *SubtargetEmitter::FindWriteResources(
672243830Sdim  const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) {
673243830Sdim
674243830Sdim  // Check if the SchedWrite is already subtarget-specific and directly
675243830Sdim  // specifies a set of processor resources.
676243830Sdim  if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))
677243830Sdim    return SchedWrite.TheDef;
678243830Sdim
679243830Sdim  Record *AliasDef = 0;
680243830Sdim  for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end();
681243830Sdim       AI != AE; ++AI) {
682243830Sdim    const CodeGenSchedRW &AliasRW =
683243830Sdim      SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
684243830Sdim    if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
685243830Sdim      Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
686243830Sdim      if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
687243830Sdim        continue;
688243830Sdim    }
689243830Sdim    if (AliasDef)
690243830Sdim      PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
691243830Sdim                    "defined for processor " + ProcModel.ModelName +
692243830Sdim                    " Ensure only one SchedAlias exists per RW.");
693243830Sdim    AliasDef = AliasRW.TheDef;
694243830Sdim  }
695243830Sdim  if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))
696243830Sdim    return AliasDef;
697243830Sdim
698243830Sdim  // Check this processor's list of write resources.
699243830Sdim  Record *ResDef = 0;
700243830Sdim  for (RecIter WRI = ProcModel.WriteResDefs.begin(),
701243830Sdim         WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) {
702243830Sdim    if (!(*WRI)->isSubClassOf("WriteRes"))
703243830Sdim      continue;
704243830Sdim    if (AliasDef == (*WRI)->getValueAsDef("WriteType")
705243830Sdim        || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) {
706243830Sdim      if (ResDef) {
707243830Sdim        PrintFatalError((*WRI)->getLoc(), "Resources are defined for both "
708243830Sdim                      "SchedWrite and its alias on processor " +
709243830Sdim                      ProcModel.ModelName);
710243830Sdim      }
711243830Sdim      ResDef = *WRI;
712243830Sdim    }
713243830Sdim  }
714243830Sdim  // TODO: If ProcModel has a base model (previous generation processor),
715243830Sdim  // then call FindWriteResources recursively with that model here.
716243830Sdim  if (!ResDef) {
717243830Sdim    PrintFatalError(ProcModel.ModelDef->getLoc(),
718243830Sdim                  std::string("Processor does not define resources for ")
719243830Sdim                  + SchedWrite.TheDef->getName());
720243830Sdim  }
721243830Sdim  return ResDef;
722243830Sdim}
723243830Sdim
724243830Sdim/// Find the ReadAdvance record for the given SchedRead on this processor or
725243830Sdim/// return NULL.
726243830SdimRecord *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
727243830Sdim                                          const CodeGenProcModel &ProcModel) {
728243830Sdim  // Check for SchedReads that directly specify a ReadAdvance.
729243830Sdim  if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))
730243830Sdim    return SchedRead.TheDef;
731243830Sdim
732243830Sdim  // Check this processor's list of aliases for SchedRead.
733243830Sdim  Record *AliasDef = 0;
734243830Sdim  for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end();
735243830Sdim       AI != AE; ++AI) {
736243830Sdim    const CodeGenSchedRW &AliasRW =
737243830Sdim      SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
738243830Sdim    if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
739243830Sdim      Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
740243830Sdim      if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
741243830Sdim        continue;
742243830Sdim    }
743243830Sdim    if (AliasDef)
744243830Sdim      PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
745243830Sdim                    "defined for processor " + ProcModel.ModelName +
746243830Sdim                    " Ensure only one SchedAlias exists per RW.");
747243830Sdim    AliasDef = AliasRW.TheDef;
748243830Sdim  }
749243830Sdim  if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))
750243830Sdim    return AliasDef;
751243830Sdim
752243830Sdim  // Check this processor's ReadAdvanceList.
753243830Sdim  Record *ResDef = 0;
754243830Sdim  for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(),
755243830Sdim         RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) {
756243830Sdim    if (!(*RAI)->isSubClassOf("ReadAdvance"))
757243830Sdim      continue;
758243830Sdim    if (AliasDef == (*RAI)->getValueAsDef("ReadType")
759243830Sdim        || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) {
760243830Sdim      if (ResDef) {
761243830Sdim        PrintFatalError((*RAI)->getLoc(), "Resources are defined for both "
762243830Sdim                      "SchedRead and its alias on processor " +
763243830Sdim                      ProcModel.ModelName);
764243830Sdim      }
765243830Sdim      ResDef = *RAI;
766243830Sdim    }
767243830Sdim  }
768243830Sdim  // TODO: If ProcModel has a base model (previous generation processor),
769243830Sdim  // then call FindReadAdvance recursively with that model here.
770243830Sdim  if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {
771243830Sdim    PrintFatalError(ProcModel.ModelDef->getLoc(),
772243830Sdim                  std::string("Processor does not define resources for ")
773243830Sdim                  + SchedRead.TheDef->getName());
774243830Sdim  }
775243830Sdim  return ResDef;
776243830Sdim}
777243830Sdim
778249423Sdim// Expand an explicit list of processor resources into a full list of implied
779251662Sdim// resource groups and super resources that cover them.
780249423Sdimvoid SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
781249423Sdim                                           std::vector<int64_t> &Cycles,
782251662Sdim                                           const CodeGenProcModel &PM) {
783249423Sdim  // Default to 1 resource cycle.
784249423Sdim  Cycles.resize(PRVec.size(), 1);
785249423Sdim  for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
786251662Sdim    Record *PRDef = PRVec[i];
787249423Sdim    RecVec SubResources;
788251662Sdim    if (PRDef->isSubClassOf("ProcResGroup"))
789251662Sdim      SubResources = PRDef->getValueAsListOfDefs("Resources");
790249423Sdim    else {
791251662Sdim      SubResources.push_back(PRDef);
792251662Sdim      PRDef = SchedModels.findProcResUnits(PRVec[i], PM);
793251662Sdim      for (Record *SubDef = PRDef;
794251662Sdim           SubDef->getValueInit("Super")->isComplete();) {
795251662Sdim        if (SubDef->isSubClassOf("ProcResGroup")) {
796251662Sdim          // Disallow this for simplicitly.
797251662Sdim          PrintFatalError(SubDef->getLoc(), "Processor resource group "
798251662Sdim                          " cannot be a super resources.");
799251662Sdim        }
800251662Sdim        Record *SuperDef =
801251662Sdim          SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM);
802251662Sdim        PRVec.push_back(SuperDef);
803251662Sdim        Cycles.push_back(Cycles[i]);
804251662Sdim        SubDef = SuperDef;
805251662Sdim      }
806249423Sdim    }
807251662Sdim    for (RecIter PRI = PM.ProcResourceDefs.begin(),
808251662Sdim           PRE = PM.ProcResourceDefs.end();
809249423Sdim         PRI != PRE; ++PRI) {
810251662Sdim      if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup"))
811249423Sdim        continue;
812249423Sdim      RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources");
813249423Sdim      RecIter SubI = SubResources.begin(), SubE = SubResources.end();
814251662Sdim      for( ; SubI != SubE; ++SubI) {
815251662Sdim        if (std::find(SuperResources.begin(), SuperResources.end(), *SubI)
816251662Sdim            == SuperResources.end()) {
817249423Sdim          break;
818251662Sdim        }
819249423Sdim      }
820249423Sdim      if (SubI == SubE) {
821249423Sdim        PRVec.push_back(*PRI);
822249423Sdim        Cycles.push_back(Cycles[i]);
823249423Sdim      }
824249423Sdim    }
825249423Sdim  }
826249423Sdim}
827249423Sdim
828243830Sdim// Generate the SchedClass table for this processor and update global
829243830Sdim// tables. Must be called for each processor in order.
830243830Sdimvoid SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
831243830Sdim                                           SchedClassTables &SchedTables) {
832243830Sdim  SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1);
833243830Sdim  if (!ProcModel.hasInstrSchedModel())
834243830Sdim    return;
835243830Sdim
836243830Sdim  std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back();
837243830Sdim  for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(),
838243830Sdim         SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
839243830Sdim    DEBUG(SCI->dump(&SchedModels));
840243830Sdim
841243830Sdim    SCTab.resize(SCTab.size() + 1);
842243830Sdim    MCSchedClassDesc &SCDesc = SCTab.back();
843243830Sdim    // SCDesc.Name is guarded by NDEBUG
844243830Sdim    SCDesc.NumMicroOps = 0;
845243830Sdim    SCDesc.BeginGroup = false;
846243830Sdim    SCDesc.EndGroup = false;
847243830Sdim    SCDesc.WriteProcResIdx = 0;
848243830Sdim    SCDesc.WriteLatencyIdx = 0;
849243830Sdim    SCDesc.ReadAdvanceIdx = 0;
850243830Sdim
851243830Sdim    // A Variant SchedClass has no resources of its own.
852249423Sdim    bool HasVariants = false;
853249423Sdim    for (std::vector<CodeGenSchedTransition>::const_iterator
854249423Sdim           TI = SCI->Transitions.begin(), TE = SCI->Transitions.end();
855249423Sdim         TI != TE; ++TI) {
856249423Sdim      if (TI->ProcIndices[0] == 0) {
857249423Sdim        HasVariants = true;
858249423Sdim        break;
859249423Sdim      }
860249423Sdim      IdxIter PIPos = std::find(TI->ProcIndices.begin(),
861249423Sdim                                TI->ProcIndices.end(), ProcModel.Index);
862249423Sdim      if (PIPos != TI->ProcIndices.end()) {
863249423Sdim        HasVariants = true;
864249423Sdim        break;
865249423Sdim      }
866249423Sdim    }
867249423Sdim    if (HasVariants) {
868243830Sdim      SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;
869243830Sdim      continue;
870243830Sdim    }
871243830Sdim
872243830Sdim    // Determine if the SchedClass is actually reachable on this processor. If
873243830Sdim    // not don't try to locate the processor resources, it will fail.
874243830Sdim    // If ProcIndices contains 0, this class applies to all processors.
875243830Sdim    assert(!SCI->ProcIndices.empty() && "expect at least one procidx");
876243830Sdim    if (SCI->ProcIndices[0] != 0) {
877243830Sdim      IdxIter PIPos = std::find(SCI->ProcIndices.begin(),
878243830Sdim                                SCI->ProcIndices.end(), ProcModel.Index);
879243830Sdim      if (PIPos == SCI->ProcIndices.end())
880243830Sdim        continue;
881243830Sdim    }
882243830Sdim    IdxVec Writes = SCI->Writes;
883243830Sdim    IdxVec Reads = SCI->Reads;
884249423Sdim    if (!SCI->InstRWs.empty()) {
885249423Sdim      // This class has a default ReadWrite list which can be overriden by
886243830Sdim      // InstRW definitions.
887243830Sdim      Record *RWDef = 0;
888243830Sdim      for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();
889243830Sdim           RWI != RWE; ++RWI) {
890243830Sdim        Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");
891243830Sdim        if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {
892243830Sdim          RWDef = *RWI;
893243830Sdim          break;
894243830Sdim        }
895243830Sdim      }
896243830Sdim      if (RWDef) {
897243830Sdim        Writes.clear();
898243830Sdim        Reads.clear();
899243830Sdim        SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
900243830Sdim                            Writes, Reads);
901243830Sdim      }
902243830Sdim    }
903249423Sdim    if (Writes.empty()) {
904249423Sdim      // Check this processor's itinerary class resources.
905249423Sdim      for (RecIter II = ProcModel.ItinRWDefs.begin(),
906249423Sdim             IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) {
907249423Sdim        RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
908249423Sdim        if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef)
909249423Sdim            != Matched.end()) {
910249423Sdim          SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"),
911249423Sdim                              Writes, Reads);
912249423Sdim          break;
913249423Sdim        }
914249423Sdim      }
915249423Sdim      if (Writes.empty()) {
916249423Sdim        DEBUG(dbgs() << ProcModel.ModelName
917249423Sdim              << " does not have resources for class " << SCI->Name << '\n');
918249423Sdim      }
919249423Sdim    }
920243830Sdim    // Sum resources across all operand writes.
921243830Sdim    std::vector<MCWriteProcResEntry> WriteProcResources;
922243830Sdim    std::vector<MCWriteLatencyEntry> WriteLatencies;
923243830Sdim    std::vector<std::string> WriterNames;
924243830Sdim    std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
925243830Sdim    for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) {
926243830Sdim      IdxVec WriteSeq;
927243830Sdim      SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false,
928243830Sdim                                     ProcModel);
929243830Sdim
930243830Sdim      // For each operand, create a latency entry.
931243830Sdim      MCWriteLatencyEntry WLEntry;
932243830Sdim      WLEntry.Cycles = 0;
933243830Sdim      unsigned WriteID = WriteSeq.back();
934243830Sdim      WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
935243830Sdim      // If this Write is not referenced by a ReadAdvance, don't distinguish it
936243830Sdim      // from other WriteLatency entries.
937249423Sdim      if (!SchedModels.hasReadOfWrite(
938249423Sdim            SchedModels.getSchedWrite(WriteID).TheDef)) {
939243830Sdim        WriteID = 0;
940243830Sdim      }
941243830Sdim      WLEntry.WriteResourceID = WriteID;
942243830Sdim
943243830Sdim      for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end();
944243830Sdim           WSI != WSE; ++WSI) {
945243830Sdim
946243830Sdim        Record *WriteRes =
947243830Sdim          FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel);
948243830Sdim
949243830Sdim        // Mark the parent class as invalid for unsupported write types.
950243830Sdim        if (WriteRes->getValueAsBit("Unsupported")) {
951243830Sdim          SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
952243830Sdim          break;
953243830Sdim        }
954243830Sdim        WLEntry.Cycles += WriteRes->getValueAsInt("Latency");
955243830Sdim        SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps");
956243830Sdim        SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup");
957243830Sdim        SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup");
958243830Sdim
959243830Sdim        // Create an entry for each ProcResource listed in WriteRes.
960243830Sdim        RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
961243830Sdim        std::vector<int64_t> Cycles =
962243830Sdim          WriteRes->getValueAsListOfInts("ResourceCycles");
963249423Sdim
964249423Sdim        ExpandProcResources(PRVec, Cycles, ProcModel);
965249423Sdim
966243830Sdim        for (unsigned PRIdx = 0, PREnd = PRVec.size();
967243830Sdim             PRIdx != PREnd; ++PRIdx) {
968243830Sdim          MCWriteProcResEntry WPREntry;
969243830Sdim          WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
970243830Sdim          assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
971249423Sdim          WPREntry.Cycles = Cycles[PRIdx];
972249423Sdim          // If this resource is already used in this sequence, add the current
973249423Sdim          // entry's cycles so that the same resource appears to be used
974249423Sdim          // serially, rather than multiple parallel uses. This is important for
975249423Sdim          // in-order machine where the resource consumption is a hazard.
976249423Sdim          unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
977249423Sdim          for( ; WPRIdx != WPREnd; ++WPRIdx) {
978249423Sdim            if (WriteProcResources[WPRIdx].ProcResourceIdx
979249423Sdim                == WPREntry.ProcResourceIdx) {
980249423Sdim              WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
981249423Sdim              break;
982249423Sdim            }
983249423Sdim          }
984249423Sdim          if (WPRIdx == WPREnd)
985249423Sdim            WriteProcResources.push_back(WPREntry);
986243830Sdim        }
987243830Sdim      }
988243830Sdim      WriteLatencies.push_back(WLEntry);
989243830Sdim    }
990243830Sdim    // Create an entry for each operand Read in this SchedClass.
991243830Sdim    // Entries must be sorted first by UseIdx then by WriteResourceID.
992243830Sdim    for (unsigned UseIdx = 0, EndIdx = Reads.size();
993243830Sdim         UseIdx != EndIdx; ++UseIdx) {
994243830Sdim      Record *ReadAdvance =
995243830Sdim        FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
996243830Sdim      if (!ReadAdvance)
997243830Sdim        continue;
998243830Sdim
999243830Sdim      // Mark the parent class as invalid for unsupported write types.
1000243830Sdim      if (ReadAdvance->getValueAsBit("Unsupported")) {
1001243830Sdim        SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
1002243830Sdim        break;
1003243830Sdim      }
1004243830Sdim      RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites");
1005243830Sdim      IdxVec WriteIDs;
1006243830Sdim      if (ValidWrites.empty())
1007243830Sdim        WriteIDs.push_back(0);
1008243830Sdim      else {
1009243830Sdim        for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end();
1010243830Sdim             VWI != VWE; ++VWI) {
1011243830Sdim          WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false));
1012243830Sdim        }
1013243830Sdim      }
1014243830Sdim      std::sort(WriteIDs.begin(), WriteIDs.end());
1015243830Sdim      for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) {
1016243830Sdim        MCReadAdvanceEntry RAEntry;
1017243830Sdim        RAEntry.UseIdx = UseIdx;
1018243830Sdim        RAEntry.WriteResourceID = *WI;
1019243830Sdim        RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
1020243830Sdim        ReadAdvanceEntries.push_back(RAEntry);
1021243830Sdim      }
1022243830Sdim    }
1023243830Sdim    if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
1024243830Sdim      WriteProcResources.clear();
1025243830Sdim      WriteLatencies.clear();
1026243830Sdim      ReadAdvanceEntries.clear();
1027243830Sdim    }
1028243830Sdim    // Add the information for this SchedClass to the global tables using basic
1029243830Sdim    // compression.
1030243830Sdim    //
1031243830Sdim    // WritePrecRes entries are sorted by ProcResIdx.
1032243830Sdim    std::sort(WriteProcResources.begin(), WriteProcResources.end(),
1033243830Sdim              LessWriteProcResources());
1034243830Sdim
1035243830Sdim    SCDesc.NumWriteProcResEntries = WriteProcResources.size();
1036243830Sdim    std::vector<MCWriteProcResEntry>::iterator WPRPos =
1037243830Sdim      std::search(SchedTables.WriteProcResources.begin(),
1038243830Sdim                  SchedTables.WriteProcResources.end(),
1039243830Sdim                  WriteProcResources.begin(), WriteProcResources.end());
1040243830Sdim    if (WPRPos != SchedTables.WriteProcResources.end())
1041243830Sdim      SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
1042243830Sdim    else {
1043243830Sdim      SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size();
1044243830Sdim      SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(),
1045243830Sdim                                            WriteProcResources.end());
1046243830Sdim    }
1047243830Sdim    // Latency entries must remain in operand order.
1048243830Sdim    SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
1049243830Sdim    std::vector<MCWriteLatencyEntry>::iterator WLPos =
1050243830Sdim      std::search(SchedTables.WriteLatencies.begin(),
1051243830Sdim                  SchedTables.WriteLatencies.end(),
1052243830Sdim                  WriteLatencies.begin(), WriteLatencies.end());
1053243830Sdim    if (WLPos != SchedTables.WriteLatencies.end()) {
1054243830Sdim      unsigned idx = WLPos - SchedTables.WriteLatencies.begin();
1055243830Sdim      SCDesc.WriteLatencyIdx = idx;
1056243830Sdim      for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i)
1057243830Sdim        if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) ==
1058243830Sdim            std::string::npos) {
1059243830Sdim          SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];
1060243830Sdim        }
1061243830Sdim    }
1062243830Sdim    else {
1063243830Sdim      SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
1064243830Sdim      SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(),
1065243830Sdim                                        WriteLatencies.begin(),
1066243830Sdim                                        WriteLatencies.end());
1067243830Sdim      SchedTables.WriterNames.insert(SchedTables.WriterNames.end(),
1068243830Sdim                                     WriterNames.begin(), WriterNames.end());
1069243830Sdim    }
1070243830Sdim    // ReadAdvanceEntries must remain in operand order.
1071243830Sdim    SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
1072243830Sdim    std::vector<MCReadAdvanceEntry>::iterator RAPos =
1073243830Sdim      std::search(SchedTables.ReadAdvanceEntries.begin(),
1074243830Sdim                  SchedTables.ReadAdvanceEntries.end(),
1075243830Sdim                  ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
1076243830Sdim    if (RAPos != SchedTables.ReadAdvanceEntries.end())
1077243830Sdim      SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
1078243830Sdim    else {
1079243830Sdim      SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
1080243830Sdim      SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(),
1081243830Sdim                                            ReadAdvanceEntries.end());
1082243830Sdim    }
1083243830Sdim  }
1084243830Sdim}
1085243830Sdim
1086243830Sdim// Emit SchedClass tables for all processors and associated global tables.
1087243830Sdimvoid SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
1088243830Sdim                                            raw_ostream &OS) {
1089243830Sdim  // Emit global WriteProcResTable.
1090243830Sdim  OS << "\n// {ProcResourceIdx, Cycles}\n"
1091243830Sdim     << "extern const llvm::MCWriteProcResEntry "
1092243830Sdim     << Target << "WriteProcResTable[] = {\n"
1093243830Sdim     << "  { 0,  0}, // Invalid\n";
1094243830Sdim  for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
1095243830Sdim       WPRIdx != WPREnd; ++WPRIdx) {
1096243830Sdim    MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
1097243830Sdim    OS << "  {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
1098243830Sdim       << format("%2d", WPREntry.Cycles) << "}";
1099243830Sdim    if (WPRIdx + 1 < WPREnd)
1100243830Sdim      OS << ',';
1101243830Sdim    OS << " // #" << WPRIdx << '\n';
1102243830Sdim  }
1103243830Sdim  OS << "}; // " << Target << "WriteProcResTable\n";
1104243830Sdim
1105243830Sdim  // Emit global WriteLatencyTable.
1106243830Sdim  OS << "\n// {Cycles, WriteResourceID}\n"
1107243830Sdim     << "extern const llvm::MCWriteLatencyEntry "
1108243830Sdim     << Target << "WriteLatencyTable[] = {\n"
1109243830Sdim     << "  { 0,  0}, // Invalid\n";
1110243830Sdim  for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
1111243830Sdim       WLIdx != WLEnd; ++WLIdx) {
1112243830Sdim    MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx];
1113243830Sdim    OS << "  {" << format("%2d", WLEntry.Cycles) << ", "
1114243830Sdim       << format("%2d", WLEntry.WriteResourceID) << "}";
1115243830Sdim    if (WLIdx + 1 < WLEnd)
1116243830Sdim      OS << ',';
1117243830Sdim    OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n';
1118243830Sdim  }
1119243830Sdim  OS << "}; // " << Target << "WriteLatencyTable\n";
1120243830Sdim
1121243830Sdim  // Emit global ReadAdvanceTable.
1122243830Sdim  OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
1123243830Sdim     << "extern const llvm::MCReadAdvanceEntry "
1124243830Sdim     << Target << "ReadAdvanceTable[] = {\n"
1125243830Sdim     << "  {0,  0,  0}, // Invalid\n";
1126243830Sdim  for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
1127243830Sdim       RAIdx != RAEnd; ++RAIdx) {
1128243830Sdim    MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx];
1129243830Sdim    OS << "  {" << RAEntry.UseIdx << ", "
1130243830Sdim       << format("%2d", RAEntry.WriteResourceID) << ", "
1131243830Sdim       << format("%2d", RAEntry.Cycles) << "}";
1132243830Sdim    if (RAIdx + 1 < RAEnd)
1133243830Sdim      OS << ',';
1134243830Sdim    OS << " // #" << RAIdx << '\n';
1135243830Sdim  }
1136243830Sdim  OS << "}; // " << Target << "ReadAdvanceTable\n";
1137243830Sdim
1138243830Sdim  // Emit a SchedClass table for each processor.
1139243830Sdim  for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1140243830Sdim         PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1141243830Sdim    if (!PI->hasInstrSchedModel())
1142243830Sdim      continue;
1143243830Sdim
1144243830Sdim    std::vector<MCSchedClassDesc> &SCTab =
1145243830Sdim      SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
1146243830Sdim
1147243830Sdim    OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup,"
1148243830Sdim       << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
1149243830Sdim    OS << "static const llvm::MCSchedClassDesc "
1150243830Sdim       << PI->ModelName << "SchedClasses[] = {\n";
1151243830Sdim
1152243830Sdim    // The first class is always invalid. We no way to distinguish it except by
1153243830Sdim    // name and position.
1154249423Sdim    assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
1155243830Sdim           && "invalid class not first");
1156243830Sdim    OS << "  {DBGFIELD(\"InvalidSchedClass\")  "
1157243830Sdim       << MCSchedClassDesc::InvalidNumMicroOps
1158243830Sdim       << ", 0, 0,  0, 0,  0, 0,  0, 0},\n";
1159243830Sdim
1160243830Sdim    for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
1161243830Sdim      MCSchedClassDesc &MCDesc = SCTab[SCIdx];
1162243830Sdim      const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
1163243830Sdim      OS << "  {DBGFIELD(\"" << SchedClass.Name << "\") ";
1164243830Sdim      if (SchedClass.Name.size() < 18)
1165243830Sdim        OS.indent(18 - SchedClass.Name.size());
1166243830Sdim      OS << MCDesc.NumMicroOps
1167243830Sdim         << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup
1168243830Sdim         << ", " << format("%2d", MCDesc.WriteProcResIdx)
1169243830Sdim         << ", " << MCDesc.NumWriteProcResEntries
1170243830Sdim         << ", " << format("%2d", MCDesc.WriteLatencyIdx)
1171243830Sdim         << ", " << MCDesc.NumWriteLatencyEntries
1172243830Sdim         << ", " << format("%2d", MCDesc.ReadAdvanceIdx)
1173243830Sdim         << ", " << MCDesc.NumReadAdvanceEntries << "}";
1174243830Sdim      if (SCIdx + 1 < SCEnd)
1175243830Sdim        OS << ',';
1176243830Sdim      OS << " // #" << SCIdx << '\n';
1177243830Sdim    }
1178243830Sdim    OS << "}; // " << PI->ModelName << "SchedClasses\n";
1179243830Sdim  }
1180243830Sdim}
1181243830Sdim
1182239462Sdimvoid SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
1183239462Sdim  // For each processor model.
1184239462Sdim  for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1185239462Sdim         PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1186243830Sdim    // Emit processor resource table.
1187243830Sdim    if (PI->hasInstrSchedModel())
1188243830Sdim      EmitProcessorResources(*PI, OS);
1189243830Sdim    else if(!PI->ProcResourceDefs.empty())
1190243830Sdim      PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines "
1191243830Sdim                    "ProcResources without defining WriteRes SchedWriteRes");
1192243830Sdim
1193239462Sdim    // Begin processor itinerary properties
1194239462Sdim    OS << "\n";
1195239462Sdim    OS << "static const llvm::MCSchedModel " << PI->ModelName << "(\n";
1196239462Sdim    EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ',');
1197263508Sdim    EmitProcessorProp(OS, PI->ModelDef, "MicroOpBufferSize", ',');
1198239462Sdim    EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ',');
1199239462Sdim    EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ',');
1200239462Sdim    EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ',');
1201263508Sdim
1202263508Sdim    OS << "  " << (bool)(PI->ModelDef ?
1203263508Sdim                         PI->ModelDef->getValueAsBit("CompleteModel") : 0)
1204263508Sdim       << ", // " << "CompleteModel\n";
1205263508Sdim
1206243830Sdim    OS << "  " << PI->Index << ", // Processor ID\n";
1207243830Sdim    if (PI->hasInstrSchedModel())
1208243830Sdim      OS << "  " << PI->ModelName << "ProcResources" << ",\n"
1209243830Sdim         << "  " << PI->ModelName << "SchedClasses" << ",\n"
1210243830Sdim         << "  " << PI->ProcResourceDefs.size()+1 << ",\n"
1211243830Sdim         << "  " << (SchedModels.schedClassEnd()
1212243830Sdim                     - SchedModels.schedClassBegin()) << ",\n";
1213243830Sdim    else
1214243830Sdim      OS << "  0, 0, 0, 0, // No instruction-level machine model.\n";
1215249423Sdim    if (SchedModels.hasItineraries())
1216243830Sdim      OS << "  " << PI->ItinsDef->getName() << ");\n";
1217239462Sdim    else
1218243830Sdim      OS << "  0); // No Itinerary\n";
1219239462Sdim  }
1220239462Sdim}
1221239462Sdim
1222193323Sed//
1223193323Sed// EmitProcessorLookup - generate cpu name to itinerary lookup table.
1224193323Sed//
1225195340Sedvoid SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
1226193323Sed  // Gather and sort processor information
1227193323Sed  std::vector<Record*> ProcessorList =
1228193323Sed                          Records.getAllDerivedDefinitions("Processor");
1229193323Sed  std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
1230193323Sed
1231193323Sed  // Begin processor table
1232193323Sed  OS << "\n";
1233193323Sed  OS << "// Sorted (by key) array of itineraries for CPU subtype.\n"
1234234353Sdim     << "extern const llvm::SubtargetInfoKV "
1235239462Sdim     << Target << "ProcSchedKV[] = {\n";
1236221345Sdim
1237193323Sed  // For each processor
1238193323Sed  for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
1239193323Sed    // Next processor
1240193323Sed    Record *Processor = ProcessorList[i];
1241193323Sed
1242193323Sed    const std::string &Name = Processor->getValueAsString("Name");
1243239462Sdim    const std::string &ProcModelName =
1244243830Sdim      SchedModels.getModelForProc(Processor).ModelName;
1245221345Sdim
1246193323Sed    // Emit as { "cpu", procinit },
1247243830Sdim    OS << "  { \"" << Name << "\", (const void *)&" << ProcModelName << " }";
1248221345Sdim
1249193323Sed    // Depending on ''if more in the list'' emit comma
1250193323Sed    if (++i < N) OS << ",";
1251221345Sdim
1252193323Sed    OS << "\n";
1253193323Sed  }
1254221345Sdim
1255193323Sed  // End processor table
1256193323Sed  OS << "};\n";
1257193323Sed}
1258193323Sed
1259193323Sed//
1260239462Sdim// EmitSchedModel - Emits all scheduling model tables, folding common patterns.
1261193323Sed//
1262239462Sdimvoid SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
1263243830Sdim  OS << "#ifdef DBGFIELD\n"
1264243830Sdim     << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n"
1265243830Sdim     << "#endif\n"
1266243830Sdim     << "#ifndef NDEBUG\n"
1267243830Sdim     << "#define DBGFIELD(x) x,\n"
1268243830Sdim     << "#else\n"
1269243830Sdim     << "#define DBGFIELD(x)\n"
1270243830Sdim     << "#endif\n";
1271243830Sdim
1272249423Sdim  if (SchedModels.hasItineraries()) {
1273239462Sdim    std::vector<std::vector<InstrItinerary> > ProcItinLists;
1274193323Sed    // Emit the stage data
1275239462Sdim    EmitStageAndOperandCycleData(OS, ProcItinLists);
1276239462Sdim    EmitItineraries(OS, ProcItinLists);
1277193323Sed  }
1278243830Sdim  OS << "\n// ===============================================================\n"
1279243830Sdim     << "// Data tables for the new per-operand machine model.\n";
1280243830Sdim
1281243830Sdim  SchedClassTables SchedTables;
1282243830Sdim  for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
1283243830Sdim         PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
1284243830Sdim    GenSchedClassTables(*PI, SchedTables);
1285243830Sdim  }
1286243830Sdim  EmitSchedClassTables(SchedTables, OS);
1287243830Sdim
1288239462Sdim  // Emit the processor machine model
1289239462Sdim  EmitProcessorModels(OS);
1290239462Sdim  // Emit the processor lookup data
1291239462Sdim  EmitProcessorLookup(OS);
1292243830Sdim
1293243830Sdim  OS << "#undef DBGFIELD";
1294193323Sed}
1295193323Sed
1296243830Sdimvoid SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
1297243830Sdim                                             raw_ostream &OS) {
1298243830Sdim  OS << "unsigned " << ClassName
1299243830Sdim     << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"
1300243830Sdim     << " const TargetSchedModel *SchedModel) const {\n";
1301243830Sdim
1302243830Sdim  std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog");
1303243830Sdim  std::sort(Prologs.begin(), Prologs.end(), LessRecord());
1304243830Sdim  for (std::vector<Record*>::const_iterator
1305243830Sdim         PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) {
1306243830Sdim    OS << (*PI)->getValueAsString("Code") << '\n';
1307243830Sdim  }
1308243830Sdim  IdxVec VariantClasses;
1309243830Sdim  for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(),
1310243830Sdim         SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
1311243830Sdim    if (SCI->Transitions.empty())
1312243830Sdim      continue;
1313249423Sdim    VariantClasses.push_back(SCI->Index);
1314243830Sdim  }
1315243830Sdim  if (!VariantClasses.empty()) {
1316243830Sdim    OS << "  switch (SchedClass) {\n";
1317243830Sdim    for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end();
1318243830Sdim         VCI != VCE; ++VCI) {
1319243830Sdim      const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI);
1320243830Sdim      OS << "  case " << *VCI << ": // " << SC.Name << '\n';
1321243830Sdim      IdxVec ProcIndices;
1322243830Sdim      for (std::vector<CodeGenSchedTransition>::const_iterator
1323243830Sdim             TI = SC.Transitions.begin(), TE = SC.Transitions.end();
1324243830Sdim           TI != TE; ++TI) {
1325243830Sdim        IdxVec PI;
1326243830Sdim        std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(),
1327243830Sdim                       ProcIndices.begin(), ProcIndices.end(),
1328243830Sdim                       std::back_inserter(PI));
1329243830Sdim        ProcIndices.swap(PI);
1330243830Sdim      }
1331243830Sdim      for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end();
1332243830Sdim           PI != PE; ++PI) {
1333243830Sdim        OS << "    ";
1334243830Sdim        if (*PI != 0)
1335243830Sdim          OS << "if (SchedModel->getProcessorID() == " << *PI << ") ";
1336243830Sdim        OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName
1337243830Sdim           << '\n';
1338243830Sdim        for (std::vector<CodeGenSchedTransition>::const_iterator
1339243830Sdim               TI = SC.Transitions.begin(), TE = SC.Transitions.end();
1340243830Sdim             TI != TE; ++TI) {
1341243830Sdim          if (*PI != 0 && !std::count(TI->ProcIndices.begin(),
1342243830Sdim                                      TI->ProcIndices.end(), *PI)) {
1343243830Sdim              continue;
1344243830Sdim          }
1345263508Sdim          OS << "      if (";
1346243830Sdim          for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end();
1347243830Sdim               RI != RE; ++RI) {
1348243830Sdim            if (RI != TI->PredTerm.begin())
1349243830Sdim              OS << "\n          && ";
1350243830Sdim            OS << "(" << (*RI)->getValueAsString("Predicate") << ")";
1351243830Sdim          }
1352243830Sdim          OS << ")\n"
1353243830Sdim             << "        return " << TI->ToClassIdx << "; // "
1354243830Sdim             << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n';
1355243830Sdim        }
1356243830Sdim        OS << "    }\n";
1357243830Sdim        if (*PI == 0)
1358243830Sdim          break;
1359243830Sdim      }
1360249423Sdim      if (SC.isInferred())
1361249423Sdim        OS << "    return " << SC.Index << ";\n";
1362243830Sdim      OS << "    break;\n";
1363243830Sdim    }
1364243830Sdim    OS << "  };\n";
1365243830Sdim  }
1366243830Sdim  OS << "  report_fatal_error(\"Expected a variant SchedClass\");\n"
1367243830Sdim     << "} // " << ClassName << "::resolveSchedClass\n";
1368243830Sdim}
1369243830Sdim
1370193323Sed//
1371193323Sed// ParseFeaturesFunction - Produces a subtarget specific function for parsing
1372193323Sed// the subtarget features string.
1373193323Sed//
1374224145Sdimvoid SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
1375224145Sdim                                             unsigned NumFeatures,
1376224145Sdim                                             unsigned NumProcs) {
1377193323Sed  std::vector<Record*> Features =
1378193323Sed                       Records.getAllDerivedDefinitions("SubtargetFeature");
1379193323Sed  std::sort(Features.begin(), Features.end(), LessRecord());
1380193323Sed
1381221345Sdim  OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
1382221345Sdim     << "// subtarget options.\n"
1383224145Sdim     << "void llvm::";
1384193323Sed  OS << Target;
1385224145Sdim  OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n"
1386202375Srdivacky     << "  DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
1387239462Sdim     << "  DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n";
1388193323Sed
1389224145Sdim  if (Features.empty()) {
1390224145Sdim    OS << "}\n";
1391224145Sdim    return;
1392224145Sdim  }
1393224145Sdim
1394243830Sdim  OS << "  InitMCProcessorInfo(CPU, FS);\n"
1395243830Sdim     << "  uint64_t Bits = getFeatureBits();\n";
1396224145Sdim
1397193323Sed  for (unsigned i = 0; i < Features.size(); i++) {
1398193323Sed    // Next record
1399193323Sed    Record *R = Features[i];
1400193323Sed    const std::string &Instance = R->getName();
1401193323Sed    const std::string &Value = R->getValueAsString("Value");
1402193323Sed    const std::string &Attribute = R->getValueAsString("Attribute");
1403193323Sed
1404193323Sed    if (Value=="true" || Value=="false")
1405224145Sdim      OS << "  if ((Bits & " << Target << "::"
1406224145Sdim         << Instance << ") != 0) "
1407193323Sed         << Attribute << " = " << Value << ";\n";
1408193323Sed    else
1409224145Sdim      OS << "  if ((Bits & " << Target << "::"
1410224145Sdim         << Instance << ") != 0 && "
1411224145Sdim         << Attribute << " < " << Value << ") "
1412224145Sdim         << Attribute << " = " << Value << ";\n";
1413193323Sed  }
1414193323Sed
1415224145Sdim  OS << "}\n";
1416193323Sed}
1417193323Sed
1418193323Sed//
1419193323Sed// SubtargetEmitter::run - Main subtarget enumeration emitter.
1420193323Sed//
1421195340Sedvoid SubtargetEmitter::run(raw_ostream &OS) {
1422239462Sdim  emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
1423193323Sed
1424224145Sdim  OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
1425224145Sdim  OS << "#undef GET_SUBTARGETINFO_ENUM\n";
1426224145Sdim
1427224145Sdim  OS << "namespace llvm {\n";
1428224145Sdim  Enumeration(OS, "SubtargetFeature", true);
1429224145Sdim  OS << "} // End llvm namespace \n";
1430224145Sdim  OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
1431224145Sdim
1432224145Sdim  OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
1433224145Sdim  OS << "#undef GET_SUBTARGETINFO_MC_DESC\n";
1434224145Sdim
1435224145Sdim  OS << "namespace llvm {\n";
1436224145Sdim#if 0
1437224145Sdim  OS << "namespace {\n";
1438224145Sdim#endif
1439224145Sdim  unsigned NumFeatures = FeatureKeyValues(OS);
1440224145Sdim  OS << "\n";
1441224145Sdim  unsigned NumProcs = CPUKeyValues(OS);
1442224145Sdim  OS << "\n";
1443239462Sdim  EmitSchedModel(OS);
1444224145Sdim  OS << "\n";
1445224145Sdim#if 0
1446224145Sdim  OS << "}\n";
1447224145Sdim#endif
1448224145Sdim
1449224145Sdim  // MCInstrInfo initialization routine.
1450224145Sdim  OS << "static inline void Init" << Target
1451224145Sdim     << "MCSubtargetInfo(MCSubtargetInfo *II, "
1452224145Sdim     << "StringRef TT, StringRef CPU, StringRef FS) {\n";
1453224145Sdim  OS << "  II->InitMCSubtargetInfo(TT, CPU, FS, ";
1454224145Sdim  if (NumFeatures)
1455224145Sdim    OS << Target << "FeatureKV, ";
1456224145Sdim  else
1457224145Sdim    OS << "0, ";
1458224145Sdim  if (NumProcs)
1459224145Sdim    OS << Target << "SubTypeKV, ";
1460224145Sdim  else
1461224145Sdim    OS << "0, ";
1462243830Sdim  OS << '\n'; OS.indent(22);
1463243830Sdim  OS << Target << "ProcSchedKV, "
1464243830Sdim     << Target << "WriteProcResTable, "
1465243830Sdim     << Target << "WriteLatencyTable, "
1466243830Sdim     << Target << "ReadAdvanceTable, ";
1467249423Sdim  if (SchedModels.hasItineraries()) {
1468243830Sdim    OS << '\n'; OS.indent(22);
1469243830Sdim    OS << Target << "Stages, "
1470224145Sdim       << Target << "OperandCycles, "
1471239462Sdim       << Target << "ForwardingPaths, ";
1472224145Sdim  } else
1473243830Sdim    OS << "0, 0, 0, ";
1474224145Sdim  OS << NumFeatures << ", " << NumProcs << ");\n}\n\n";
1475224145Sdim
1476224145Sdim  OS << "} // End llvm namespace \n";
1477224145Sdim
1478224145Sdim  OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
1479224145Sdim
1480224145Sdim  OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
1481224145Sdim  OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n";
1482224145Sdim
1483199481Srdivacky  OS << "#include \"llvm/Support/Debug.h\"\n";
1484199481Srdivacky  OS << "#include \"llvm/Support/raw_ostream.h\"\n";
1485224145Sdim  ParseFeaturesFunction(OS, NumFeatures, NumProcs);
1486207618Srdivacky
1487224145Sdim  OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
1488224145Sdim
1489224145Sdim  // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
1490224145Sdim  OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
1491224145Sdim  OS << "#undef GET_SUBTARGETINFO_HEADER\n";
1492224145Sdim
1493224145Sdim  std::string ClassName = Target + "GenSubtargetInfo";
1494224145Sdim  OS << "namespace llvm {\n";
1495234353Sdim  OS << "class DFAPacketizer;\n";
1496224145Sdim  OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
1497224145Sdim     << "  explicit " << ClassName << "(StringRef TT, StringRef CPU, "
1498224145Sdim     << "StringRef FS);\n"
1499234353Sdim     << "public:\n"
1500243830Sdim     << "  unsigned resolveSchedClass(unsigned SchedClass, const MachineInstr *DefMI,"
1501243830Sdim     << " const TargetSchedModel *SchedModel) const;\n"
1502234353Sdim     << "  DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
1503234353Sdim     << " const;\n"
1504224145Sdim     << "};\n";
1505224145Sdim  OS << "} // End llvm namespace \n";
1506224145Sdim
1507224145Sdim  OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
1508224145Sdim
1509224145Sdim  OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
1510224145Sdim  OS << "#undef GET_SUBTARGETINFO_CTOR\n";
1511224145Sdim
1512243830Sdim  OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n";
1513224145Sdim  OS << "namespace llvm {\n";
1514234353Sdim  OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
1515234353Sdim  OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n";
1516243830Sdim  OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n";
1517243830Sdim  OS << "extern const llvm::MCWriteProcResEntry "
1518243830Sdim     << Target << "WriteProcResTable[];\n";
1519243830Sdim  OS << "extern const llvm::MCWriteLatencyEntry "
1520243830Sdim     << Target << "WriteLatencyTable[];\n";
1521243830Sdim  OS << "extern const llvm::MCReadAdvanceEntry "
1522243830Sdim     << Target << "ReadAdvanceTable[];\n";
1523243830Sdim
1524249423Sdim  if (SchedModels.hasItineraries()) {
1525234353Sdim    OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
1526234353Sdim    OS << "extern const unsigned " << Target << "OperandCycles[];\n";
1527239462Sdim    OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
1528224145Sdim  }
1529224145Sdim
1530224145Sdim  OS << ClassName << "::" << ClassName << "(StringRef TT, StringRef CPU, "
1531224145Sdim     << "StringRef FS)\n"
1532224145Sdim     << "  : TargetSubtargetInfo() {\n"
1533224145Sdim     << "  InitMCSubtargetInfo(TT, CPU, FS, ";
1534224145Sdim  if (NumFeatures)
1535224145Sdim    OS << Target << "FeatureKV, ";
1536224145Sdim  else
1537224145Sdim    OS << "0, ";
1538224145Sdim  if (NumProcs)
1539224145Sdim    OS << Target << "SubTypeKV, ";
1540224145Sdim  else
1541224145Sdim    OS << "0, ";
1542243830Sdim  OS << '\n'; OS.indent(22);
1543243830Sdim  OS << Target << "ProcSchedKV, "
1544243830Sdim     << Target << "WriteProcResTable, "
1545243830Sdim     << Target << "WriteLatencyTable, "
1546243830Sdim     << Target << "ReadAdvanceTable, ";
1547243830Sdim  OS << '\n'; OS.indent(22);
1548249423Sdim  if (SchedModels.hasItineraries()) {
1549243830Sdim    OS << Target << "Stages, "
1550224145Sdim       << Target << "OperandCycles, "
1551239462Sdim       << Target << "ForwardingPaths, ";
1552224145Sdim  } else
1553243830Sdim    OS << "0, 0, 0, ";
1554224145Sdim  OS << NumFeatures << ", " << NumProcs << ");\n}\n\n";
1555243830Sdim
1556243830Sdim  EmitSchedModelHelpers(ClassName, OS);
1557243830Sdim
1558224145Sdim  OS << "} // End llvm namespace \n";
1559224145Sdim
1560224145Sdim  OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
1561193323Sed}
1562239462Sdim
1563239462Sdimnamespace llvm {
1564239462Sdim
1565239462Sdimvoid EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
1566239462Sdim  CodeGenTarget CGTarget(RK);
1567239462Sdim  SubtargetEmitter(RK, CGTarget).run(OS);
1568239462Sdim}
1569239462Sdim
1570239462Sdim} // End llvm namespace
1571