1e6ae6767STim Northover //===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
2e6ae6767STim Northover //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e6ae6767STim Northover //
7e6ae6767STim Northover //===----------------------------------------------------------------------===//
8e6ae6767STim Northover //
9e6ae6767STim Northover // This tablegen backend emits a generic array initialized by specified fields,
10e6ae6767STim Northover // together with companion index tables and lookup functions (binary search,
11e6ae6767STim Northover // currently).
12e6ae6767STim Northover //
13e6ae6767STim Northover //===----------------------------------------------------------------------===//
14e6ae6767STim Northover 
15b3931188SPaul C. Anagnostopoulos #include "CodeGenIntrinsics.h"
16b3931188SPaul C. Anagnostopoulos #include "llvm/ADT/ArrayRef.h"
17398c0b67SNicolai Haehnle #include "llvm/ADT/DenseMap.h"
18e6ae6767STim Northover #include "llvm/ADT/StringExtras.h"
19e6ae6767STim Northover #include "llvm/Support/Format.h"
20e6ae6767STim Northover #include "llvm/Support/MemoryBuffer.h"
21e6ae6767STim Northover #include "llvm/Support/SourceMgr.h"
22e6ae6767STim Northover #include "llvm/TableGen/Error.h"
23e6ae6767STim Northover #include "llvm/TableGen/Record.h"
24e6ae6767STim Northover #include <algorithm>
250ea4d06eSNicolai Haehnle #include <set>
26e6ae6767STim Northover #include <string>
27e6ae6767STim Northover #include <vector>
280ea4d06eSNicolai Haehnle 
29e6ae6767STim Northover using namespace llvm;
30e6ae6767STim Northover 
31e6ae6767STim Northover #define DEBUG_TYPE "searchable-table-emitter"
32e6ae6767STim Northover 
33e6ae6767STim Northover namespace {
34e6ae6767STim Northover 
350ea4d06eSNicolai Haehnle struct GenericTable;
360ea4d06eSNicolai Haehnle 
370ea4d06eSNicolai Haehnle int getAsInt(Init *B) {
380ea4d06eSNicolai Haehnle   return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
390ea4d06eSNicolai Haehnle }
400ea4d06eSNicolai Haehnle int getInt(Record *R, StringRef Field) {
410ea4d06eSNicolai Haehnle   return getAsInt(R->getValueInit(Field));
420ea4d06eSNicolai Haehnle }
430ea4d06eSNicolai Haehnle 
440ea4d06eSNicolai Haehnle struct GenericEnum {
450ea4d06eSNicolai Haehnle   using Entry = std::pair<StringRef, int64_t>;
460ea4d06eSNicolai Haehnle 
470ea4d06eSNicolai Haehnle   std::string Name;
48612810e3SSimon Pilgrim   Record *Class = nullptr;
490ea4d06eSNicolai Haehnle   std::string PreprocessorGuard;
500ea4d06eSNicolai Haehnle   std::vector<std::unique_ptr<Entry>> Entries;
510ea4d06eSNicolai Haehnle   DenseMap<Record *, Entry *> EntryMap;
520ea4d06eSNicolai Haehnle };
530ea4d06eSNicolai Haehnle 
540ea4d06eSNicolai Haehnle struct GenericField {
550ea4d06eSNicolai Haehnle   std::string Name;
560ea4d06eSNicolai Haehnle   RecTy *RecType = nullptr;
57415fab6fSPaul C. Anagnostopoulos   bool IsCode = false;
580ea4d06eSNicolai Haehnle   bool IsIntrinsic = false;
590ea4d06eSNicolai Haehnle   bool IsInstruction = false;
600ea4d06eSNicolai Haehnle   GenericEnum *Enum = nullptr;
610ea4d06eSNicolai Haehnle 
62adcd0268SBenjamin Kramer   GenericField(StringRef Name) : Name(std::string(Name)) {}
630ea4d06eSNicolai Haehnle };
640ea4d06eSNicolai Haehnle 
650ea4d06eSNicolai Haehnle struct SearchIndex {
660ea4d06eSNicolai Haehnle   std::string Name;
67b3931188SPaul C. Anagnostopoulos   SMLoc Loc; // Source location of PrimaryKey or Key field definition.
680ea4d06eSNicolai Haehnle   SmallVector<GenericField, 1> Fields;
69612810e3SSimon Pilgrim   bool EarlyOut = false;
700ea4d06eSNicolai Haehnle };
710ea4d06eSNicolai Haehnle 
720ea4d06eSNicolai Haehnle struct GenericTable {
730ea4d06eSNicolai Haehnle   std::string Name;
74b3931188SPaul C. Anagnostopoulos   ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
750ea4d06eSNicolai Haehnle   std::string PreprocessorGuard;
760ea4d06eSNicolai Haehnle   std::string CppTypeName;
770ea4d06eSNicolai Haehnle   SmallVector<GenericField, 2> Fields;
780ea4d06eSNicolai Haehnle   std::vector<Record *> Entries;
790ea4d06eSNicolai Haehnle 
800ea4d06eSNicolai Haehnle   std::unique_ptr<SearchIndex> PrimaryKey;
810ea4d06eSNicolai Haehnle   SmallVector<std::unique_ptr<SearchIndex>, 2> Indices;
820ea4d06eSNicolai Haehnle 
830ea4d06eSNicolai Haehnle   const GenericField *getFieldByName(StringRef Name) const {
840ea4d06eSNicolai Haehnle     for (const auto &Field : Fields) {
850ea4d06eSNicolai Haehnle       if (Name == Field.Name)
860ea4d06eSNicolai Haehnle         return &Field;
870ea4d06eSNicolai Haehnle     }
880ea4d06eSNicolai Haehnle     return nullptr;
890ea4d06eSNicolai Haehnle   }
900ea4d06eSNicolai Haehnle };
910ea4d06eSNicolai Haehnle 
92e6ae6767STim Northover class SearchableTableEmitter {
93e6ae6767STim Northover   RecordKeeper &Records;
94398c0b67SNicolai Haehnle   DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;
950ea4d06eSNicolai Haehnle   std::vector<std::unique_ptr<GenericEnum>> Enums;
960ea4d06eSNicolai Haehnle   DenseMap<Record *, GenericEnum *> EnumMap;
970ea4d06eSNicolai Haehnle   std::set<std::string> PreprocessorGuards;
98e6ae6767STim Northover 
99e6ae6767STim Northover public:
100e6ae6767STim Northover   SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
101e6ae6767STim Northover 
102e6ae6767STim Northover   void run(raw_ostream &OS);
103e6ae6767STim Northover 
104e6ae6767STim Northover private:
105e6ae6767STim Northover   typedef std::pair<Init *, int> SearchTableEntry;
106e6ae6767STim Northover 
1070ea4d06eSNicolai Haehnle   enum TypeContext {
1080ea4d06eSNicolai Haehnle     TypeInStaticStruct,
1090ea4d06eSNicolai Haehnle     TypeInTempStruct,
1100ea4d06eSNicolai Haehnle     TypeInArgument,
1110ea4d06eSNicolai Haehnle   };
112e6ae6767STim Northover 
113b3931188SPaul C. Anagnostopoulos   std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
114b3931188SPaul C. Anagnostopoulos                                     Init *I) {
115415fab6fSPaul C. Anagnostopoulos     if (StringInit *SI = dyn_cast<StringInit>(I)) {
116415fab6fSPaul C. Anagnostopoulos       if (Field.IsCode || SI->hasCodeFormat())
117415fab6fSPaul C. Anagnostopoulos         return std::string(SI->getValue());
118415fab6fSPaul C. Anagnostopoulos       else
119e6ae6767STim Northover         return SI->getAsString();
120415fab6fSPaul C. Anagnostopoulos     } else if (BitsInit *BI = dyn_cast<BitsInit>(I))
121e6ae6767STim Northover       return "0x" + utohexstr(getAsInt(BI));
122e6ae6767STim Northover     else if (BitInit *BI = dyn_cast<BitInit>(I))
123e6ae6767STim Northover       return BI->getValue() ? "true" : "false";
1240ea4d06eSNicolai Haehnle     else if (Field.IsIntrinsic)
125398c0b67SNicolai Haehnle       return "Intrinsic::" + getIntrinsic(I).EnumName;
1260ea4d06eSNicolai Haehnle     else if (Field.IsInstruction)
1270ea4d06eSNicolai Haehnle       return I->getAsString();
128d668d8b6SSebastian Neubauer     else if (Field.Enum) {
129d668d8b6SSebastian Neubauer       auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
130d668d8b6SSebastian Neubauer       if (!Entry)
131b3931188SPaul C. Anagnostopoulos         PrintFatalError(Loc,
132b3931188SPaul C. Anagnostopoulos                         Twine("Entry for field '") + Field.Name + "' is null");
133d668d8b6SSebastian Neubauer       return std::string(Entry->first);
134d668d8b6SSebastian Neubauer     }
135b3931188SPaul C. Anagnostopoulos     PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
136b3931188SPaul C. Anagnostopoulos                              "'; expected: bit, bits, string, or code");
137e6ae6767STim Northover   }
138e6ae6767STim Northover 
139398c0b67SNicolai Haehnle   bool isIntrinsic(Init *I) {
140398c0b67SNicolai Haehnle     if (DefInit *DI = dyn_cast<DefInit>(I))
141398c0b67SNicolai Haehnle       return DI->getDef()->isSubClassOf("Intrinsic");
142398c0b67SNicolai Haehnle     return false;
143398c0b67SNicolai Haehnle   }
144398c0b67SNicolai Haehnle 
145398c0b67SNicolai Haehnle   CodeGenIntrinsic &getIntrinsic(Init *I) {
146398c0b67SNicolai Haehnle     std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
147398c0b67SNicolai Haehnle     if (!Intr)
14899d18f79Ssstefan1       Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),
14999d18f79Ssstefan1                                                 std::vector<Record *>());
150398c0b67SNicolai Haehnle     return *Intr;
151398c0b67SNicolai Haehnle   }
152398c0b67SNicolai Haehnle 
1530ea4d06eSNicolai Haehnle   bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
1540ea4d06eSNicolai Haehnle 
155b3931188SPaul C. Anagnostopoulos   std::string searchableFieldType(const GenericTable &Table,
156b3931188SPaul C. Anagnostopoulos                                   const SearchIndex &Index,
157b3931188SPaul C. Anagnostopoulos                                   const GenericField &Field, TypeContext Ctx) {
1580ea4d06eSNicolai Haehnle     if (isa<StringRecTy>(Field.RecType)) {
1590ea4d06eSNicolai Haehnle       if (Ctx == TypeInStaticStruct)
160e6ae6767STim Northover         return "const char *";
1610ea4d06eSNicolai Haehnle       if (Ctx == TypeInTempStruct)
1620ea4d06eSNicolai Haehnle         return "std::string";
1630ea4d06eSNicolai Haehnle       return "StringRef";
1640ea4d06eSNicolai Haehnle     } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
165e6ae6767STim Northover       unsigned NumBits = BI->getNumBits();
166e6ae6767STim Northover       if (NumBits <= 8)
1676feb62a4SNicolai Haehnle         return "uint8_t";
1686feb62a4SNicolai Haehnle       if (NumBits <= 16)
1696feb62a4SNicolai Haehnle         return "uint16_t";
1706feb62a4SNicolai Haehnle       if (NumBits <= 32)
1716feb62a4SNicolai Haehnle         return "uint32_t";
1726feb62a4SNicolai Haehnle       if (NumBits <= 64)
1736feb62a4SNicolai Haehnle         return "uint64_t";
174b3931188SPaul C. Anagnostopoulos       PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
175b3931188SPaul C. Anagnostopoulos                                      "' lookup method '" + Index.Name +
176b3931188SPaul C. Anagnostopoulos                                      "', key field '" + Field.Name +
177b3931188SPaul C. Anagnostopoulos                                      "' of type bits is too large");
1780ea4d06eSNicolai Haehnle     } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
179398c0b67SNicolai Haehnle       return "unsigned";
180b3931188SPaul C. Anagnostopoulos     PrintFatalError(Index.Loc,
181b3931188SPaul C. Anagnostopoulos                     Twine("In table '") + Table.Name + "' lookup method '" +
182b3931188SPaul C. Anagnostopoulos                         Index.Name + "', key field '" + Field.Name +
183b3931188SPaul C. Anagnostopoulos                         "' has invalid type: " + Field.RecType->getAsString());
184e6ae6767STim Northover   }
185e6ae6767STim Northover 
1860ea4d06eSNicolai Haehnle   void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
1870ea4d06eSNicolai Haehnle   void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
1880ea4d06eSNicolai Haehnle   void emitLookupDeclaration(const GenericTable &Table,
1890ea4d06eSNicolai Haehnle                              const SearchIndex &Index, raw_ostream &OS);
1900ea4d06eSNicolai Haehnle   void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
1910ea4d06eSNicolai Haehnle                           bool IsPrimary, raw_ostream &OS);
1920ea4d06eSNicolai Haehnle   void emitIfdef(StringRef Guard, raw_ostream &OS);
1930ea4d06eSNicolai Haehnle 
1940ea4d06eSNicolai Haehnle   bool parseFieldType(GenericField &Field, Init *II);
1950ea4d06eSNicolai Haehnle   std::unique_ptr<SearchIndex>
196b3931188SPaul C. Anagnostopoulos   parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
1970ea4d06eSNicolai Haehnle                    const std::vector<StringRef> &Key, bool EarlyOut);
1980ea4d06eSNicolai Haehnle   void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
1990ea4d06eSNicolai Haehnle                           StringRef ValueField,
2000ea4d06eSNicolai Haehnle                           const std::vector<Record *> &Items);
2010ea4d06eSNicolai Haehnle   void collectTableEntries(GenericTable &Table,
2020ea4d06eSNicolai Haehnle                            const std::vector<Record *> &Items);
203e6ae6767STim Northover };
204e6ae6767STim Northover 
205e6ae6767STim Northover } // End anonymous namespace.
206e6ae6767STim Northover 
2070ea4d06eSNicolai Haehnle // For search indices that consists of a single field whose numeric value is
2080ea4d06eSNicolai Haehnle // known, return that numeric value.
2090ea4d06eSNicolai Haehnle static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
2100ea4d06eSNicolai Haehnle   assert(Index.Fields.size() == 1);
2110ea4d06eSNicolai Haehnle 
2120ea4d06eSNicolai Haehnle   if (Index.Fields[0].Enum) {
2130ea4d06eSNicolai Haehnle     Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);
2140ea4d06eSNicolai Haehnle     return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;
2150ea4d06eSNicolai Haehnle   }
2160ea4d06eSNicolai Haehnle 
2170ea4d06eSNicolai Haehnle   return getInt(Rec, Index.Fields[0].Name);
2180ea4d06eSNicolai Haehnle }
2190ea4d06eSNicolai Haehnle 
2200ea4d06eSNicolai Haehnle /// Less-than style comparison between \p LHS and \p RHS according to the
2210ea4d06eSNicolai Haehnle /// key of \p Index.
2220ea4d06eSNicolai Haehnle bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
2230ea4d06eSNicolai Haehnle                                        const SearchIndex &Index) {
2240ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
2250ea4d06eSNicolai Haehnle     Init *LHSI = LHS->getValueInit(Field.Name);
2260ea4d06eSNicolai Haehnle     Init *RHSI = RHS->getValueInit(Field.Name);
2270ea4d06eSNicolai Haehnle 
2280ea4d06eSNicolai Haehnle     if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) {
2290ea4d06eSNicolai Haehnle       int64_t LHSi = getAsInt(LHSI);
2300ea4d06eSNicolai Haehnle       int64_t RHSi = getAsInt(RHSI);
2310ea4d06eSNicolai Haehnle       if (LHSi < RHSi)
2320ea4d06eSNicolai Haehnle         return true;
2330ea4d06eSNicolai Haehnle       if (LHSi > RHSi)
2340ea4d06eSNicolai Haehnle         return false;
2350ea4d06eSNicolai Haehnle     } else if (Field.IsIntrinsic) {
2360ea4d06eSNicolai Haehnle       CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);
2370ea4d06eSNicolai Haehnle       CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);
2380ea4d06eSNicolai Haehnle       if (std::tie(LHSi.TargetPrefix, LHSi.Name) <
2390ea4d06eSNicolai Haehnle           std::tie(RHSi.TargetPrefix, RHSi.Name))
2400ea4d06eSNicolai Haehnle         return true;
2410ea4d06eSNicolai Haehnle       if (std::tie(LHSi.TargetPrefix, LHSi.Name) >
2420ea4d06eSNicolai Haehnle           std::tie(RHSi.TargetPrefix, RHSi.Name))
2430ea4d06eSNicolai Haehnle         return false;
2440ea4d06eSNicolai Haehnle     } else if (Field.IsInstruction) {
2450ea4d06eSNicolai Haehnle       // This does not correctly compare the predefined instructions!
2460ea4d06eSNicolai Haehnle       Record *LHSr = cast<DefInit>(LHSI)->getDef();
2470ea4d06eSNicolai Haehnle       Record *RHSr = cast<DefInit>(RHSI)->getDef();
2480ea4d06eSNicolai Haehnle 
2490ea4d06eSNicolai Haehnle       bool LHSpseudo = LHSr->getValueAsBit("isPseudo");
2500ea4d06eSNicolai Haehnle       bool RHSpseudo = RHSr->getValueAsBit("isPseudo");
2510ea4d06eSNicolai Haehnle       if (LHSpseudo && !RHSpseudo)
2520ea4d06eSNicolai Haehnle         return true;
2530ea4d06eSNicolai Haehnle       if (!LHSpseudo && RHSpseudo)
2540ea4d06eSNicolai Haehnle         return false;
2550ea4d06eSNicolai Haehnle 
2560ea4d06eSNicolai Haehnle       int comp = LHSr->getName().compare(RHSr->getName());
2570ea4d06eSNicolai Haehnle       if (comp < 0)
2580ea4d06eSNicolai Haehnle         return true;
2590ea4d06eSNicolai Haehnle       if (comp > 0)
2600ea4d06eSNicolai Haehnle         return false;
2610ea4d06eSNicolai Haehnle     } else if (Field.Enum) {
2620ea4d06eSNicolai Haehnle       auto LHSr = cast<DefInit>(LHSI)->getDef();
2630ea4d06eSNicolai Haehnle       auto RHSr = cast<DefInit>(RHSI)->getDef();
2640ea4d06eSNicolai Haehnle       int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
2650ea4d06eSNicolai Haehnle       int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
2660ea4d06eSNicolai Haehnle       if (LHSv < RHSv)
2670ea4d06eSNicolai Haehnle         return true;
2680ea4d06eSNicolai Haehnle       if (LHSv > RHSv)
2690ea4d06eSNicolai Haehnle         return false;
2700ea4d06eSNicolai Haehnle     } else {
271b3931188SPaul C. Anagnostopoulos       std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);
272b3931188SPaul C. Anagnostopoulos       std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);
2730ea4d06eSNicolai Haehnle 
2740ea4d06eSNicolai Haehnle       if (isa<StringRecTy>(Field.RecType)) {
2750ea4d06eSNicolai Haehnle         LHSs = StringRef(LHSs).upper();
2760ea4d06eSNicolai Haehnle         RHSs = StringRef(RHSs).upper();
2770ea4d06eSNicolai Haehnle       }
2780ea4d06eSNicolai Haehnle 
2790ea4d06eSNicolai Haehnle       int comp = LHSs.compare(RHSs);
2800ea4d06eSNicolai Haehnle       if (comp < 0)
2810ea4d06eSNicolai Haehnle         return true;
2820ea4d06eSNicolai Haehnle       if (comp > 0)
2830ea4d06eSNicolai Haehnle         return false;
2840ea4d06eSNicolai Haehnle     }
2850ea4d06eSNicolai Haehnle   }
2860ea4d06eSNicolai Haehnle   return false;
2870ea4d06eSNicolai Haehnle }
2880ea4d06eSNicolai Haehnle 
2890ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {
2900ea4d06eSNicolai Haehnle   OS << "#ifdef " << Guard << "\n";
291adcd0268SBenjamin Kramer   PreprocessorGuards.insert(std::string(Guard));
2920ea4d06eSNicolai Haehnle }
2930ea4d06eSNicolai Haehnle 
2940ea4d06eSNicolai Haehnle /// Emit a generic enum.
2950ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
296e6ae6767STim Northover                                              raw_ostream &OS) {
2970ea4d06eSNicolai Haehnle   emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
298e6ae6767STim Northover 
2990ea4d06eSNicolai Haehnle   OS << "enum " << Enum.Name << " {\n";
3000ea4d06eSNicolai Haehnle   for (const auto &Entry : Enum.Entries)
3010ea4d06eSNicolai Haehnle     OS << "  " << Entry->first << " = " << Entry->second << ",\n";
3020ea4d06eSNicolai Haehnle   OS << "};\n";
3030ea4d06eSNicolai Haehnle 
3040ea4d06eSNicolai Haehnle   OS << "#endif\n\n";
305e6ae6767STim Northover }
306e6ae6767STim Northover 
3070ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
3080ea4d06eSNicolai Haehnle                                                 const SearchIndex &Index,
3090ea4d06eSNicolai Haehnle                                                 bool IsPrimary,
3100ea4d06eSNicolai Haehnle                                                 raw_ostream &OS) {
3110ea4d06eSNicolai Haehnle   OS << "\n";
3120ea4d06eSNicolai Haehnle   emitLookupDeclaration(Table, Index, OS);
3130ea4d06eSNicolai Haehnle   OS << " {\n";
314e6ae6767STim Northover 
3150ea4d06eSNicolai Haehnle   std::vector<Record *> IndexRowsStorage;
3160ea4d06eSNicolai Haehnle   ArrayRef<Record *> IndexRows;
3170ea4d06eSNicolai Haehnle   StringRef IndexTypeName;
3180ea4d06eSNicolai Haehnle   StringRef IndexName;
3190ea4d06eSNicolai Haehnle 
3200ea4d06eSNicolai Haehnle   if (IsPrimary) {
3210ea4d06eSNicolai Haehnle     IndexTypeName = Table.CppTypeName;
3220ea4d06eSNicolai Haehnle     IndexName = Table.Name;
3230ea4d06eSNicolai Haehnle     IndexRows = Table.Entries;
3240ea4d06eSNicolai Haehnle   } else {
3250ea4d06eSNicolai Haehnle     OS << "  struct IndexType {\n";
3260ea4d06eSNicolai Haehnle     for (const auto &Field : Index.Fields) {
327b3931188SPaul C. Anagnostopoulos       OS << "    "
328b3931188SPaul C. Anagnostopoulos          << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "
3290ea4d06eSNicolai Haehnle          << Field.Name << ";\n";
3300ea4d06eSNicolai Haehnle     }
3310ea4d06eSNicolai Haehnle     OS << "    unsigned _index;\n";
3320ea4d06eSNicolai Haehnle     OS << "  };\n";
3330ea4d06eSNicolai Haehnle 
3340ea4d06eSNicolai Haehnle     OS << "  static const struct IndexType Index[] = {\n";
3350ea4d06eSNicolai Haehnle 
3360ea4d06eSNicolai Haehnle     std::vector<std::pair<Record *, unsigned>> Entries;
3370ea4d06eSNicolai Haehnle     Entries.reserve(Table.Entries.size());
3380ea4d06eSNicolai Haehnle     for (unsigned i = 0; i < Table.Entries.size(); ++i)
3390ea4d06eSNicolai Haehnle       Entries.emplace_back(Table.Entries[i], i);
3400ea4d06eSNicolai Haehnle 
341125ea20dSKazu Hirata     llvm::stable_sort(Entries, [&](const std::pair<Record *, unsigned> &LHS,
3420ea4d06eSNicolai Haehnle                                    const std::pair<Record *, unsigned> &RHS) {
3430ea4d06eSNicolai Haehnle       return compareBy(LHS.first, RHS.first, Index);
3440ea4d06eSNicolai Haehnle     });
3450ea4d06eSNicolai Haehnle 
3460ea4d06eSNicolai Haehnle     IndexRowsStorage.reserve(Entries.size());
3470ea4d06eSNicolai Haehnle     for (const auto &Entry : Entries) {
3480ea4d06eSNicolai Haehnle       IndexRowsStorage.push_back(Entry.first);
3490ea4d06eSNicolai Haehnle 
350e6ae6767STim Northover       OS << "    { ";
3510ea4d06eSNicolai Haehnle       bool NeedComma = false;
3520ea4d06eSNicolai Haehnle       for (const auto &Field : Index.Fields) {
3530ea4d06eSNicolai Haehnle         if (NeedComma)
354e6ae6767STim Northover           OS << ", ";
3550ea4d06eSNicolai Haehnle         NeedComma = true;
3560ea4d06eSNicolai Haehnle 
357b3931188SPaul C. Anagnostopoulos         std::string Repr = primaryRepresentation(
358b3931188SPaul C. Anagnostopoulos             Index.Loc, Field, Entry.first->getValueInit(Field.Name));
3590ea4d06eSNicolai Haehnle         if (isa<StringRecTy>(Field.RecType))
3600ea4d06eSNicolai Haehnle           Repr = StringRef(Repr).upper();
3610ea4d06eSNicolai Haehnle         OS << Repr;
362e6ae6767STim Northover       }
3630ea4d06eSNicolai Haehnle       OS << ", " << Entry.second << " },\n";
364e6ae6767STim Northover     }
3650ea4d06eSNicolai Haehnle 
366e6ae6767STim Northover     OS << "  };\n\n";
3670ea4d06eSNicolai Haehnle 
3680ea4d06eSNicolai Haehnle     IndexTypeName = "IndexType";
3690ea4d06eSNicolai Haehnle     IndexName = "Index";
3700ea4d06eSNicolai Haehnle     IndexRows = IndexRowsStorage;
371e6ae6767STim Northover   }
372e6ae6767STim Northover 
3730ea4d06eSNicolai Haehnle   bool IsContiguous = false;
374e6ae6767STim Northover 
3750ea4d06eSNicolai Haehnle   if (Index.Fields.size() == 1 &&
3760ea4d06eSNicolai Haehnle       (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) {
3770ea4d06eSNicolai Haehnle     IsContiguous = true;
3780ea4d06eSNicolai Haehnle     for (unsigned i = 0; i < IndexRows.size(); ++i) {
3790ea4d06eSNicolai Haehnle       if (getNumericKey(Index, IndexRows[i]) != i) {
3800ea4d06eSNicolai Haehnle         IsContiguous = false;
3810ea4d06eSNicolai Haehnle         break;
3820ea4d06eSNicolai Haehnle       }
3830ea4d06eSNicolai Haehnle     }
3840ea4d06eSNicolai Haehnle   }
3850ea4d06eSNicolai Haehnle 
3860ea4d06eSNicolai Haehnle   if (IsContiguous) {
3870ea4d06eSNicolai Haehnle     OS << "  auto Table = makeArrayRef(" << IndexName << ");\n";
3880ea4d06eSNicolai Haehnle     OS << "  size_t Idx = " << Index.Fields[0].Name << ";\n";
3890ea4d06eSNicolai Haehnle     OS << "  return Idx >= Table.size() ? nullptr : ";
3900ea4d06eSNicolai Haehnle     if (IsPrimary)
3910ea4d06eSNicolai Haehnle       OS << "&Table[Idx]";
3920ea4d06eSNicolai Haehnle     else
3930ea4d06eSNicolai Haehnle       OS << "&" << Table.Name << "[Table[Idx]._index]";
3940ea4d06eSNicolai Haehnle     OS << ";\n";
3950ea4d06eSNicolai Haehnle     OS << "}\n";
3960ea4d06eSNicolai Haehnle     return;
3970ea4d06eSNicolai Haehnle   }
3980ea4d06eSNicolai Haehnle 
3990ea4d06eSNicolai Haehnle   if (Index.EarlyOut) {
4000ea4d06eSNicolai Haehnle     const GenericField &Field = Index.Fields[0];
401b3931188SPaul C. Anagnostopoulos     std::string FirstRepr = primaryRepresentation(
402b3931188SPaul C. Anagnostopoulos         Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));
4030ea4d06eSNicolai Haehnle     std::string LastRepr = primaryRepresentation(
404b3931188SPaul C. Anagnostopoulos         Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));
4050ea4d06eSNicolai Haehnle     OS << "  if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
4060ea4d06eSNicolai Haehnle     OS << "      (" << Field.Name << " > " << LastRepr << "))\n";
4070ea4d06eSNicolai Haehnle     OS << "    return nullptr;\n\n";
4080ea4d06eSNicolai Haehnle   }
4090ea4d06eSNicolai Haehnle 
4100ea4d06eSNicolai Haehnle   OS << "  struct KeyType {\n";
4110ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
412b3931188SPaul C. Anagnostopoulos     OS << "    " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
413b3931188SPaul C. Anagnostopoulos        << " " << Field.Name << ";\n";
4140ea4d06eSNicolai Haehnle   }
4150ea4d06eSNicolai Haehnle   OS << "  };\n";
4160ea4d06eSNicolai Haehnle   OS << "  KeyType Key = {";
417*6bfb02caSKazu Hirata   ListSeparator LS;
4180ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
419*6bfb02caSKazu Hirata     OS << LS << Field.Name;
4200ea4d06eSNicolai Haehnle     if (isa<StringRecTy>(Field.RecType)) {
4210ea4d06eSNicolai Haehnle       OS << ".upper()";
4220ea4d06eSNicolai Haehnle       if (IsPrimary)
423b3931188SPaul C. Anagnostopoulos         PrintFatalError(Index.Loc,
424b3931188SPaul C. Anagnostopoulos                         Twine("In table '") + Table.Name +
425b3931188SPaul C. Anagnostopoulos                             "', use a secondary lookup method for "
426b3931188SPaul C. Anagnostopoulos                             "case-insensitive comparison of field '" +
427b3931188SPaul C. Anagnostopoulos                             Field.Name + "'");
4280ea4d06eSNicolai Haehnle     }
4290ea4d06eSNicolai Haehnle   }
4300ea4d06eSNicolai Haehnle   OS << "};\n";
4310ea4d06eSNicolai Haehnle 
4320ea4d06eSNicolai Haehnle   OS << "  auto Table = makeArrayRef(" << IndexName << ");\n";
4330ea4d06eSNicolai Haehnle   OS << "  auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
4340ea4d06eSNicolai Haehnle   OS << "    [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
4350ea4d06eSNicolai Haehnle 
4360ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
4370ea4d06eSNicolai Haehnle     if (isa<StringRecTy>(Field.RecType)) {
4380ea4d06eSNicolai Haehnle       OS << "      int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
4390ea4d06eSNicolai Haehnle          << ").compare(RHS." << Field.Name << ");\n";
4400ea4d06eSNicolai Haehnle       OS << "      if (Cmp" << Field.Name << " < 0) return true;\n";
4410ea4d06eSNicolai Haehnle       OS << "      if (Cmp" << Field.Name << " > 0) return false;\n";
442ba9eee5fSNicolai Haehnle     } else if (Field.Enum) {
443ba9eee5fSNicolai Haehnle       // Explicitly cast to unsigned, because the signedness of enums is
444ba9eee5fSNicolai Haehnle       // compiler-dependent.
445ba9eee5fSNicolai Haehnle       OS << "      if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
446ba9eee5fSNicolai Haehnle          << Field.Name << ")\n";
447ba9eee5fSNicolai Haehnle       OS << "        return true;\n";
448ba9eee5fSNicolai Haehnle       OS << "      if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
449ba9eee5fSNicolai Haehnle          << Field.Name << ")\n";
450ba9eee5fSNicolai Haehnle       OS << "        return false;\n";
451e6ae6767STim Northover     } else {
4520ea4d06eSNicolai Haehnle       OS << "      if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
4530ea4d06eSNicolai Haehnle       OS << "        return true;\n";
4540ea4d06eSNicolai Haehnle       OS << "      if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
4550ea4d06eSNicolai Haehnle       OS << "        return false;\n";
4560ea4d06eSNicolai Haehnle     }
457e6ae6767STim Northover   }
458e6ae6767STim Northover 
4590ea4d06eSNicolai Haehnle   OS << "      return false;\n";
460e6ae6767STim Northover   OS << "    });\n\n";
4610ea4d06eSNicolai Haehnle 
4620ea4d06eSNicolai Haehnle   OS << "  if (Idx == Table.end()";
4630ea4d06eSNicolai Haehnle 
4640ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields)
4650ea4d06eSNicolai Haehnle     OS << " ||\n      Key." << Field.Name << " != Idx->" << Field.Name;
4660ea4d06eSNicolai Haehnle   OS << ")\n    return nullptr;\n";
4670ea4d06eSNicolai Haehnle 
4680ea4d06eSNicolai Haehnle   if (IsPrimary)
4690ea4d06eSNicolai Haehnle     OS << "  return &*Idx;\n";
4700ea4d06eSNicolai Haehnle   else
4710ea4d06eSNicolai Haehnle     OS << "  return &" << Table.Name << "[Idx->_index];\n";
4720ea4d06eSNicolai Haehnle 
4730ea4d06eSNicolai Haehnle   OS << "}\n";
474e6ae6767STim Northover }
475e6ae6767STim Northover 
4760ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
4770ea4d06eSNicolai Haehnle                                                    const SearchIndex &Index,
478e6ae6767STim Northover                                                    raw_ostream &OS) {
4790ea4d06eSNicolai Haehnle   OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
4800ea4d06eSNicolai Haehnle 
481*6bfb02caSKazu Hirata   ListSeparator LS;
482*6bfb02caSKazu Hirata   for (const auto &Field : Index.Fields)
483*6bfb02caSKazu Hirata     OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
484b3931188SPaul C. Anagnostopoulos        << Field.Name;
4850ea4d06eSNicolai Haehnle   OS << ")";
486e6ae6767STim Northover }
487e6ae6767STim Northover 
4880ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
489e6ae6767STim Northover                                               raw_ostream &OS) {
4900ea4d06eSNicolai Haehnle   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);
491e6ae6767STim Northover 
4920ea4d06eSNicolai Haehnle   // Emit the declarations for the functions that will perform lookup.
4930ea4d06eSNicolai Haehnle   if (Table.PrimaryKey) {
4940ea4d06eSNicolai Haehnle     emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
4950ea4d06eSNicolai Haehnle     OS << ";\n";
496e6ae6767STim Northover   }
4970ea4d06eSNicolai Haehnle   for (const auto &Index : Table.Indices) {
4980ea4d06eSNicolai Haehnle     emitLookupDeclaration(Table, *Index, OS);
4990ea4d06eSNicolai Haehnle     OS << ";\n";
500e6ae6767STim Northover   }
501e6ae6767STim Northover 
502e6ae6767STim Northover   OS << "#endif\n\n";
503e6ae6767STim Northover 
5040ea4d06eSNicolai Haehnle   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
505e6ae6767STim Northover 
506e6ae6767STim Northover   // The primary data table contains all the fields defined for this map.
50716b32291SBenjamin Kramer   OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
5080ea4d06eSNicolai Haehnle   for (unsigned i = 0; i < Table.Entries.size(); ++i) {
5090ea4d06eSNicolai Haehnle     Record *Entry = Table.Entries[i];
5100ea4d06eSNicolai Haehnle     OS << "  { ";
5110ea4d06eSNicolai Haehnle 
5120ea4d06eSNicolai Haehnle     bool NeedComma = false;
5130ea4d06eSNicolai Haehnle     for (const auto &Field : Table.Fields) {
5140ea4d06eSNicolai Haehnle       if (NeedComma)
5150ea4d06eSNicolai Haehnle         OS << ", ";
5160ea4d06eSNicolai Haehnle       NeedComma = true;
5170ea4d06eSNicolai Haehnle 
518b3931188SPaul C. Anagnostopoulos       OS << primaryRepresentation(Table.Locs[0], Field,
519b3931188SPaul C. Anagnostopoulos                                   Entry->getValueInit(Field.Name));
5200ea4d06eSNicolai Haehnle     }
5210ea4d06eSNicolai Haehnle 
5220ea4d06eSNicolai Haehnle     OS << " }, // " << i << "\n";
5230ea4d06eSNicolai Haehnle   }
5240ea4d06eSNicolai Haehnle   OS << " };\n";
525e6ae6767STim Northover 
526e6ae6767STim Northover   // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
527e6ae6767STim Northover   // search can be performed by "Thing".
5280ea4d06eSNicolai Haehnle   if (Table.PrimaryKey)
5290ea4d06eSNicolai Haehnle     emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
5300ea4d06eSNicolai Haehnle   for (const auto &Index : Table.Indices)
5310ea4d06eSNicolai Haehnle     emitLookupFunction(Table, *Index, false, OS);
5320ea4d06eSNicolai Haehnle 
5330ea4d06eSNicolai Haehnle   OS << "#endif\n\n";
534e6ae6767STim Northover }
535e6ae6767STim Northover 
536415fab6fSPaul C. Anagnostopoulos bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
537415fab6fSPaul C. Anagnostopoulos   if (auto Type = dyn_cast<StringInit>(TypeOf)) {
538415fab6fSPaul C. Anagnostopoulos     if (Type->getValue() == "code") {
539415fab6fSPaul C. Anagnostopoulos       Field.IsCode = true;
540415fab6fSPaul C. Anagnostopoulos       return true;
541415fab6fSPaul C. Anagnostopoulos     } else {
542415fab6fSPaul C. Anagnostopoulos       if (Record *TypeRec = Records.getDef(Type->getValue())) {
5430ea4d06eSNicolai Haehnle         if (TypeRec->isSubClassOf("GenericEnum")) {
5440ea4d06eSNicolai Haehnle           Field.Enum = EnumMap[TypeRec];
5450ea4d06eSNicolai Haehnle           Field.RecType = RecordRecTy::get(Field.Enum->Class);
5460ea4d06eSNicolai Haehnle           return true;
5470ea4d06eSNicolai Haehnle         }
5480ea4d06eSNicolai Haehnle       }
549415fab6fSPaul C. Anagnostopoulos     }
550415fab6fSPaul C. Anagnostopoulos   }
5510ea4d06eSNicolai Haehnle 
5520ea4d06eSNicolai Haehnle   return false;
5530ea4d06eSNicolai Haehnle }
5540ea4d06eSNicolai Haehnle 
555b3931188SPaul C. Anagnostopoulos std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
556b3931188SPaul C. Anagnostopoulos     GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
557b3931188SPaul C. Anagnostopoulos     const std::vector<StringRef> &Key, bool EarlyOut) {
5580eaee545SJonas Devlieghere   auto Index = std::make_unique<SearchIndex>();
559adcd0268SBenjamin Kramer   Index->Name = std::string(Name);
560b3931188SPaul C. Anagnostopoulos   Index->Loc = KeyRecVal->getLoc();
5610ea4d06eSNicolai Haehnle   Index->EarlyOut = EarlyOut;
5620ea4d06eSNicolai Haehnle 
5630ea4d06eSNicolai Haehnle   for (const auto &FieldName : Key) {
5640ea4d06eSNicolai Haehnle     const GenericField *Field = Table.getFieldByName(FieldName);
5650ea4d06eSNicolai Haehnle     if (!Field)
566b3931188SPaul C. Anagnostopoulos       PrintFatalError(
567b3931188SPaul C. Anagnostopoulos           KeyRecVal,
568b3931188SPaul C. Anagnostopoulos           Twine("In table '") + Table.Name +
569b3931188SPaul C. Anagnostopoulos               "', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
570b3931188SPaul C. Anagnostopoulos               FieldName + "'");
571b3931188SPaul C. Anagnostopoulos 
5720ea4d06eSNicolai Haehnle     Index->Fields.push_back(*Field);
5730ea4d06eSNicolai Haehnle   }
5740ea4d06eSNicolai Haehnle 
5750ea4d06eSNicolai Haehnle   if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
5760ea4d06eSNicolai Haehnle     PrintFatalError(
577b3931188SPaul C. Anagnostopoulos         KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +
578b3931188SPaul C. Anagnostopoulos                        "supported for a first key field of type string");
5790ea4d06eSNicolai Haehnle   }
5800ea4d06eSNicolai Haehnle 
5810ea4d06eSNicolai Haehnle   return Index;
5820ea4d06eSNicolai Haehnle }
5830ea4d06eSNicolai Haehnle 
5840ea4d06eSNicolai Haehnle void SearchableTableEmitter::collectEnumEntries(
5850ea4d06eSNicolai Haehnle     GenericEnum &Enum, StringRef NameField, StringRef ValueField,
5860ea4d06eSNicolai Haehnle     const std::vector<Record *> &Items) {
5870ea4d06eSNicolai Haehnle   for (auto EntryRec : Items) {
5880ea4d06eSNicolai Haehnle     StringRef Name;
5890ea4d06eSNicolai Haehnle     if (NameField.empty())
5900ea4d06eSNicolai Haehnle       Name = EntryRec->getName();
5910ea4d06eSNicolai Haehnle     else
5920ea4d06eSNicolai Haehnle       Name = EntryRec->getValueAsString(NameField);
5930ea4d06eSNicolai Haehnle 
5940ea4d06eSNicolai Haehnle     int64_t Value = 0;
5950ea4d06eSNicolai Haehnle     if (!ValueField.empty())
5960ea4d06eSNicolai Haehnle       Value = getInt(EntryRec, ValueField);
5970ea4d06eSNicolai Haehnle 
5980eaee545SJonas Devlieghere     Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));
5990ea4d06eSNicolai Haehnle     Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
6000ea4d06eSNicolai Haehnle   }
6010ea4d06eSNicolai Haehnle 
6020ea4d06eSNicolai Haehnle   if (ValueField.empty()) {
603125ea20dSKazu Hirata     llvm::stable_sort(Enum.Entries,
6040ea4d06eSNicolai Haehnle                       [](const std::unique_ptr<GenericEnum::Entry> &LHS,
6050ea4d06eSNicolai Haehnle                          const std::unique_ptr<GenericEnum::Entry> &RHS) {
6060ea4d06eSNicolai Haehnle                         return LHS->first < RHS->first;
6070ea4d06eSNicolai Haehnle                       });
6080ea4d06eSNicolai Haehnle 
6090ea4d06eSNicolai Haehnle     for (size_t i = 0; i < Enum.Entries.size(); ++i)
6100ea4d06eSNicolai Haehnle       Enum.Entries[i]->second = i;
6110ea4d06eSNicolai Haehnle   }
6120ea4d06eSNicolai Haehnle }
6130ea4d06eSNicolai Haehnle 
6140ea4d06eSNicolai Haehnle void SearchableTableEmitter::collectTableEntries(
6150ea4d06eSNicolai Haehnle     GenericTable &Table, const std::vector<Record *> &Items) {
616d668d8b6SSebastian Neubauer   if (Items.empty())
617b3931188SPaul C. Anagnostopoulos     PrintFatalError(Table.Locs,
618b3931188SPaul C. Anagnostopoulos                     Twine("Table '") + Table.Name + "' has no entries");
619d668d8b6SSebastian Neubauer 
6200ea4d06eSNicolai Haehnle   for (auto EntryRec : Items) {
6210ea4d06eSNicolai Haehnle     for (auto &Field : Table.Fields) {
6220ea4d06eSNicolai Haehnle       auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
623a9122758SJay Foad       if (!TI || !TI->isComplete()) {
624b3931188SPaul C. Anagnostopoulos         PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +
625b3931188SPaul C. Anagnostopoulos                                       "' for table '" + Table.Name +
626b3931188SPaul C. Anagnostopoulos                                       "' is missing field '" + Field.Name +
627b3931188SPaul C. Anagnostopoulos                                       "'");
6280ea4d06eSNicolai Haehnle       }
6290ea4d06eSNicolai Haehnle       if (!Field.RecType) {
6300ea4d06eSNicolai Haehnle         Field.RecType = TI->getType();
6310ea4d06eSNicolai Haehnle       } else {
6320ea4d06eSNicolai Haehnle         RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
6330ea4d06eSNicolai Haehnle         if (!Ty)
634b3931188SPaul C. Anagnostopoulos           PrintFatalError(EntryRec->getValue(Field.Name),
635b3931188SPaul C. Anagnostopoulos                           Twine("Field '") + Field.Name + "' of table '" +
636b3931188SPaul C. Anagnostopoulos                           Table.Name + "' entry has incompatible type: " +
637b3931188SPaul C. Anagnostopoulos                           TI->getType()->getAsString() + " vs. " +
638b3931188SPaul C. Anagnostopoulos                           Field.RecType->getAsString());
6390ea4d06eSNicolai Haehnle         Field.RecType = Ty;
6400ea4d06eSNicolai Haehnle       }
6410ea4d06eSNicolai Haehnle     }
6420ea4d06eSNicolai Haehnle 
643b3931188SPaul C. Anagnostopoulos     Table.Entries.push_back(EntryRec); // Add record to table's record list.
6440ea4d06eSNicolai Haehnle   }
6450ea4d06eSNicolai Haehnle 
6460ea4d06eSNicolai Haehnle   Record *IntrinsicClass = Records.getClass("Intrinsic");
6470ea4d06eSNicolai Haehnle   Record *InstructionClass = Records.getClass("Instruction");
6480ea4d06eSNicolai Haehnle   for (auto &Field : Table.Fields) {
649d668d8b6SSebastian Neubauer     if (!Field.RecType)
650d668d8b6SSebastian Neubauer       PrintFatalError(Twine("Cannot determine type of field '") + Field.Name +
651d668d8b6SSebastian Neubauer                       "' in table '" + Table.Name + "'. Maybe it is not used?");
652d668d8b6SSebastian Neubauer 
6530ea4d06eSNicolai Haehnle     if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) {
6540ea4d06eSNicolai Haehnle       if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))
6550ea4d06eSNicolai Haehnle         Field.IsIntrinsic = true;
6560ea4d06eSNicolai Haehnle       else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))
6570ea4d06eSNicolai Haehnle         Field.IsInstruction = true;
6580ea4d06eSNicolai Haehnle     }
6590ea4d06eSNicolai Haehnle   }
660e6ae6767STim Northover }
661e6ae6767STim Northover 
662e6ae6767STim Northover void SearchableTableEmitter::run(raw_ostream &OS) {
6630ea4d06eSNicolai Haehnle   // Emit tables in a deterministic order to avoid needless rebuilds.
6640ea4d06eSNicolai Haehnle   SmallVector<std::unique_ptr<GenericTable>, 4> Tables;
6650ea4d06eSNicolai Haehnle   DenseMap<Record *, GenericTable *> TableMap;
6660ea4d06eSNicolai Haehnle 
6670ea4d06eSNicolai Haehnle   // Collect all definitions first.
6680ea4d06eSNicolai Haehnle   for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
6690ea4d06eSNicolai Haehnle     StringRef NameField;
6700ea4d06eSNicolai Haehnle     if (!EnumRec->isValueUnset("NameField"))
6710ea4d06eSNicolai Haehnle       NameField = EnumRec->getValueAsString("NameField");
6720ea4d06eSNicolai Haehnle 
6730ea4d06eSNicolai Haehnle     StringRef ValueField;
6740ea4d06eSNicolai Haehnle     if (!EnumRec->isValueUnset("ValueField"))
6750ea4d06eSNicolai Haehnle       ValueField = EnumRec->getValueAsString("ValueField");
6760ea4d06eSNicolai Haehnle 
6770eaee545SJonas Devlieghere     auto Enum = std::make_unique<GenericEnum>();
678adcd0268SBenjamin Kramer     Enum->Name = std::string(EnumRec->getName());
679adcd0268SBenjamin Kramer     Enum->PreprocessorGuard = std::string(EnumRec->getName());
6800ea4d06eSNicolai Haehnle 
6810ea4d06eSNicolai Haehnle     StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
6820ea4d06eSNicolai Haehnle     Enum->Class = Records.getClass(FilterClass);
6830ea4d06eSNicolai Haehnle     if (!Enum->Class)
684b3931188SPaul C. Anagnostopoulos       PrintFatalError(EnumRec->getValue("FilterClass"),
685b3931188SPaul C. Anagnostopoulos                       Twine("Enum FilterClass '") + FilterClass +
686b3931188SPaul C. Anagnostopoulos                           "' does not exist");
6870ea4d06eSNicolai Haehnle 
6880ea4d06eSNicolai Haehnle     collectEnumEntries(*Enum, NameField, ValueField,
6890ea4d06eSNicolai Haehnle                        Records.getAllDerivedDefinitions(FilterClass));
6900ea4d06eSNicolai Haehnle     EnumMap.insert(std::make_pair(EnumRec, Enum.get()));
6910ea4d06eSNicolai Haehnle     Enums.emplace_back(std::move(Enum));
6920ea4d06eSNicolai Haehnle   }
6930ea4d06eSNicolai Haehnle 
6940ea4d06eSNicolai Haehnle   for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
6950eaee545SJonas Devlieghere     auto Table = std::make_unique<GenericTable>();
696adcd0268SBenjamin Kramer     Table->Name = std::string(TableRec->getName());
697b3931188SPaul C. Anagnostopoulos     Table->Locs = TableRec->getLoc();
698adcd0268SBenjamin Kramer     Table->PreprocessorGuard = std::string(TableRec->getName());
699adcd0268SBenjamin Kramer     Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName"));
7000ea4d06eSNicolai Haehnle 
7010ea4d06eSNicolai Haehnle     std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");
7020ea4d06eSNicolai Haehnle     for (const auto &FieldName : Fields) {
703b3931188SPaul C. Anagnostopoulos       Table->Fields.emplace_back(FieldName); // Construct a GenericField.
7040ea4d06eSNicolai Haehnle 
705415fab6fSPaul C. Anagnostopoulos       if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
706415fab6fSPaul C. Anagnostopoulos         if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
707415fab6fSPaul C. Anagnostopoulos           PrintError(TypeOfRecordVal,
708dff673bbSDaniel Sanders                      Twine("Table '") + Table->Name +
709b3931188SPaul C. Anagnostopoulos                          "' has invalid 'TypeOf_" + FieldName +
710415fab6fSPaul C. Anagnostopoulos                          "': " + TypeOfRecordVal->getValue()->getAsString());
711415fab6fSPaul C. Anagnostopoulos           PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
712415fab6fSPaul C. Anagnostopoulos                          "GenericEnum record, or \"code\"");
7130ea4d06eSNicolai Haehnle         }
7140ea4d06eSNicolai Haehnle       }
7150ea4d06eSNicolai Haehnle     }
7160ea4d06eSNicolai Haehnle 
717b3931188SPaul C. Anagnostopoulos     StringRef FilterClass = TableRec->getValueAsString("FilterClass");
718b3931188SPaul C. Anagnostopoulos     if (!Records.getClass(FilterClass))
719b3931188SPaul C. Anagnostopoulos       PrintFatalError(TableRec->getValue("FilterClass"),
720b3931188SPaul C. Anagnostopoulos                       Twine("Table FilterClass '") +
721b3931188SPaul C. Anagnostopoulos                           FilterClass + "' does not exist");
722b3931188SPaul C. Anagnostopoulos 
723b3931188SPaul C. Anagnostopoulos     collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
7240ea4d06eSNicolai Haehnle 
7250ea4d06eSNicolai Haehnle     if (!TableRec->isValueUnset("PrimaryKey")) {
7260ea4d06eSNicolai Haehnle       Table->PrimaryKey =
727b3931188SPaul C. Anagnostopoulos           parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
728b3931188SPaul C. Anagnostopoulos                            TableRec->getValueAsString("PrimaryKeyName"),
7290ea4d06eSNicolai Haehnle                            TableRec->getValueAsListOfStrings("PrimaryKey"),
7300ea4d06eSNicolai Haehnle                            TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
7310ea4d06eSNicolai Haehnle 
732125ea20dSKazu Hirata       llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
7330ea4d06eSNicolai Haehnle         return compareBy(LHS, RHS, *Table->PrimaryKey);
7340ea4d06eSNicolai Haehnle       });
7350ea4d06eSNicolai Haehnle     }
7360ea4d06eSNicolai Haehnle 
7370ea4d06eSNicolai Haehnle     TableMap.insert(std::make_pair(TableRec, Table.get()));
7380ea4d06eSNicolai Haehnle     Tables.emplace_back(std::move(Table));
7390ea4d06eSNicolai Haehnle   }
7400ea4d06eSNicolai Haehnle 
7410ea4d06eSNicolai Haehnle   for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {
7420ea4d06eSNicolai Haehnle     Record *TableRec = IndexRec->getValueAsDef("Table");
7430ea4d06eSNicolai Haehnle     auto It = TableMap.find(TableRec);
7440ea4d06eSNicolai Haehnle     if (It == TableMap.end())
745b3931188SPaul C. Anagnostopoulos       PrintFatalError(IndexRec->getValue("Table"),
746dff673bbSDaniel Sanders                       Twine("SearchIndex '") + IndexRec->getName() +
747b3931188SPaul C. Anagnostopoulos                           "' refers to nonexistent table '" +
748dff673bbSDaniel Sanders                           TableRec->getName());
7490ea4d06eSNicolai Haehnle 
7500ea4d06eSNicolai Haehnle     GenericTable &Table = *It->second;
751b3931188SPaul C. Anagnostopoulos     Table.Indices.push_back(
752b3931188SPaul C. Anagnostopoulos         parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
753b3931188SPaul C. Anagnostopoulos                          IndexRec->getValueAsListOfStrings("Key"),
7540ea4d06eSNicolai Haehnle                          IndexRec->getValueAsBit("EarlyOut")));
7550ea4d06eSNicolai Haehnle   }
7560ea4d06eSNicolai Haehnle 
7570ea4d06eSNicolai Haehnle   // Translate legacy tables.
758e6ae6767STim Northover   Record *SearchableTable = Records.getClass("SearchableTable");
759e6ae6767STim Northover   for (auto &NameRec : Records.getClasses()) {
760e6ae6767STim Northover     Record *Class = NameRec.second.get();
761e6ae6767STim Northover     if (Class->getSuperClasses().size() != 1 ||
762e6ae6767STim Northover         !Class->isSubClassOf(SearchableTable))
763e6ae6767STim Northover       continue;
7640ea4d06eSNicolai Haehnle 
7650ea4d06eSNicolai Haehnle     StringRef TableName = Class->getName();
7660ea4d06eSNicolai Haehnle     std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
7670ea4d06eSNicolai Haehnle     if (!Class->isValueUnset("EnumNameField")) {
7680ea4d06eSNicolai Haehnle       StringRef NameField = Class->getValueAsString("EnumNameField");
7690ea4d06eSNicolai Haehnle       StringRef ValueField;
7700ea4d06eSNicolai Haehnle       if (!Class->isValueUnset("EnumValueField"))
7710ea4d06eSNicolai Haehnle         ValueField = Class->getValueAsString("EnumValueField");
7720ea4d06eSNicolai Haehnle 
7730eaee545SJonas Devlieghere       auto Enum = std::make_unique<GenericEnum>();
7740ea4d06eSNicolai Haehnle       Enum->Name = (Twine(Class->getName()) + "Values").str();
7750ea4d06eSNicolai Haehnle       Enum->PreprocessorGuard = Class->getName().upper();
7760ea4d06eSNicolai Haehnle       Enum->Class = Class;
7770ea4d06eSNicolai Haehnle 
7780ea4d06eSNicolai Haehnle       collectEnumEntries(*Enum, NameField, ValueField, Items);
7790ea4d06eSNicolai Haehnle 
7800ea4d06eSNicolai Haehnle       Enums.emplace_back(std::move(Enum));
781e6ae6767STim Northover     }
7820ea4d06eSNicolai Haehnle 
7830eaee545SJonas Devlieghere     auto Table = std::make_unique<GenericTable>();
7840ea4d06eSNicolai Haehnle     Table->Name = (Twine(Class->getName()) + "sList").str();
785b3931188SPaul C. Anagnostopoulos     Table->Locs = Class->getLoc();
7860ea4d06eSNicolai Haehnle     Table->PreprocessorGuard = Class->getName().upper();
787adcd0268SBenjamin Kramer     Table->CppTypeName = std::string(Class->getName());
7880ea4d06eSNicolai Haehnle 
7890ea4d06eSNicolai Haehnle     for (const RecordVal &Field : Class->getValues()) {
790adcd0268SBenjamin Kramer       std::string FieldName = std::string(Field.getName());
7910ea4d06eSNicolai Haehnle 
7920ea4d06eSNicolai Haehnle       // Skip uninteresting fields: either special to us, or injected
7930ea4d06eSNicolai Haehnle       // template parameters (if they contain a ':').
7940ea4d06eSNicolai Haehnle       if (FieldName.find(':') != std::string::npos ||
7950ea4d06eSNicolai Haehnle           FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
7960ea4d06eSNicolai Haehnle           FieldName == "EnumValueField")
7970ea4d06eSNicolai Haehnle         continue;
7980ea4d06eSNicolai Haehnle 
7990ea4d06eSNicolai Haehnle       Table->Fields.emplace_back(FieldName);
8000ea4d06eSNicolai Haehnle     }
8010ea4d06eSNicolai Haehnle 
8020ea4d06eSNicolai Haehnle     collectTableEntries(*Table, Items);
8030ea4d06eSNicolai Haehnle 
8040ea4d06eSNicolai Haehnle     for (const auto &Field :
8050ea4d06eSNicolai Haehnle          Class->getValueAsListOfStrings("SearchableFields")) {
8060ea4d06eSNicolai Haehnle       std::string Name =
8070ea4d06eSNicolai Haehnle           (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
808b3931188SPaul C. Anagnostopoulos       Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
809b3931188SPaul C. Anagnostopoulos                                                 Name, {Field}, false));
8100ea4d06eSNicolai Haehnle     }
8110ea4d06eSNicolai Haehnle 
8120ea4d06eSNicolai Haehnle     Tables.emplace_back(std::move(Table));
8130ea4d06eSNicolai Haehnle   }
8140ea4d06eSNicolai Haehnle 
8150ea4d06eSNicolai Haehnle   // Emit everything.
8160ea4d06eSNicolai Haehnle   for (const auto &Enum : Enums)
8170ea4d06eSNicolai Haehnle     emitGenericEnum(*Enum, OS);
8180ea4d06eSNicolai Haehnle 
8190ea4d06eSNicolai Haehnle   for (const auto &Table : Tables)
8200ea4d06eSNicolai Haehnle     emitGenericTable(*Table, OS);
8210ea4d06eSNicolai Haehnle 
8220ea4d06eSNicolai Haehnle   // Put all #undefs last, to allow multiple sections guarded by the same
8230ea4d06eSNicolai Haehnle   // define.
8240ea4d06eSNicolai Haehnle   for (const auto &Guard : PreprocessorGuards)
8250ea4d06eSNicolai Haehnle     OS << "#undef " << Guard << "\n";
826e6ae6767STim Northover }
827e6ae6767STim Northover 
828e6ae6767STim Northover namespace llvm {
829e6ae6767STim Northover 
830e6ae6767STim Northover void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
831e6ae6767STim Northover   SearchableTableEmitter(RK).run(OS);
832e6ae6767STim Northover }
833e6ae6767STim Northover 
834e6ae6767STim Northover } // End llvm namespace.
835