1 //===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
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 a generic array initialized by specified fields,
10 // together with companion index tables and lookup functions (binary search,
11 // currently).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "CodeGenIntrinsics.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/TableGen/Error.h"
21 #include "llvm/TableGen/Record.h"
22 #include <algorithm>
23 #include <set>
24 #include <string>
25 #include <vector>
26 
27 using namespace llvm;
28 
29 #define DEBUG_TYPE "searchable-table-emitter"
30 
31 namespace {
32 
getAsInt(Init * B)33 int getAsInt(Init *B) {
34   return cast<IntInit>(
35              B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper())))
36       ->getValue();
37 }
getInt(Record * R,StringRef Field)38 int getInt(Record *R, StringRef Field) {
39   return getAsInt(R->getValueInit(Field));
40 }
41 
42 struct GenericEnum {
43   using Entry = std::pair<StringRef, int64_t>;
44 
45   std::string Name;
46   Record *Class = nullptr;
47   std::string PreprocessorGuard;
48   std::vector<std::unique_ptr<Entry>> Entries;
49   DenseMap<Record *, Entry *> EntryMap;
50 };
51 
52 struct GenericField {
53   std::string Name;
54   RecTy *RecType = nullptr;
55   bool IsCode = false;
56   bool IsIntrinsic = false;
57   bool IsInstruction = false;
58   GenericEnum *Enum = nullptr;
59 
GenericField__anonf7e9f2940111::GenericField60   GenericField(StringRef Name) : Name(std::string(Name)) {}
61 };
62 
63 struct SearchIndex {
64   std::string Name;
65   SMLoc Loc; // Source location of PrimaryKey or Key field definition.
66   SmallVector<GenericField, 1> Fields;
67   bool EarlyOut = false;
68 };
69 
70 struct GenericTable {
71   std::string Name;
72   ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
73   std::string PreprocessorGuard;
74   std::string CppTypeName;
75   SmallVector<GenericField, 2> Fields;
76   std::vector<Record *> Entries;
77 
78   std::unique_ptr<SearchIndex> PrimaryKey;
79   SmallVector<std::unique_ptr<SearchIndex>, 2> Indices;
80 
getFieldByName__anonf7e9f2940111::GenericTable81   const GenericField *getFieldByName(StringRef Name) const {
82     for (const auto &Field : Fields) {
83       if (Name == Field.Name)
84         return &Field;
85     }
86     return nullptr;
87   }
88 };
89 
90 class SearchableTableEmitter {
91   RecordKeeper &Records;
92   DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;
93   std::vector<std::unique_ptr<GenericEnum>> Enums;
94   DenseMap<Record *, GenericEnum *> EnumMap;
95   std::set<std::string> PreprocessorGuards;
96 
97 public:
SearchableTableEmitter(RecordKeeper & R)98   SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
99 
100   void run(raw_ostream &OS);
101 
102 private:
103   typedef std::pair<Init *, int> SearchTableEntry;
104 
105   enum TypeContext {
106     TypeInStaticStruct,
107     TypeInTempStruct,
108     TypeInArgument,
109   };
110 
primaryRepresentation(SMLoc Loc,const GenericField & Field,Init * I)111   std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
112                                     Init *I) {
113     if (StringInit *SI = dyn_cast<StringInit>(I)) {
114       if (Field.IsCode || SI->hasCodeFormat())
115         return std::string(SI->getValue());
116       else
117         return SI->getAsString();
118     } else if (BitsInit *BI = dyn_cast<BitsInit>(I))
119       return "0x" + utohexstr(getAsInt(BI));
120     else if (BitInit *BI = dyn_cast<BitInit>(I))
121       return BI->getValue() ? "true" : "false";
122     else if (Field.IsIntrinsic)
123       return "Intrinsic::" + getIntrinsic(I).EnumName;
124     else if (Field.IsInstruction)
125       return I->getAsString();
126     else if (Field.Enum) {
127       auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
128       if (!Entry)
129         PrintFatalError(Loc,
130                         Twine("Entry for field '") + Field.Name + "' is null");
131       return std::string(Entry->first);
132     }
133     PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
134                              "'; expected: bit, bits, string, or code");
135   }
136 
isIntrinsic(Init * I)137   bool isIntrinsic(Init *I) {
138     if (DefInit *DI = dyn_cast<DefInit>(I))
139       return DI->getDef()->isSubClassOf("Intrinsic");
140     return false;
141   }
142 
getIntrinsic(Init * I)143   CodeGenIntrinsic &getIntrinsic(Init *I) {
144     std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
145     if (!Intr)
146       Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),
147                                                 std::vector<Record *>());
148     return *Intr;
149   }
150 
151   bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
152 
searchableFieldType(const GenericTable & Table,const SearchIndex & Index,const GenericField & Field,TypeContext Ctx)153   std::string searchableFieldType(const GenericTable &Table,
154                                   const SearchIndex &Index,
155                                   const GenericField &Field, TypeContext Ctx) {
156     if (isa<StringRecTy>(Field.RecType)) {
157       if (Ctx == TypeInStaticStruct)
158         return "const char *";
159       if (Ctx == TypeInTempStruct)
160         return "std::string";
161       return "StringRef";
162     } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
163       unsigned NumBits = BI->getNumBits();
164       if (NumBits <= 8)
165         return "uint8_t";
166       if (NumBits <= 16)
167         return "uint16_t";
168       if (NumBits <= 32)
169         return "uint32_t";
170       if (NumBits <= 64)
171         return "uint64_t";
172       PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
173                                      "' lookup method '" + Index.Name +
174                                      "', key field '" + Field.Name +
175                                      "' of type bits is too large");
176     } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
177       return "unsigned";
178     PrintFatalError(Index.Loc,
179                     Twine("In table '") + Table.Name + "' lookup method '" +
180                         Index.Name + "', key field '" + Field.Name +
181                         "' has invalid type: " + Field.RecType->getAsString());
182   }
183 
184   void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
185   void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
186   void emitLookupDeclaration(const GenericTable &Table,
187                              const SearchIndex &Index, raw_ostream &OS);
188   void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
189                           bool IsPrimary, raw_ostream &OS);
190   void emitIfdef(StringRef Guard, raw_ostream &OS);
191 
192   bool parseFieldType(GenericField &Field, Init *II);
193   std::unique_ptr<SearchIndex>
194   parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
195                    const std::vector<StringRef> &Key, bool EarlyOut);
196   void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
197                           StringRef ValueField,
198                           const std::vector<Record *> &Items);
199   void collectTableEntries(GenericTable &Table,
200                            const std::vector<Record *> &Items);
201 };
202 
203 } // End anonymous namespace.
204 
205 // For search indices that consists of a single field whose numeric value is
206 // known, return that numeric value.
getNumericKey(const SearchIndex & Index,Record * Rec)207 static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
208   assert(Index.Fields.size() == 1);
209 
210   if (Index.Fields[0].Enum) {
211     Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);
212     return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;
213   }
214 
215   return getInt(Rec, Index.Fields[0].Name);
216 }
217 
218 /// Less-than style comparison between \p LHS and \p RHS according to the
219 /// key of \p Index.
compareBy(Record * LHS,Record * RHS,const SearchIndex & Index)220 bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
221                                        const SearchIndex &Index) {
222   for (const auto &Field : Index.Fields) {
223     Init *LHSI = LHS->getValueInit(Field.Name);
224     Init *RHSI = RHS->getValueInit(Field.Name);
225 
226     if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) {
227       int64_t LHSi = getAsInt(LHSI);
228       int64_t RHSi = getAsInt(RHSI);
229       if (LHSi < RHSi)
230         return true;
231       if (LHSi > RHSi)
232         return false;
233     } else if (Field.IsIntrinsic) {
234       CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);
235       CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);
236       if (std::tie(LHSi.TargetPrefix, LHSi.Name) <
237           std::tie(RHSi.TargetPrefix, RHSi.Name))
238         return true;
239       if (std::tie(LHSi.TargetPrefix, LHSi.Name) >
240           std::tie(RHSi.TargetPrefix, RHSi.Name))
241         return false;
242     } else if (Field.IsInstruction) {
243       // This does not correctly compare the predefined instructions!
244       Record *LHSr = cast<DefInit>(LHSI)->getDef();
245       Record *RHSr = cast<DefInit>(RHSI)->getDef();
246 
247       bool LHSpseudo = LHSr->getValueAsBit("isPseudo");
248       bool RHSpseudo = RHSr->getValueAsBit("isPseudo");
249       if (LHSpseudo && !RHSpseudo)
250         return true;
251       if (!LHSpseudo && RHSpseudo)
252         return false;
253 
254       int comp = LHSr->getName().compare(RHSr->getName());
255       if (comp < 0)
256         return true;
257       if (comp > 0)
258         return false;
259     } else if (Field.Enum) {
260       auto LHSr = cast<DefInit>(LHSI)->getDef();
261       auto RHSr = cast<DefInit>(RHSI)->getDef();
262       int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
263       int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
264       if (LHSv < RHSv)
265         return true;
266       if (LHSv > RHSv)
267         return false;
268     } else {
269       std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);
270       std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);
271 
272       if (isa<StringRecTy>(Field.RecType)) {
273         LHSs = StringRef(LHSs).upper();
274         RHSs = StringRef(RHSs).upper();
275       }
276 
277       int comp = LHSs.compare(RHSs);
278       if (comp < 0)
279         return true;
280       if (comp > 0)
281         return false;
282     }
283   }
284   return false;
285 }
286 
emitIfdef(StringRef Guard,raw_ostream & OS)287 void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {
288   OS << "#ifdef " << Guard << "\n";
289   PreprocessorGuards.insert(std::string(Guard));
290 }
291 
292 /// Emit a generic enum.
emitGenericEnum(const GenericEnum & Enum,raw_ostream & OS)293 void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
294                                              raw_ostream &OS) {
295   emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
296 
297   OS << "enum " << Enum.Name << " {\n";
298   for (const auto &Entry : Enum.Entries)
299     OS << "  " << Entry->first << " = " << Entry->second << ",\n";
300   OS << "};\n";
301 
302   OS << "#endif\n\n";
303 }
304 
emitLookupFunction(const GenericTable & Table,const SearchIndex & Index,bool IsPrimary,raw_ostream & OS)305 void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
306                                                 const SearchIndex &Index,
307                                                 bool IsPrimary,
308                                                 raw_ostream &OS) {
309   OS << "\n";
310   emitLookupDeclaration(Table, Index, OS);
311   OS << " {\n";
312 
313   std::vector<Record *> IndexRowsStorage;
314   ArrayRef<Record *> IndexRows;
315   StringRef IndexTypeName;
316   StringRef IndexName;
317 
318   if (IsPrimary) {
319     IndexTypeName = Table.CppTypeName;
320     IndexName = Table.Name;
321     IndexRows = Table.Entries;
322   } else {
323     OS << "  struct IndexType {\n";
324     for (const auto &Field : Index.Fields) {
325       OS << "    "
326          << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "
327          << Field.Name << ";\n";
328     }
329     OS << "    unsigned _index;\n";
330     OS << "  };\n";
331 
332     OS << "  static const struct IndexType Index[] = {\n";
333 
334     std::vector<std::pair<Record *, unsigned>> Entries;
335     Entries.reserve(Table.Entries.size());
336     for (unsigned i = 0; i < Table.Entries.size(); ++i)
337       Entries.emplace_back(Table.Entries[i], i);
338 
339     llvm::stable_sort(Entries, [&](const std::pair<Record *, unsigned> &LHS,
340                                    const std::pair<Record *, unsigned> &RHS) {
341       return compareBy(LHS.first, RHS.first, Index);
342     });
343 
344     IndexRowsStorage.reserve(Entries.size());
345     for (const auto &Entry : Entries) {
346       IndexRowsStorage.push_back(Entry.first);
347 
348       OS << "    { ";
349       ListSeparator LS;
350       for (const auto &Field : Index.Fields) {
351         std::string Repr = primaryRepresentation(
352             Index.Loc, Field, Entry.first->getValueInit(Field.Name));
353         if (isa<StringRecTy>(Field.RecType))
354           Repr = StringRef(Repr).upper();
355         OS << LS << Repr;
356       }
357       OS << ", " << Entry.second << " },\n";
358     }
359 
360     OS << "  };\n\n";
361 
362     IndexTypeName = "IndexType";
363     IndexName = "Index";
364     IndexRows = IndexRowsStorage;
365   }
366 
367   bool IsContiguous = false;
368 
369   if (Index.Fields.size() == 1 &&
370       (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) {
371     IsContiguous = true;
372     for (unsigned i = 0; i < IndexRows.size(); ++i) {
373       if (getNumericKey(Index, IndexRows[i]) != i) {
374         IsContiguous = false;
375         break;
376       }
377     }
378   }
379 
380   if (IsContiguous) {
381     OS << "  auto Table = ArrayRef(" << IndexName << ");\n";
382     OS << "  size_t Idx = " << Index.Fields[0].Name << ";\n";
383     OS << "  return Idx >= Table.size() ? nullptr : ";
384     if (IsPrimary)
385       OS << "&Table[Idx]";
386     else
387       OS << "&" << Table.Name << "[Table[Idx]._index]";
388     OS << ";\n";
389     OS << "}\n";
390     return;
391   }
392 
393   if (Index.EarlyOut) {
394     const GenericField &Field = Index.Fields[0];
395     std::string FirstRepr = primaryRepresentation(
396         Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));
397     std::string LastRepr = primaryRepresentation(
398         Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));
399     OS << "  if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
400     OS << "      (" << Field.Name << " > " << LastRepr << "))\n";
401     OS << "    return nullptr;\n\n";
402   }
403 
404   OS << "  struct KeyType {\n";
405   for (const auto &Field : Index.Fields) {
406     OS << "    " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
407        << " " << Field.Name << ";\n";
408   }
409   OS << "  };\n";
410   OS << "  KeyType Key = {";
411   ListSeparator LS;
412   for (const auto &Field : Index.Fields) {
413     OS << LS << Field.Name;
414     if (isa<StringRecTy>(Field.RecType)) {
415       OS << ".upper()";
416       if (IsPrimary)
417         PrintFatalError(Index.Loc,
418                         Twine("In table '") + Table.Name +
419                             "', use a secondary lookup method for "
420                             "case-insensitive comparison of field '" +
421                             Field.Name + "'");
422     }
423   }
424   OS << "};\n";
425 
426   OS << "  auto Table = ArrayRef(" << IndexName << ");\n";
427   OS << "  auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
428   OS << "    [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
429 
430   for (const auto &Field : Index.Fields) {
431     if (isa<StringRecTy>(Field.RecType)) {
432       OS << "      int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
433          << ").compare(RHS." << Field.Name << ");\n";
434       OS << "      if (Cmp" << Field.Name << " < 0) return true;\n";
435       OS << "      if (Cmp" << Field.Name << " > 0) return false;\n";
436     } else if (Field.Enum) {
437       // Explicitly cast to unsigned, because the signedness of enums is
438       // compiler-dependent.
439       OS << "      if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
440          << Field.Name << ")\n";
441       OS << "        return true;\n";
442       OS << "      if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
443          << Field.Name << ")\n";
444       OS << "        return false;\n";
445     } else {
446       OS << "      if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
447       OS << "        return true;\n";
448       OS << "      if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
449       OS << "        return false;\n";
450     }
451   }
452 
453   OS << "      return false;\n";
454   OS << "    });\n\n";
455 
456   OS << "  if (Idx == Table.end()";
457 
458   for (const auto &Field : Index.Fields)
459     OS << " ||\n      Key." << Field.Name << " != Idx->" << Field.Name;
460   OS << ")\n    return nullptr;\n";
461 
462   if (IsPrimary)
463     OS << "  return &*Idx;\n";
464   else
465     OS << "  return &" << Table.Name << "[Idx->_index];\n";
466 
467   OS << "}\n";
468 }
469 
emitLookupDeclaration(const GenericTable & Table,const SearchIndex & Index,raw_ostream & OS)470 void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
471                                                    const SearchIndex &Index,
472                                                    raw_ostream &OS) {
473   OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
474 
475   ListSeparator LS;
476   for (const auto &Field : Index.Fields)
477     OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
478        << Field.Name;
479   OS << ")";
480 }
481 
emitGenericTable(const GenericTable & Table,raw_ostream & OS)482 void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
483                                               raw_ostream &OS) {
484   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);
485 
486   // Emit the declarations for the functions that will perform lookup.
487   if (Table.PrimaryKey) {
488     emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
489     OS << ";\n";
490   }
491   for (const auto &Index : Table.Indices) {
492     emitLookupDeclaration(Table, *Index, OS);
493     OS << ";\n";
494   }
495 
496   OS << "#endif\n\n";
497 
498   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
499 
500   // The primary data table contains all the fields defined for this map.
501   OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
502   for (unsigned i = 0; i < Table.Entries.size(); ++i) {
503     Record *Entry = Table.Entries[i];
504     OS << "  { ";
505 
506     ListSeparator LS;
507     for (const auto &Field : Table.Fields)
508       OS << LS
509          << primaryRepresentation(Table.Locs[0], Field,
510                                   Entry->getValueInit(Field.Name));
511 
512     OS << " }, // " << i << "\n";
513   }
514   OS << " };\n";
515 
516   // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
517   // search can be performed by "Thing".
518   if (Table.PrimaryKey)
519     emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
520   for (const auto &Index : Table.Indices)
521     emitLookupFunction(Table, *Index, false, OS);
522 
523   OS << "#endif\n\n";
524 }
525 
parseFieldType(GenericField & Field,Init * TypeOf)526 bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
527   if (auto Type = dyn_cast<StringInit>(TypeOf)) {
528     if (Type->getValue() == "code") {
529       Field.IsCode = true;
530       return true;
531     } else {
532       if (Record *TypeRec = Records.getDef(Type->getValue())) {
533         if (TypeRec->isSubClassOf("GenericEnum")) {
534           Field.Enum = EnumMap[TypeRec];
535           Field.RecType = RecordRecTy::get(Field.Enum->Class);
536           return true;
537         }
538       }
539     }
540   }
541 
542   return false;
543 }
544 
parseSearchIndex(GenericTable & Table,const RecordVal * KeyRecVal,StringRef Name,const std::vector<StringRef> & Key,bool EarlyOut)545 std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
546     GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
547     const std::vector<StringRef> &Key, bool EarlyOut) {
548   auto Index = std::make_unique<SearchIndex>();
549   Index->Name = std::string(Name);
550   Index->Loc = KeyRecVal->getLoc();
551   Index->EarlyOut = EarlyOut;
552 
553   for (const auto &FieldName : Key) {
554     const GenericField *Field = Table.getFieldByName(FieldName);
555     if (!Field)
556       PrintFatalError(
557           KeyRecVal,
558           Twine("In table '") + Table.Name +
559               "', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
560               FieldName + "'");
561 
562     Index->Fields.push_back(*Field);
563   }
564 
565   if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
566     PrintFatalError(
567         KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +
568                        "supported for a first key field of type string");
569   }
570 
571   return Index;
572 }
573 
collectEnumEntries(GenericEnum & Enum,StringRef NameField,StringRef ValueField,const std::vector<Record * > & Items)574 void SearchableTableEmitter::collectEnumEntries(
575     GenericEnum &Enum, StringRef NameField, StringRef ValueField,
576     const std::vector<Record *> &Items) {
577   for (auto *EntryRec : Items) {
578     StringRef Name;
579     if (NameField.empty())
580       Name = EntryRec->getName();
581     else
582       Name = EntryRec->getValueAsString(NameField);
583 
584     int64_t Value = 0;
585     if (!ValueField.empty())
586       Value = getInt(EntryRec, ValueField);
587 
588     Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));
589     Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
590   }
591 
592   if (ValueField.empty()) {
593     llvm::stable_sort(Enum.Entries,
594                       [](const std::unique_ptr<GenericEnum::Entry> &LHS,
595                          const std::unique_ptr<GenericEnum::Entry> &RHS) {
596                         return LHS->first < RHS->first;
597                       });
598 
599     for (size_t i = 0; i < Enum.Entries.size(); ++i)
600       Enum.Entries[i]->second = i;
601   }
602 }
603 
collectTableEntries(GenericTable & Table,const std::vector<Record * > & Items)604 void SearchableTableEmitter::collectTableEntries(
605     GenericTable &Table, const std::vector<Record *> &Items) {
606   if (Items.empty())
607     PrintFatalError(Table.Locs,
608                     Twine("Table '") + Table.Name + "' has no entries");
609 
610   for (auto *EntryRec : Items) {
611     for (auto &Field : Table.Fields) {
612       auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
613       if (!TI || !TI->isComplete()) {
614         PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +
615                                       "' for table '" + Table.Name +
616                                       "' is missing field '" + Field.Name +
617                                       "'");
618       }
619       if (!Field.RecType) {
620         Field.RecType = TI->getType();
621       } else {
622         RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
623         if (!Ty)
624           PrintFatalError(EntryRec->getValue(Field.Name),
625                           Twine("Field '") + Field.Name + "' of table '" +
626                           Table.Name + "' entry has incompatible type: " +
627                           TI->getType()->getAsString() + " vs. " +
628                           Field.RecType->getAsString());
629         Field.RecType = Ty;
630       }
631     }
632 
633     Table.Entries.push_back(EntryRec); // Add record to table's record list.
634   }
635 
636   Record *IntrinsicClass = Records.getClass("Intrinsic");
637   Record *InstructionClass = Records.getClass("Instruction");
638   for (auto &Field : Table.Fields) {
639     if (!Field.RecType)
640       PrintFatalError(Twine("Cannot determine type of field '") + Field.Name +
641                       "' in table '" + Table.Name + "'. Maybe it is not used?");
642 
643     if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) {
644       if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))
645         Field.IsIntrinsic = true;
646       else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))
647         Field.IsInstruction = true;
648     }
649   }
650 
651   SearchIndex Idx;
652   std::copy(Table.Fields.begin(), Table.Fields.end(),
653             std::back_inserter(Idx.Fields));
654   llvm::sort(Table.Entries, [&](Record *LHS, Record *RHS) {
655     return compareBy(LHS, RHS, Idx);
656   });
657 }
658 
run(raw_ostream & OS)659 void SearchableTableEmitter::run(raw_ostream &OS) {
660   // Emit tables in a deterministic order to avoid needless rebuilds.
661   SmallVector<std::unique_ptr<GenericTable>, 4> Tables;
662   DenseMap<Record *, GenericTable *> TableMap;
663 
664   // Collect all definitions first.
665   for (auto *EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
666     StringRef NameField;
667     if (!EnumRec->isValueUnset("NameField"))
668       NameField = EnumRec->getValueAsString("NameField");
669 
670     StringRef ValueField;
671     if (!EnumRec->isValueUnset("ValueField"))
672       ValueField = EnumRec->getValueAsString("ValueField");
673 
674     auto Enum = std::make_unique<GenericEnum>();
675     Enum->Name = std::string(EnumRec->getName());
676     Enum->PreprocessorGuard = std::string(EnumRec->getName());
677 
678     StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
679     Enum->Class = Records.getClass(FilterClass);
680     if (!Enum->Class)
681       PrintFatalError(EnumRec->getValue("FilterClass"),
682                       Twine("Enum FilterClass '") + FilterClass +
683                           "' does not exist");
684 
685     collectEnumEntries(*Enum, NameField, ValueField,
686                        Records.getAllDerivedDefinitions(FilterClass));
687     EnumMap.insert(std::make_pair(EnumRec, Enum.get()));
688     Enums.emplace_back(std::move(Enum));
689   }
690 
691   for (auto *TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
692     auto Table = std::make_unique<GenericTable>();
693     Table->Name = std::string(TableRec->getName());
694     Table->Locs = TableRec->getLoc();
695     Table->PreprocessorGuard = std::string(TableRec->getName());
696     Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName"));
697 
698     std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");
699     for (const auto &FieldName : Fields) {
700       Table->Fields.emplace_back(FieldName); // Construct a GenericField.
701 
702       if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
703         if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
704           PrintError(TypeOfRecordVal,
705                      Twine("Table '") + Table->Name +
706                          "' has invalid 'TypeOf_" + FieldName +
707                          "': " + TypeOfRecordVal->getValue()->getAsString());
708           PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
709                          "GenericEnum record, or \"code\"");
710         }
711       }
712     }
713 
714     StringRef FilterClass = TableRec->getValueAsString("FilterClass");
715     if (!Records.getClass(FilterClass))
716       PrintFatalError(TableRec->getValue("FilterClass"),
717                       Twine("Table FilterClass '") +
718                           FilterClass + "' does not exist");
719 
720     collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
721 
722     if (!TableRec->isValueUnset("PrimaryKey")) {
723       Table->PrimaryKey =
724           parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
725                            TableRec->getValueAsString("PrimaryKeyName"),
726                            TableRec->getValueAsListOfStrings("PrimaryKey"),
727                            TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
728 
729       llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
730         return compareBy(LHS, RHS, *Table->PrimaryKey);
731       });
732     }
733 
734     TableMap.insert(std::make_pair(TableRec, Table.get()));
735     Tables.emplace_back(std::move(Table));
736   }
737 
738   for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {
739     Record *TableRec = IndexRec->getValueAsDef("Table");
740     auto It = TableMap.find(TableRec);
741     if (It == TableMap.end())
742       PrintFatalError(IndexRec->getValue("Table"),
743                       Twine("SearchIndex '") + IndexRec->getName() +
744                           "' refers to nonexistent table '" +
745                           TableRec->getName());
746 
747     GenericTable &Table = *It->second;
748     Table.Indices.push_back(
749         parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
750                          IndexRec->getValueAsListOfStrings("Key"),
751                          IndexRec->getValueAsBit("EarlyOut")));
752   }
753 
754   // Translate legacy tables.
755   Record *SearchableTable = Records.getClass("SearchableTable");
756   for (auto &NameRec : Records.getClasses()) {
757     Record *Class = NameRec.second.get();
758     if (Class->getSuperClasses().size() != 1 ||
759         !Class->isSubClassOf(SearchableTable))
760       continue;
761 
762     StringRef TableName = Class->getName();
763     std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
764     if (!Class->isValueUnset("EnumNameField")) {
765       StringRef NameField = Class->getValueAsString("EnumNameField");
766       StringRef ValueField;
767       if (!Class->isValueUnset("EnumValueField"))
768         ValueField = Class->getValueAsString("EnumValueField");
769 
770       auto Enum = std::make_unique<GenericEnum>();
771       Enum->Name = (Twine(Class->getName()) + "Values").str();
772       Enum->PreprocessorGuard = Class->getName().upper();
773       Enum->Class = Class;
774 
775       collectEnumEntries(*Enum, NameField, ValueField, Items);
776 
777       Enums.emplace_back(std::move(Enum));
778     }
779 
780     auto Table = std::make_unique<GenericTable>();
781     Table->Name = (Twine(Class->getName()) + "sList").str();
782     Table->Locs = Class->getLoc();
783     Table->PreprocessorGuard = Class->getName().upper();
784     Table->CppTypeName = std::string(Class->getName());
785 
786     for (const RecordVal &Field : Class->getValues()) {
787       std::string FieldName = std::string(Field.getName());
788 
789       // Skip uninteresting fields: either special to us, or injected
790       // template parameters (if they contain a ':').
791       if (FieldName.find(':') != std::string::npos ||
792           FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
793           FieldName == "EnumValueField")
794         continue;
795 
796       Table->Fields.emplace_back(FieldName);
797     }
798 
799     collectTableEntries(*Table, Items);
800 
801     for (const auto &Field :
802          Class->getValueAsListOfStrings("SearchableFields")) {
803       std::string Name =
804           (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
805       Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
806                                                 Name, {Field}, false));
807     }
808 
809     Tables.emplace_back(std::move(Table));
810   }
811 
812   // Emit everything.
813   for (const auto &Enum : Enums)
814     emitGenericEnum(*Enum, OS);
815 
816   for (const auto &Table : Tables)
817     emitGenericTable(*Table, OS);
818 
819   // Put all #undefs last, to allow multiple sections guarded by the same
820   // define.
821   for (const auto &Guard : PreprocessorGuards)
822     OS << "#undef " << Guard << "\n";
823 }
824 
825 namespace llvm {
826 
EmitSearchableTables(RecordKeeper & RK,raw_ostream & OS)827 void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
828   SearchableTableEmitter(RK).run(OS);
829 }
830 
831 } // End llvm namespace.
832