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