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"
18*aba43035SDmitri Gribenko #include "llvm/ADT/STLExtras.h"
19e6ae6767STim Northover #include "llvm/ADT/StringExtras.h"
20e6ae6767STim Northover #include "llvm/TableGen/Error.h"
21e6ae6767STim Northover #include "llvm/TableGen/Record.h"
22e6ae6767STim Northover #include <algorithm>
230ea4d06eSNicolai Haehnle #include <set>
24e6ae6767STim Northover #include <string>
25e6ae6767STim Northover #include <vector>
260ea4d06eSNicolai Haehnle 
27e6ae6767STim Northover using namespace llvm;
28e6ae6767STim Northover 
29e6ae6767STim Northover #define DEBUG_TYPE "searchable-table-emitter"
30e6ae6767STim Northover 
31e6ae6767STim Northover namespace {
32e6ae6767STim Northover 
getAsInt(Init * B)330ea4d06eSNicolai Haehnle int getAsInt(Init *B) {
342ac3cd20SRiver Riddle   return cast<IntInit>(
352ac3cd20SRiver Riddle              B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper())))
362ac3cd20SRiver Riddle       ->getValue();
370ea4d06eSNicolai Haehnle }
getInt(Record * R,StringRef Field)380ea4d06eSNicolai Haehnle int getInt(Record *R, StringRef Field) {
390ea4d06eSNicolai Haehnle   return getAsInt(R->getValueInit(Field));
400ea4d06eSNicolai Haehnle }
410ea4d06eSNicolai Haehnle 
420ea4d06eSNicolai Haehnle struct GenericEnum {
430ea4d06eSNicolai Haehnle   using Entry = std::pair<StringRef, int64_t>;
440ea4d06eSNicolai Haehnle 
450ea4d06eSNicolai Haehnle   std::string Name;
46612810e3SSimon Pilgrim   Record *Class = nullptr;
470ea4d06eSNicolai Haehnle   std::string PreprocessorGuard;
480ea4d06eSNicolai Haehnle   std::vector<std::unique_ptr<Entry>> Entries;
490ea4d06eSNicolai Haehnle   DenseMap<Record *, Entry *> EntryMap;
500ea4d06eSNicolai Haehnle };
510ea4d06eSNicolai Haehnle 
520ea4d06eSNicolai Haehnle struct GenericField {
530ea4d06eSNicolai Haehnle   std::string Name;
540ea4d06eSNicolai Haehnle   RecTy *RecType = nullptr;
55415fab6fSPaul C. Anagnostopoulos   bool IsCode = false;
560ea4d06eSNicolai Haehnle   bool IsIntrinsic = false;
570ea4d06eSNicolai Haehnle   bool IsInstruction = false;
580ea4d06eSNicolai Haehnle   GenericEnum *Enum = nullptr;
590ea4d06eSNicolai Haehnle 
GenericField__anon30beeb170111::GenericField60adcd0268SBenjamin Kramer   GenericField(StringRef Name) : Name(std::string(Name)) {}
610ea4d06eSNicolai Haehnle };
620ea4d06eSNicolai Haehnle 
630ea4d06eSNicolai Haehnle struct SearchIndex {
640ea4d06eSNicolai Haehnle   std::string Name;
65b3931188SPaul C. Anagnostopoulos   SMLoc Loc; // Source location of PrimaryKey or Key field definition.
660ea4d06eSNicolai Haehnle   SmallVector<GenericField, 1> Fields;
67612810e3SSimon Pilgrim   bool EarlyOut = false;
680ea4d06eSNicolai Haehnle };
690ea4d06eSNicolai Haehnle 
700ea4d06eSNicolai Haehnle struct GenericTable {
710ea4d06eSNicolai Haehnle   std::string Name;
72b3931188SPaul C. Anagnostopoulos   ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
730ea4d06eSNicolai Haehnle   std::string PreprocessorGuard;
740ea4d06eSNicolai Haehnle   std::string CppTypeName;
750ea4d06eSNicolai Haehnle   SmallVector<GenericField, 2> Fields;
760ea4d06eSNicolai Haehnle   std::vector<Record *> Entries;
770ea4d06eSNicolai Haehnle 
780ea4d06eSNicolai Haehnle   std::unique_ptr<SearchIndex> PrimaryKey;
790ea4d06eSNicolai Haehnle   SmallVector<std::unique_ptr<SearchIndex>, 2> Indices;
800ea4d06eSNicolai Haehnle 
getFieldByName__anon30beeb170111::GenericTable810ea4d06eSNicolai Haehnle   const GenericField *getFieldByName(StringRef Name) const {
820ea4d06eSNicolai Haehnle     for (const auto &Field : Fields) {
830ea4d06eSNicolai Haehnle       if (Name == Field.Name)
840ea4d06eSNicolai Haehnle         return &Field;
850ea4d06eSNicolai Haehnle     }
860ea4d06eSNicolai Haehnle     return nullptr;
870ea4d06eSNicolai Haehnle   }
880ea4d06eSNicolai Haehnle };
890ea4d06eSNicolai Haehnle 
90e6ae6767STim Northover class SearchableTableEmitter {
91e6ae6767STim Northover   RecordKeeper &Records;
92398c0b67SNicolai Haehnle   DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;
930ea4d06eSNicolai Haehnle   std::vector<std::unique_ptr<GenericEnum>> Enums;
940ea4d06eSNicolai Haehnle   DenseMap<Record *, GenericEnum *> EnumMap;
950ea4d06eSNicolai Haehnle   std::set<std::string> PreprocessorGuards;
96e6ae6767STim Northover 
97e6ae6767STim Northover public:
SearchableTableEmitter(RecordKeeper & R)98e6ae6767STim Northover   SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
99e6ae6767STim Northover 
100e6ae6767STim Northover   void run(raw_ostream &OS);
101e6ae6767STim Northover 
102e6ae6767STim Northover private:
103e6ae6767STim Northover   typedef std::pair<Init *, int> SearchTableEntry;
104e6ae6767STim Northover 
1050ea4d06eSNicolai Haehnle   enum TypeContext {
1060ea4d06eSNicolai Haehnle     TypeInStaticStruct,
1070ea4d06eSNicolai Haehnle     TypeInTempStruct,
1080ea4d06eSNicolai Haehnle     TypeInArgument,
1090ea4d06eSNicolai Haehnle   };
110e6ae6767STim Northover 
primaryRepresentation(SMLoc Loc,const GenericField & Field,Init * I)111b3931188SPaul C. Anagnostopoulos   std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
112b3931188SPaul C. Anagnostopoulos                                     Init *I) {
113415fab6fSPaul C. Anagnostopoulos     if (StringInit *SI = dyn_cast<StringInit>(I)) {
114415fab6fSPaul C. Anagnostopoulos       if (Field.IsCode || SI->hasCodeFormat())
115415fab6fSPaul C. Anagnostopoulos         return std::string(SI->getValue());
116415fab6fSPaul C. Anagnostopoulos       else
117e6ae6767STim Northover         return SI->getAsString();
118415fab6fSPaul C. Anagnostopoulos     } else if (BitsInit *BI = dyn_cast<BitsInit>(I))
119e6ae6767STim Northover       return "0x" + utohexstr(getAsInt(BI));
120e6ae6767STim Northover     else if (BitInit *BI = dyn_cast<BitInit>(I))
121e6ae6767STim Northover       return BI->getValue() ? "true" : "false";
1220ea4d06eSNicolai Haehnle     else if (Field.IsIntrinsic)
123398c0b67SNicolai Haehnle       return "Intrinsic::" + getIntrinsic(I).EnumName;
1240ea4d06eSNicolai Haehnle     else if (Field.IsInstruction)
1250ea4d06eSNicolai Haehnle       return I->getAsString();
126d668d8b6SSebastian Neubauer     else if (Field.Enum) {
127d668d8b6SSebastian Neubauer       auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
128d668d8b6SSebastian Neubauer       if (!Entry)
129b3931188SPaul C. Anagnostopoulos         PrintFatalError(Loc,
130b3931188SPaul C. Anagnostopoulos                         Twine("Entry for field '") + Field.Name + "' is null");
131d668d8b6SSebastian Neubauer       return std::string(Entry->first);
132d668d8b6SSebastian Neubauer     }
133b3931188SPaul C. Anagnostopoulos     PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
134b3931188SPaul C. Anagnostopoulos                              "'; expected: bit, bits, string, or code");
135e6ae6767STim Northover   }
136e6ae6767STim Northover 
isIntrinsic(Init * I)137398c0b67SNicolai Haehnle   bool isIntrinsic(Init *I) {
138398c0b67SNicolai Haehnle     if (DefInit *DI = dyn_cast<DefInit>(I))
139398c0b67SNicolai Haehnle       return DI->getDef()->isSubClassOf("Intrinsic");
140398c0b67SNicolai Haehnle     return false;
141398c0b67SNicolai Haehnle   }
142398c0b67SNicolai Haehnle 
getIntrinsic(Init * I)143398c0b67SNicolai Haehnle   CodeGenIntrinsic &getIntrinsic(Init *I) {
144398c0b67SNicolai Haehnle     std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
145398c0b67SNicolai Haehnle     if (!Intr)
14699d18f79Ssstefan1       Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),
14799d18f79Ssstefan1                                                 std::vector<Record *>());
148398c0b67SNicolai Haehnle     return *Intr;
149398c0b67SNicolai Haehnle   }
150398c0b67SNicolai Haehnle 
1510ea4d06eSNicolai Haehnle   bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
1520ea4d06eSNicolai Haehnle 
searchableFieldType(const GenericTable & Table,const SearchIndex & Index,const GenericField & Field,TypeContext Ctx)153b3931188SPaul C. Anagnostopoulos   std::string searchableFieldType(const GenericTable &Table,
154b3931188SPaul C. Anagnostopoulos                                   const SearchIndex &Index,
155b3931188SPaul C. Anagnostopoulos                                   const GenericField &Field, TypeContext Ctx) {
1560ea4d06eSNicolai Haehnle     if (isa<StringRecTy>(Field.RecType)) {
1570ea4d06eSNicolai Haehnle       if (Ctx == TypeInStaticStruct)
158e6ae6767STim Northover         return "const char *";
1590ea4d06eSNicolai Haehnle       if (Ctx == TypeInTempStruct)
1600ea4d06eSNicolai Haehnle         return "std::string";
1610ea4d06eSNicolai Haehnle       return "StringRef";
1620ea4d06eSNicolai Haehnle     } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
163e6ae6767STim Northover       unsigned NumBits = BI->getNumBits();
164e6ae6767STim Northover       if (NumBits <= 8)
1656feb62a4SNicolai Haehnle         return "uint8_t";
1666feb62a4SNicolai Haehnle       if (NumBits <= 16)
1676feb62a4SNicolai Haehnle         return "uint16_t";
1686feb62a4SNicolai Haehnle       if (NumBits <= 32)
1696feb62a4SNicolai Haehnle         return "uint32_t";
1706feb62a4SNicolai Haehnle       if (NumBits <= 64)
1716feb62a4SNicolai Haehnle         return "uint64_t";
172b3931188SPaul C. Anagnostopoulos       PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
173b3931188SPaul C. Anagnostopoulos                                      "' lookup method '" + Index.Name +
174b3931188SPaul C. Anagnostopoulos                                      "', key field '" + Field.Name +
175b3931188SPaul C. Anagnostopoulos                                      "' of type bits is too large");
1760ea4d06eSNicolai Haehnle     } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
177398c0b67SNicolai Haehnle       return "unsigned";
178b3931188SPaul C. Anagnostopoulos     PrintFatalError(Index.Loc,
179b3931188SPaul C. Anagnostopoulos                     Twine("In table '") + Table.Name + "' lookup method '" +
180b3931188SPaul C. Anagnostopoulos                         Index.Name + "', key field '" + Field.Name +
181b3931188SPaul C. Anagnostopoulos                         "' has invalid type: " + Field.RecType->getAsString());
182e6ae6767STim Northover   }
183e6ae6767STim Northover 
1840ea4d06eSNicolai Haehnle   void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
1850ea4d06eSNicolai Haehnle   void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
1860ea4d06eSNicolai Haehnle   void emitLookupDeclaration(const GenericTable &Table,
1870ea4d06eSNicolai Haehnle                              const SearchIndex &Index, raw_ostream &OS);
1880ea4d06eSNicolai Haehnle   void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
1890ea4d06eSNicolai Haehnle                           bool IsPrimary, raw_ostream &OS);
1900ea4d06eSNicolai Haehnle   void emitIfdef(StringRef Guard, raw_ostream &OS);
1910ea4d06eSNicolai Haehnle 
1920ea4d06eSNicolai Haehnle   bool parseFieldType(GenericField &Field, Init *II);
1930ea4d06eSNicolai Haehnle   std::unique_ptr<SearchIndex>
194b3931188SPaul C. Anagnostopoulos   parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
1950ea4d06eSNicolai Haehnle                    const std::vector<StringRef> &Key, bool EarlyOut);
1960ea4d06eSNicolai Haehnle   void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
1970ea4d06eSNicolai Haehnle                           StringRef ValueField,
1980ea4d06eSNicolai Haehnle                           const std::vector<Record *> &Items);
1990ea4d06eSNicolai Haehnle   void collectTableEntries(GenericTable &Table,
2000ea4d06eSNicolai Haehnle                            const std::vector<Record *> &Items);
201e6ae6767STim Northover };
202e6ae6767STim Northover 
203e6ae6767STim Northover } // End anonymous namespace.
204e6ae6767STim Northover 
2050ea4d06eSNicolai Haehnle // For search indices that consists of a single field whose numeric value is
2060ea4d06eSNicolai Haehnle // known, return that numeric value.
getNumericKey(const SearchIndex & Index,Record * Rec)2070ea4d06eSNicolai Haehnle static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
2080ea4d06eSNicolai Haehnle   assert(Index.Fields.size() == 1);
2090ea4d06eSNicolai Haehnle 
2100ea4d06eSNicolai Haehnle   if (Index.Fields[0].Enum) {
2110ea4d06eSNicolai Haehnle     Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);
2120ea4d06eSNicolai Haehnle     return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;
2130ea4d06eSNicolai Haehnle   }
2140ea4d06eSNicolai Haehnle 
2150ea4d06eSNicolai Haehnle   return getInt(Rec, Index.Fields[0].Name);
2160ea4d06eSNicolai Haehnle }
2170ea4d06eSNicolai Haehnle 
2180ea4d06eSNicolai Haehnle /// Less-than style comparison between \p LHS and \p RHS according to the
2190ea4d06eSNicolai Haehnle /// key of \p Index.
compareBy(Record * LHS,Record * RHS,const SearchIndex & Index)2200ea4d06eSNicolai Haehnle bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
2210ea4d06eSNicolai Haehnle                                        const SearchIndex &Index) {
2220ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
2230ea4d06eSNicolai Haehnle     Init *LHSI = LHS->getValueInit(Field.Name);
2240ea4d06eSNicolai Haehnle     Init *RHSI = RHS->getValueInit(Field.Name);
2250ea4d06eSNicolai Haehnle 
2260ea4d06eSNicolai Haehnle     if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) {
2270ea4d06eSNicolai Haehnle       int64_t LHSi = getAsInt(LHSI);
2280ea4d06eSNicolai Haehnle       int64_t RHSi = getAsInt(RHSI);
2290ea4d06eSNicolai Haehnle       if (LHSi < RHSi)
2300ea4d06eSNicolai Haehnle         return true;
2310ea4d06eSNicolai Haehnle       if (LHSi > RHSi)
2320ea4d06eSNicolai Haehnle         return false;
2330ea4d06eSNicolai Haehnle     } else if (Field.IsIntrinsic) {
2340ea4d06eSNicolai Haehnle       CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);
2350ea4d06eSNicolai Haehnle       CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);
2360ea4d06eSNicolai Haehnle       if (std::tie(LHSi.TargetPrefix, LHSi.Name) <
2370ea4d06eSNicolai Haehnle           std::tie(RHSi.TargetPrefix, RHSi.Name))
2380ea4d06eSNicolai Haehnle         return true;
2390ea4d06eSNicolai Haehnle       if (std::tie(LHSi.TargetPrefix, LHSi.Name) >
2400ea4d06eSNicolai Haehnle           std::tie(RHSi.TargetPrefix, RHSi.Name))
2410ea4d06eSNicolai Haehnle         return false;
2420ea4d06eSNicolai Haehnle     } else if (Field.IsInstruction) {
2430ea4d06eSNicolai Haehnle       // This does not correctly compare the predefined instructions!
2440ea4d06eSNicolai Haehnle       Record *LHSr = cast<DefInit>(LHSI)->getDef();
2450ea4d06eSNicolai Haehnle       Record *RHSr = cast<DefInit>(RHSI)->getDef();
2460ea4d06eSNicolai Haehnle 
2470ea4d06eSNicolai Haehnle       bool LHSpseudo = LHSr->getValueAsBit("isPseudo");
2480ea4d06eSNicolai Haehnle       bool RHSpseudo = RHSr->getValueAsBit("isPseudo");
2490ea4d06eSNicolai Haehnle       if (LHSpseudo && !RHSpseudo)
2500ea4d06eSNicolai Haehnle         return true;
2510ea4d06eSNicolai Haehnle       if (!LHSpseudo && RHSpseudo)
2520ea4d06eSNicolai Haehnle         return false;
2530ea4d06eSNicolai Haehnle 
2540ea4d06eSNicolai Haehnle       int comp = LHSr->getName().compare(RHSr->getName());
2550ea4d06eSNicolai Haehnle       if (comp < 0)
2560ea4d06eSNicolai Haehnle         return true;
2570ea4d06eSNicolai Haehnle       if (comp > 0)
2580ea4d06eSNicolai Haehnle         return false;
2590ea4d06eSNicolai Haehnle     } else if (Field.Enum) {
2600ea4d06eSNicolai Haehnle       auto LHSr = cast<DefInit>(LHSI)->getDef();
2610ea4d06eSNicolai Haehnle       auto RHSr = cast<DefInit>(RHSI)->getDef();
2620ea4d06eSNicolai Haehnle       int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
2630ea4d06eSNicolai Haehnle       int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
2640ea4d06eSNicolai Haehnle       if (LHSv < RHSv)
2650ea4d06eSNicolai Haehnle         return true;
2660ea4d06eSNicolai Haehnle       if (LHSv > RHSv)
2670ea4d06eSNicolai Haehnle         return false;
2680ea4d06eSNicolai Haehnle     } else {
269b3931188SPaul C. Anagnostopoulos       std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);
270b3931188SPaul C. Anagnostopoulos       std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);
2710ea4d06eSNicolai Haehnle 
2720ea4d06eSNicolai Haehnle       if (isa<StringRecTy>(Field.RecType)) {
2730ea4d06eSNicolai Haehnle         LHSs = StringRef(LHSs).upper();
2740ea4d06eSNicolai Haehnle         RHSs = StringRef(RHSs).upper();
2750ea4d06eSNicolai Haehnle       }
2760ea4d06eSNicolai Haehnle 
2770ea4d06eSNicolai Haehnle       int comp = LHSs.compare(RHSs);
2780ea4d06eSNicolai Haehnle       if (comp < 0)
2790ea4d06eSNicolai Haehnle         return true;
2800ea4d06eSNicolai Haehnle       if (comp > 0)
2810ea4d06eSNicolai Haehnle         return false;
2820ea4d06eSNicolai Haehnle     }
2830ea4d06eSNicolai Haehnle   }
2840ea4d06eSNicolai Haehnle   return false;
2850ea4d06eSNicolai Haehnle }
2860ea4d06eSNicolai Haehnle 
emitIfdef(StringRef Guard,raw_ostream & OS)2870ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {
2880ea4d06eSNicolai Haehnle   OS << "#ifdef " << Guard << "\n";
289adcd0268SBenjamin Kramer   PreprocessorGuards.insert(std::string(Guard));
2900ea4d06eSNicolai Haehnle }
2910ea4d06eSNicolai Haehnle 
2920ea4d06eSNicolai Haehnle /// Emit a generic enum.
emitGenericEnum(const GenericEnum & Enum,raw_ostream & OS)2930ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
294e6ae6767STim Northover                                              raw_ostream &OS) {
2950ea4d06eSNicolai Haehnle   emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
296e6ae6767STim Northover 
2970ea4d06eSNicolai Haehnle   OS << "enum " << Enum.Name << " {\n";
2980ea4d06eSNicolai Haehnle   for (const auto &Entry : Enum.Entries)
2990ea4d06eSNicolai Haehnle     OS << "  " << Entry->first << " = " << Entry->second << ",\n";
3000ea4d06eSNicolai Haehnle   OS << "};\n";
3010ea4d06eSNicolai Haehnle 
3020ea4d06eSNicolai Haehnle   OS << "#endif\n\n";
303e6ae6767STim Northover }
304e6ae6767STim Northover 
emitLookupFunction(const GenericTable & Table,const SearchIndex & Index,bool IsPrimary,raw_ostream & OS)3050ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
3060ea4d06eSNicolai Haehnle                                                 const SearchIndex &Index,
3070ea4d06eSNicolai Haehnle                                                 bool IsPrimary,
3080ea4d06eSNicolai Haehnle                                                 raw_ostream &OS) {
3090ea4d06eSNicolai Haehnle   OS << "\n";
3100ea4d06eSNicolai Haehnle   emitLookupDeclaration(Table, Index, OS);
3110ea4d06eSNicolai Haehnle   OS << " {\n";
312e6ae6767STim Northover 
3130ea4d06eSNicolai Haehnle   std::vector<Record *> IndexRowsStorage;
3140ea4d06eSNicolai Haehnle   ArrayRef<Record *> IndexRows;
3150ea4d06eSNicolai Haehnle   StringRef IndexTypeName;
3160ea4d06eSNicolai Haehnle   StringRef IndexName;
3170ea4d06eSNicolai Haehnle 
3180ea4d06eSNicolai Haehnle   if (IsPrimary) {
3190ea4d06eSNicolai Haehnle     IndexTypeName = Table.CppTypeName;
3200ea4d06eSNicolai Haehnle     IndexName = Table.Name;
3210ea4d06eSNicolai Haehnle     IndexRows = Table.Entries;
3220ea4d06eSNicolai Haehnle   } else {
3230ea4d06eSNicolai Haehnle     OS << "  struct IndexType {\n";
3240ea4d06eSNicolai Haehnle     for (const auto &Field : Index.Fields) {
325b3931188SPaul C. Anagnostopoulos       OS << "    "
326b3931188SPaul C. Anagnostopoulos          << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "
3270ea4d06eSNicolai Haehnle          << Field.Name << ";\n";
3280ea4d06eSNicolai Haehnle     }
3290ea4d06eSNicolai Haehnle     OS << "    unsigned _index;\n";
3300ea4d06eSNicolai Haehnle     OS << "  };\n";
3310ea4d06eSNicolai Haehnle 
3320ea4d06eSNicolai Haehnle     OS << "  static const struct IndexType Index[] = {\n";
3330ea4d06eSNicolai Haehnle 
3340ea4d06eSNicolai Haehnle     std::vector<std::pair<Record *, unsigned>> Entries;
3350ea4d06eSNicolai Haehnle     Entries.reserve(Table.Entries.size());
3360ea4d06eSNicolai Haehnle     for (unsigned i = 0; i < Table.Entries.size(); ++i)
3370ea4d06eSNicolai Haehnle       Entries.emplace_back(Table.Entries[i], i);
3380ea4d06eSNicolai Haehnle 
339125ea20dSKazu Hirata     llvm::stable_sort(Entries, [&](const std::pair<Record *, unsigned> &LHS,
3400ea4d06eSNicolai Haehnle                                    const std::pair<Record *, unsigned> &RHS) {
3410ea4d06eSNicolai Haehnle       return compareBy(LHS.first, RHS.first, Index);
3420ea4d06eSNicolai Haehnle     });
3430ea4d06eSNicolai Haehnle 
3440ea4d06eSNicolai Haehnle     IndexRowsStorage.reserve(Entries.size());
3450ea4d06eSNicolai Haehnle     for (const auto &Entry : Entries) {
3460ea4d06eSNicolai Haehnle       IndexRowsStorage.push_back(Entry.first);
3470ea4d06eSNicolai Haehnle 
348e6ae6767STim Northover       OS << "    { ";
34994c35084SKazu Hirata       ListSeparator LS;
3500ea4d06eSNicolai Haehnle       for (const auto &Field : Index.Fields) {
351b3931188SPaul C. Anagnostopoulos         std::string Repr = primaryRepresentation(
352b3931188SPaul C. Anagnostopoulos             Index.Loc, Field, Entry.first->getValueInit(Field.Name));
3530ea4d06eSNicolai Haehnle         if (isa<StringRecTy>(Field.RecType))
3540ea4d06eSNicolai Haehnle           Repr = StringRef(Repr).upper();
35594c35084SKazu Hirata         OS << LS << Repr;
356e6ae6767STim Northover       }
3570ea4d06eSNicolai Haehnle       OS << ", " << Entry.second << " },\n";
358e6ae6767STim Northover     }
3590ea4d06eSNicolai Haehnle 
360e6ae6767STim Northover     OS << "  };\n\n";
3610ea4d06eSNicolai Haehnle 
3620ea4d06eSNicolai Haehnle     IndexTypeName = "IndexType";
3630ea4d06eSNicolai Haehnle     IndexName = "Index";
3640ea4d06eSNicolai Haehnle     IndexRows = IndexRowsStorage;
365e6ae6767STim Northover   }
366e6ae6767STim Northover 
3670ea4d06eSNicolai Haehnle   bool IsContiguous = false;
368e6ae6767STim Northover 
3690ea4d06eSNicolai Haehnle   if (Index.Fields.size() == 1 &&
3700ea4d06eSNicolai Haehnle       (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) {
3710ea4d06eSNicolai Haehnle     IsContiguous = true;
3720ea4d06eSNicolai Haehnle     for (unsigned i = 0; i < IndexRows.size(); ++i) {
3730ea4d06eSNicolai Haehnle       if (getNumericKey(Index, IndexRows[i]) != i) {
3740ea4d06eSNicolai Haehnle         IsContiguous = false;
3750ea4d06eSNicolai Haehnle         break;
3760ea4d06eSNicolai Haehnle       }
3770ea4d06eSNicolai Haehnle     }
3780ea4d06eSNicolai Haehnle   }
3790ea4d06eSNicolai Haehnle 
3800ea4d06eSNicolai Haehnle   if (IsContiguous) {
3810ea4d06eSNicolai Haehnle     OS << "  auto Table = makeArrayRef(" << IndexName << ");\n";
3820ea4d06eSNicolai Haehnle     OS << "  size_t Idx = " << Index.Fields[0].Name << ";\n";
3830ea4d06eSNicolai Haehnle     OS << "  return Idx >= Table.size() ? nullptr : ";
3840ea4d06eSNicolai Haehnle     if (IsPrimary)
3850ea4d06eSNicolai Haehnle       OS << "&Table[Idx]";
3860ea4d06eSNicolai Haehnle     else
3870ea4d06eSNicolai Haehnle       OS << "&" << Table.Name << "[Table[Idx]._index]";
3880ea4d06eSNicolai Haehnle     OS << ";\n";
3890ea4d06eSNicolai Haehnle     OS << "}\n";
3900ea4d06eSNicolai Haehnle     return;
3910ea4d06eSNicolai Haehnle   }
3920ea4d06eSNicolai Haehnle 
3930ea4d06eSNicolai Haehnle   if (Index.EarlyOut) {
3940ea4d06eSNicolai Haehnle     const GenericField &Field = Index.Fields[0];
395b3931188SPaul C. Anagnostopoulos     std::string FirstRepr = primaryRepresentation(
396b3931188SPaul C. Anagnostopoulos         Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));
3970ea4d06eSNicolai Haehnle     std::string LastRepr = primaryRepresentation(
398b3931188SPaul C. Anagnostopoulos         Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));
3990ea4d06eSNicolai Haehnle     OS << "  if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
4000ea4d06eSNicolai Haehnle     OS << "      (" << Field.Name << " > " << LastRepr << "))\n";
4010ea4d06eSNicolai Haehnle     OS << "    return nullptr;\n\n";
4020ea4d06eSNicolai Haehnle   }
4030ea4d06eSNicolai Haehnle 
4040ea4d06eSNicolai Haehnle   OS << "  struct KeyType {\n";
4050ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
406b3931188SPaul C. Anagnostopoulos     OS << "    " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
407b3931188SPaul C. Anagnostopoulos        << " " << Field.Name << ";\n";
4080ea4d06eSNicolai Haehnle   }
4090ea4d06eSNicolai Haehnle   OS << "  };\n";
4100ea4d06eSNicolai Haehnle   OS << "  KeyType Key = {";
4116bfb02caSKazu Hirata   ListSeparator LS;
4120ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
4136bfb02caSKazu Hirata     OS << LS << Field.Name;
4140ea4d06eSNicolai Haehnle     if (isa<StringRecTy>(Field.RecType)) {
4150ea4d06eSNicolai Haehnle       OS << ".upper()";
4160ea4d06eSNicolai Haehnle       if (IsPrimary)
417b3931188SPaul C. Anagnostopoulos         PrintFatalError(Index.Loc,
418b3931188SPaul C. Anagnostopoulos                         Twine("In table '") + Table.Name +
419b3931188SPaul C. Anagnostopoulos                             "', use a secondary lookup method for "
420b3931188SPaul C. Anagnostopoulos                             "case-insensitive comparison of field '" +
421b3931188SPaul C. Anagnostopoulos                             Field.Name + "'");
4220ea4d06eSNicolai Haehnle     }
4230ea4d06eSNicolai Haehnle   }
4240ea4d06eSNicolai Haehnle   OS << "};\n";
4250ea4d06eSNicolai Haehnle 
4260ea4d06eSNicolai Haehnle   OS << "  auto Table = makeArrayRef(" << IndexName << ");\n";
4270ea4d06eSNicolai Haehnle   OS << "  auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
4280ea4d06eSNicolai Haehnle   OS << "    [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
4290ea4d06eSNicolai Haehnle 
4300ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields) {
4310ea4d06eSNicolai Haehnle     if (isa<StringRecTy>(Field.RecType)) {
4320ea4d06eSNicolai Haehnle       OS << "      int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
4330ea4d06eSNicolai Haehnle          << ").compare(RHS." << Field.Name << ");\n";
4340ea4d06eSNicolai Haehnle       OS << "      if (Cmp" << Field.Name << " < 0) return true;\n";
4350ea4d06eSNicolai Haehnle       OS << "      if (Cmp" << Field.Name << " > 0) return false;\n";
436ba9eee5fSNicolai Haehnle     } else if (Field.Enum) {
437ba9eee5fSNicolai Haehnle       // Explicitly cast to unsigned, because the signedness of enums is
438ba9eee5fSNicolai Haehnle       // compiler-dependent.
439ba9eee5fSNicolai Haehnle       OS << "      if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
440ba9eee5fSNicolai Haehnle          << Field.Name << ")\n";
441ba9eee5fSNicolai Haehnle       OS << "        return true;\n";
442ba9eee5fSNicolai Haehnle       OS << "      if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
443ba9eee5fSNicolai Haehnle          << Field.Name << ")\n";
444ba9eee5fSNicolai Haehnle       OS << "        return false;\n";
445e6ae6767STim Northover     } else {
4460ea4d06eSNicolai Haehnle       OS << "      if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
4470ea4d06eSNicolai Haehnle       OS << "        return true;\n";
4480ea4d06eSNicolai Haehnle       OS << "      if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
4490ea4d06eSNicolai Haehnle       OS << "        return false;\n";
4500ea4d06eSNicolai Haehnle     }
451e6ae6767STim Northover   }
452e6ae6767STim Northover 
4530ea4d06eSNicolai Haehnle   OS << "      return false;\n";
454e6ae6767STim Northover   OS << "    });\n\n";
4550ea4d06eSNicolai Haehnle 
4560ea4d06eSNicolai Haehnle   OS << "  if (Idx == Table.end()";
4570ea4d06eSNicolai Haehnle 
4580ea4d06eSNicolai Haehnle   for (const auto &Field : Index.Fields)
4590ea4d06eSNicolai Haehnle     OS << " ||\n      Key." << Field.Name << " != Idx->" << Field.Name;
4600ea4d06eSNicolai Haehnle   OS << ")\n    return nullptr;\n";
4610ea4d06eSNicolai Haehnle 
4620ea4d06eSNicolai Haehnle   if (IsPrimary)
4630ea4d06eSNicolai Haehnle     OS << "  return &*Idx;\n";
4640ea4d06eSNicolai Haehnle   else
4650ea4d06eSNicolai Haehnle     OS << "  return &" << Table.Name << "[Idx->_index];\n";
4660ea4d06eSNicolai Haehnle 
4670ea4d06eSNicolai Haehnle   OS << "}\n";
468e6ae6767STim Northover }
469e6ae6767STim Northover 
emitLookupDeclaration(const GenericTable & Table,const SearchIndex & Index,raw_ostream & OS)4700ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
4710ea4d06eSNicolai Haehnle                                                    const SearchIndex &Index,
472e6ae6767STim Northover                                                    raw_ostream &OS) {
4730ea4d06eSNicolai Haehnle   OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
4740ea4d06eSNicolai Haehnle 
4756bfb02caSKazu Hirata   ListSeparator LS;
4766bfb02caSKazu Hirata   for (const auto &Field : Index.Fields)
4776bfb02caSKazu Hirata     OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
478b3931188SPaul C. Anagnostopoulos        << Field.Name;
4790ea4d06eSNicolai Haehnle   OS << ")";
480e6ae6767STim Northover }
481e6ae6767STim Northover 
emitGenericTable(const GenericTable & Table,raw_ostream & OS)4820ea4d06eSNicolai Haehnle void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
483e6ae6767STim Northover                                               raw_ostream &OS) {
4840ea4d06eSNicolai Haehnle   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);
485e6ae6767STim Northover 
4860ea4d06eSNicolai Haehnle   // Emit the declarations for the functions that will perform lookup.
4870ea4d06eSNicolai Haehnle   if (Table.PrimaryKey) {
4880ea4d06eSNicolai Haehnle     emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
4890ea4d06eSNicolai Haehnle     OS << ";\n";
490e6ae6767STim Northover   }
4910ea4d06eSNicolai Haehnle   for (const auto &Index : Table.Indices) {
4920ea4d06eSNicolai Haehnle     emitLookupDeclaration(Table, *Index, OS);
4930ea4d06eSNicolai Haehnle     OS << ";\n";
494e6ae6767STim Northover   }
495e6ae6767STim Northover 
496e6ae6767STim Northover   OS << "#endif\n\n";
497e6ae6767STim Northover 
4980ea4d06eSNicolai Haehnle   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
499e6ae6767STim Northover 
500e6ae6767STim Northover   // The primary data table contains all the fields defined for this map.
50116b32291SBenjamin Kramer   OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
5020ea4d06eSNicolai Haehnle   for (unsigned i = 0; i < Table.Entries.size(); ++i) {
5030ea4d06eSNicolai Haehnle     Record *Entry = Table.Entries[i];
5040ea4d06eSNicolai Haehnle     OS << "  { ";
5050ea4d06eSNicolai Haehnle 
50694c35084SKazu Hirata     ListSeparator LS;
50794c35084SKazu Hirata     for (const auto &Field : Table.Fields)
50894c35084SKazu Hirata       OS << LS
50994c35084SKazu Hirata          << primaryRepresentation(Table.Locs[0], Field,
510b3931188SPaul C. Anagnostopoulos                                   Entry->getValueInit(Field.Name));
5110ea4d06eSNicolai Haehnle 
5120ea4d06eSNicolai Haehnle     OS << " }, // " << i << "\n";
5130ea4d06eSNicolai Haehnle   }
5140ea4d06eSNicolai Haehnle   OS << " };\n";
515e6ae6767STim Northover 
516e6ae6767STim Northover   // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
517e6ae6767STim Northover   // search can be performed by "Thing".
5180ea4d06eSNicolai Haehnle   if (Table.PrimaryKey)
5190ea4d06eSNicolai Haehnle     emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
5200ea4d06eSNicolai Haehnle   for (const auto &Index : Table.Indices)
5210ea4d06eSNicolai Haehnle     emitLookupFunction(Table, *Index, false, OS);
5220ea4d06eSNicolai Haehnle 
5230ea4d06eSNicolai Haehnle   OS << "#endif\n\n";
524e6ae6767STim Northover }
525e6ae6767STim Northover 
parseFieldType(GenericField & Field,Init * TypeOf)526415fab6fSPaul C. Anagnostopoulos bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
527415fab6fSPaul C. Anagnostopoulos   if (auto Type = dyn_cast<StringInit>(TypeOf)) {
528415fab6fSPaul C. Anagnostopoulos     if (Type->getValue() == "code") {
529415fab6fSPaul C. Anagnostopoulos       Field.IsCode = true;
530415fab6fSPaul C. Anagnostopoulos       return true;
531415fab6fSPaul C. Anagnostopoulos     } else {
532415fab6fSPaul C. Anagnostopoulos       if (Record *TypeRec = Records.getDef(Type->getValue())) {
5330ea4d06eSNicolai Haehnle         if (TypeRec->isSubClassOf("GenericEnum")) {
5340ea4d06eSNicolai Haehnle           Field.Enum = EnumMap[TypeRec];
5350ea4d06eSNicolai Haehnle           Field.RecType = RecordRecTy::get(Field.Enum->Class);
5360ea4d06eSNicolai Haehnle           return true;
5370ea4d06eSNicolai Haehnle         }
5380ea4d06eSNicolai Haehnle       }
539415fab6fSPaul C. Anagnostopoulos     }
540415fab6fSPaul C. Anagnostopoulos   }
5410ea4d06eSNicolai Haehnle 
5420ea4d06eSNicolai Haehnle   return false;
5430ea4d06eSNicolai Haehnle }
5440ea4d06eSNicolai Haehnle 
parseSearchIndex(GenericTable & Table,const RecordVal * KeyRecVal,StringRef Name,const std::vector<StringRef> & Key,bool EarlyOut)545b3931188SPaul C. Anagnostopoulos std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
546b3931188SPaul C. Anagnostopoulos     GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
547b3931188SPaul C. Anagnostopoulos     const std::vector<StringRef> &Key, bool EarlyOut) {
5480eaee545SJonas Devlieghere   auto Index = std::make_unique<SearchIndex>();
549adcd0268SBenjamin Kramer   Index->Name = std::string(Name);
550b3931188SPaul C. Anagnostopoulos   Index->Loc = KeyRecVal->getLoc();
5510ea4d06eSNicolai Haehnle   Index->EarlyOut = EarlyOut;
5520ea4d06eSNicolai Haehnle 
5530ea4d06eSNicolai Haehnle   for (const auto &FieldName : Key) {
5540ea4d06eSNicolai Haehnle     const GenericField *Field = Table.getFieldByName(FieldName);
5550ea4d06eSNicolai Haehnle     if (!Field)
556b3931188SPaul C. Anagnostopoulos       PrintFatalError(
557b3931188SPaul C. Anagnostopoulos           KeyRecVal,
558b3931188SPaul C. Anagnostopoulos           Twine("In table '") + Table.Name +
559b3931188SPaul C. Anagnostopoulos               "', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
560b3931188SPaul C. Anagnostopoulos               FieldName + "'");
561b3931188SPaul C. Anagnostopoulos 
5620ea4d06eSNicolai Haehnle     Index->Fields.push_back(*Field);
5630ea4d06eSNicolai Haehnle   }
5640ea4d06eSNicolai Haehnle 
5650ea4d06eSNicolai Haehnle   if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
5660ea4d06eSNicolai Haehnle     PrintFatalError(
567b3931188SPaul C. Anagnostopoulos         KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +
568b3931188SPaul C. Anagnostopoulos                        "supported for a first key field of type string");
5690ea4d06eSNicolai Haehnle   }
5700ea4d06eSNicolai Haehnle 
5710ea4d06eSNicolai Haehnle   return Index;
5720ea4d06eSNicolai Haehnle }
5730ea4d06eSNicolai Haehnle 
collectEnumEntries(GenericEnum & Enum,StringRef NameField,StringRef ValueField,const std::vector<Record * > & Items)5740ea4d06eSNicolai Haehnle void SearchableTableEmitter::collectEnumEntries(
5750ea4d06eSNicolai Haehnle     GenericEnum &Enum, StringRef NameField, StringRef ValueField,
5760ea4d06eSNicolai Haehnle     const std::vector<Record *> &Items) {
5770ea4d06eSNicolai Haehnle   for (auto EntryRec : Items) {
5780ea4d06eSNicolai Haehnle     StringRef Name;
5790ea4d06eSNicolai Haehnle     if (NameField.empty())
5800ea4d06eSNicolai Haehnle       Name = EntryRec->getName();
5810ea4d06eSNicolai Haehnle     else
5820ea4d06eSNicolai Haehnle       Name = EntryRec->getValueAsString(NameField);
5830ea4d06eSNicolai Haehnle 
5840ea4d06eSNicolai Haehnle     int64_t Value = 0;
5850ea4d06eSNicolai Haehnle     if (!ValueField.empty())
5860ea4d06eSNicolai Haehnle       Value = getInt(EntryRec, ValueField);
5870ea4d06eSNicolai Haehnle 
5880eaee545SJonas Devlieghere     Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));
5890ea4d06eSNicolai Haehnle     Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
5900ea4d06eSNicolai Haehnle   }
5910ea4d06eSNicolai Haehnle 
5920ea4d06eSNicolai Haehnle   if (ValueField.empty()) {
593125ea20dSKazu Hirata     llvm::stable_sort(Enum.Entries,
5940ea4d06eSNicolai Haehnle                       [](const std::unique_ptr<GenericEnum::Entry> &LHS,
5950ea4d06eSNicolai Haehnle                          const std::unique_ptr<GenericEnum::Entry> &RHS) {
5960ea4d06eSNicolai Haehnle                         return LHS->first < RHS->first;
5970ea4d06eSNicolai Haehnle                       });
5980ea4d06eSNicolai Haehnle 
5990ea4d06eSNicolai Haehnle     for (size_t i = 0; i < Enum.Entries.size(); ++i)
6000ea4d06eSNicolai Haehnle       Enum.Entries[i]->second = i;
6010ea4d06eSNicolai Haehnle   }
6020ea4d06eSNicolai Haehnle }
6030ea4d06eSNicolai Haehnle 
collectTableEntries(GenericTable & Table,const std::vector<Record * > & Items)6040ea4d06eSNicolai Haehnle void SearchableTableEmitter::collectTableEntries(
6050ea4d06eSNicolai Haehnle     GenericTable &Table, const std::vector<Record *> &Items) {
606d668d8b6SSebastian Neubauer   if (Items.empty())
607b3931188SPaul C. Anagnostopoulos     PrintFatalError(Table.Locs,
608b3931188SPaul C. Anagnostopoulos                     Twine("Table '") + Table.Name + "' has no entries");
609d668d8b6SSebastian Neubauer 
6100ea4d06eSNicolai Haehnle   for (auto EntryRec : Items) {
6110ea4d06eSNicolai Haehnle     for (auto &Field : Table.Fields) {
6120ea4d06eSNicolai Haehnle       auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
613a9122758SJay Foad       if (!TI || !TI->isComplete()) {
614b3931188SPaul C. Anagnostopoulos         PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +
615b3931188SPaul C. Anagnostopoulos                                       "' for table '" + Table.Name +
616b3931188SPaul C. Anagnostopoulos                                       "' is missing field '" + Field.Name +
617b3931188SPaul C. Anagnostopoulos                                       "'");
6180ea4d06eSNicolai Haehnle       }
6190ea4d06eSNicolai Haehnle       if (!Field.RecType) {
6200ea4d06eSNicolai Haehnle         Field.RecType = TI->getType();
6210ea4d06eSNicolai Haehnle       } else {
6220ea4d06eSNicolai Haehnle         RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
6230ea4d06eSNicolai Haehnle         if (!Ty)
624b3931188SPaul C. Anagnostopoulos           PrintFatalError(EntryRec->getValue(Field.Name),
625b3931188SPaul C. Anagnostopoulos                           Twine("Field '") + Field.Name + "' of table '" +
626b3931188SPaul C. Anagnostopoulos                           Table.Name + "' entry has incompatible type: " +
627b3931188SPaul C. Anagnostopoulos                           TI->getType()->getAsString() + " vs. " +
628b3931188SPaul C. Anagnostopoulos                           Field.RecType->getAsString());
6290ea4d06eSNicolai Haehnle         Field.RecType = Ty;
6300ea4d06eSNicolai Haehnle       }
6310ea4d06eSNicolai Haehnle     }
6320ea4d06eSNicolai Haehnle 
633b3931188SPaul C. Anagnostopoulos     Table.Entries.push_back(EntryRec); // Add record to table's record list.
6340ea4d06eSNicolai Haehnle   }
6350ea4d06eSNicolai Haehnle 
6360ea4d06eSNicolai Haehnle   Record *IntrinsicClass = Records.getClass("Intrinsic");
6370ea4d06eSNicolai Haehnle   Record *InstructionClass = Records.getClass("Instruction");
6380ea4d06eSNicolai Haehnle   for (auto &Field : Table.Fields) {
639d668d8b6SSebastian Neubauer     if (!Field.RecType)
640d668d8b6SSebastian Neubauer       PrintFatalError(Twine("Cannot determine type of field '") + Field.Name +
641d668d8b6SSebastian Neubauer                       "' in table '" + Table.Name + "'. Maybe it is not used?");
642d668d8b6SSebastian Neubauer 
6430ea4d06eSNicolai Haehnle     if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) {
6440ea4d06eSNicolai Haehnle       if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))
6450ea4d06eSNicolai Haehnle         Field.IsIntrinsic = true;
6460ea4d06eSNicolai Haehnle       else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))
6470ea4d06eSNicolai Haehnle         Field.IsInstruction = true;
6480ea4d06eSNicolai Haehnle     }
6490ea4d06eSNicolai Haehnle   }
65051f743dbSTim Northover 
65151f743dbSTim Northover   SearchIndex Idx;
65251f743dbSTim Northover   std::copy(Table.Fields.begin(), Table.Fields.end(),
65351f743dbSTim Northover             std::back_inserter(Idx.Fields));
654*aba43035SDmitri Gribenko   llvm::sort(Table.Entries, [&](Record *LHS, Record *RHS) {
655*aba43035SDmitri Gribenko     return compareBy(LHS, RHS, Idx);
656*aba43035SDmitri Gribenko   });
657e6ae6767STim Northover }
658e6ae6767STim Northover 
run(raw_ostream & OS)659e6ae6767STim Northover void SearchableTableEmitter::run(raw_ostream &OS) {
6600ea4d06eSNicolai Haehnle   // Emit tables in a deterministic order to avoid needless rebuilds.
6610ea4d06eSNicolai Haehnle   SmallVector<std::unique_ptr<GenericTable>, 4> Tables;
6620ea4d06eSNicolai Haehnle   DenseMap<Record *, GenericTable *> TableMap;
6630ea4d06eSNicolai Haehnle 
6640ea4d06eSNicolai Haehnle   // Collect all definitions first.
6650ea4d06eSNicolai Haehnle   for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
6660ea4d06eSNicolai Haehnle     StringRef NameField;
6670ea4d06eSNicolai Haehnle     if (!EnumRec->isValueUnset("NameField"))
6680ea4d06eSNicolai Haehnle       NameField = EnumRec->getValueAsString("NameField");
6690ea4d06eSNicolai Haehnle 
6700ea4d06eSNicolai Haehnle     StringRef ValueField;
6710ea4d06eSNicolai Haehnle     if (!EnumRec->isValueUnset("ValueField"))
6720ea4d06eSNicolai Haehnle       ValueField = EnumRec->getValueAsString("ValueField");
6730ea4d06eSNicolai Haehnle 
6740eaee545SJonas Devlieghere     auto Enum = std::make_unique<GenericEnum>();
675adcd0268SBenjamin Kramer     Enum->Name = std::string(EnumRec->getName());
676adcd0268SBenjamin Kramer     Enum->PreprocessorGuard = std::string(EnumRec->getName());
6770ea4d06eSNicolai Haehnle 
6780ea4d06eSNicolai Haehnle     StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
6790ea4d06eSNicolai Haehnle     Enum->Class = Records.getClass(FilterClass);
6800ea4d06eSNicolai Haehnle     if (!Enum->Class)
681b3931188SPaul C. Anagnostopoulos       PrintFatalError(EnumRec->getValue("FilterClass"),
682b3931188SPaul C. Anagnostopoulos                       Twine("Enum FilterClass '") + FilterClass +
683b3931188SPaul C. Anagnostopoulos                           "' does not exist");
6840ea4d06eSNicolai Haehnle 
6850ea4d06eSNicolai Haehnle     collectEnumEntries(*Enum, NameField, ValueField,
6860ea4d06eSNicolai Haehnle                        Records.getAllDerivedDefinitions(FilterClass));
6870ea4d06eSNicolai Haehnle     EnumMap.insert(std::make_pair(EnumRec, Enum.get()));
6880ea4d06eSNicolai Haehnle     Enums.emplace_back(std::move(Enum));
6890ea4d06eSNicolai Haehnle   }
6900ea4d06eSNicolai Haehnle 
6910ea4d06eSNicolai Haehnle   for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
6920eaee545SJonas Devlieghere     auto Table = std::make_unique<GenericTable>();
693adcd0268SBenjamin Kramer     Table->Name = std::string(TableRec->getName());
694b3931188SPaul C. Anagnostopoulos     Table->Locs = TableRec->getLoc();
695adcd0268SBenjamin Kramer     Table->PreprocessorGuard = std::string(TableRec->getName());
696adcd0268SBenjamin Kramer     Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName"));
6970ea4d06eSNicolai Haehnle 
6980ea4d06eSNicolai Haehnle     std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");
6990ea4d06eSNicolai Haehnle     for (const auto &FieldName : Fields) {
700b3931188SPaul C. Anagnostopoulos       Table->Fields.emplace_back(FieldName); // Construct a GenericField.
7010ea4d06eSNicolai Haehnle 
702415fab6fSPaul C. Anagnostopoulos       if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
703415fab6fSPaul C. Anagnostopoulos         if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
704415fab6fSPaul C. Anagnostopoulos           PrintError(TypeOfRecordVal,
705dff673bbSDaniel Sanders                      Twine("Table '") + Table->Name +
706b3931188SPaul C. Anagnostopoulos                          "' has invalid 'TypeOf_" + FieldName +
707415fab6fSPaul C. Anagnostopoulos                          "': " + TypeOfRecordVal->getValue()->getAsString());
708415fab6fSPaul C. Anagnostopoulos           PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
709415fab6fSPaul C. Anagnostopoulos                          "GenericEnum record, or \"code\"");
7100ea4d06eSNicolai Haehnle         }
7110ea4d06eSNicolai Haehnle       }
7120ea4d06eSNicolai Haehnle     }
7130ea4d06eSNicolai Haehnle 
714b3931188SPaul C. Anagnostopoulos     StringRef FilterClass = TableRec->getValueAsString("FilterClass");
715b3931188SPaul C. Anagnostopoulos     if (!Records.getClass(FilterClass))
716b3931188SPaul C. Anagnostopoulos       PrintFatalError(TableRec->getValue("FilterClass"),
717b3931188SPaul C. Anagnostopoulos                       Twine("Table FilterClass '") +
718b3931188SPaul C. Anagnostopoulos                           FilterClass + "' does not exist");
719b3931188SPaul C. Anagnostopoulos 
720b3931188SPaul C. Anagnostopoulos     collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
7210ea4d06eSNicolai Haehnle 
7220ea4d06eSNicolai Haehnle     if (!TableRec->isValueUnset("PrimaryKey")) {
7230ea4d06eSNicolai Haehnle       Table->PrimaryKey =
724b3931188SPaul C. Anagnostopoulos           parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
725b3931188SPaul C. Anagnostopoulos                            TableRec->getValueAsString("PrimaryKeyName"),
7260ea4d06eSNicolai Haehnle                            TableRec->getValueAsListOfStrings("PrimaryKey"),
7270ea4d06eSNicolai Haehnle                            TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
7280ea4d06eSNicolai Haehnle 
729125ea20dSKazu Hirata       llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
7300ea4d06eSNicolai Haehnle         return compareBy(LHS, RHS, *Table->PrimaryKey);
7310ea4d06eSNicolai Haehnle       });
7320ea4d06eSNicolai Haehnle     }
7330ea4d06eSNicolai Haehnle 
7340ea4d06eSNicolai Haehnle     TableMap.insert(std::make_pair(TableRec, Table.get()));
7350ea4d06eSNicolai Haehnle     Tables.emplace_back(std::move(Table));
7360ea4d06eSNicolai Haehnle   }
7370ea4d06eSNicolai Haehnle 
7380ea4d06eSNicolai Haehnle   for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {
7390ea4d06eSNicolai Haehnle     Record *TableRec = IndexRec->getValueAsDef("Table");
7400ea4d06eSNicolai Haehnle     auto It = TableMap.find(TableRec);
7410ea4d06eSNicolai Haehnle     if (It == TableMap.end())
742b3931188SPaul C. Anagnostopoulos       PrintFatalError(IndexRec->getValue("Table"),
743dff673bbSDaniel Sanders                       Twine("SearchIndex '") + IndexRec->getName() +
744b3931188SPaul C. Anagnostopoulos                           "' refers to nonexistent table '" +
745dff673bbSDaniel Sanders                           TableRec->getName());
7460ea4d06eSNicolai Haehnle 
7470ea4d06eSNicolai Haehnle     GenericTable &Table = *It->second;
748b3931188SPaul C. Anagnostopoulos     Table.Indices.push_back(
749b3931188SPaul C. Anagnostopoulos         parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
750b3931188SPaul C. Anagnostopoulos                          IndexRec->getValueAsListOfStrings("Key"),
7510ea4d06eSNicolai Haehnle                          IndexRec->getValueAsBit("EarlyOut")));
7520ea4d06eSNicolai Haehnle   }
7530ea4d06eSNicolai Haehnle 
7540ea4d06eSNicolai Haehnle   // Translate legacy tables.
755e6ae6767STim Northover   Record *SearchableTable = Records.getClass("SearchableTable");
756e6ae6767STim Northover   for (auto &NameRec : Records.getClasses()) {
757e6ae6767STim Northover     Record *Class = NameRec.second.get();
758e6ae6767STim Northover     if (Class->getSuperClasses().size() != 1 ||
759e6ae6767STim Northover         !Class->isSubClassOf(SearchableTable))
760e6ae6767STim Northover       continue;
7610ea4d06eSNicolai Haehnle 
7620ea4d06eSNicolai Haehnle     StringRef TableName = Class->getName();
7630ea4d06eSNicolai Haehnle     std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
7640ea4d06eSNicolai Haehnle     if (!Class->isValueUnset("EnumNameField")) {
7650ea4d06eSNicolai Haehnle       StringRef NameField = Class->getValueAsString("EnumNameField");
7660ea4d06eSNicolai Haehnle       StringRef ValueField;
7670ea4d06eSNicolai Haehnle       if (!Class->isValueUnset("EnumValueField"))
7680ea4d06eSNicolai Haehnle         ValueField = Class->getValueAsString("EnumValueField");
7690ea4d06eSNicolai Haehnle 
7700eaee545SJonas Devlieghere       auto Enum = std::make_unique<GenericEnum>();
7710ea4d06eSNicolai Haehnle       Enum->Name = (Twine(Class->getName()) + "Values").str();
7720ea4d06eSNicolai Haehnle       Enum->PreprocessorGuard = Class->getName().upper();
7730ea4d06eSNicolai Haehnle       Enum->Class = Class;
7740ea4d06eSNicolai Haehnle 
7750ea4d06eSNicolai Haehnle       collectEnumEntries(*Enum, NameField, ValueField, Items);
7760ea4d06eSNicolai Haehnle 
7770ea4d06eSNicolai Haehnle       Enums.emplace_back(std::move(Enum));
778e6ae6767STim Northover     }
7790ea4d06eSNicolai Haehnle 
7800eaee545SJonas Devlieghere     auto Table = std::make_unique<GenericTable>();
7810ea4d06eSNicolai Haehnle     Table->Name = (Twine(Class->getName()) + "sList").str();
782b3931188SPaul C. Anagnostopoulos     Table->Locs = Class->getLoc();
7830ea4d06eSNicolai Haehnle     Table->PreprocessorGuard = Class->getName().upper();
784adcd0268SBenjamin Kramer     Table->CppTypeName = std::string(Class->getName());
7850ea4d06eSNicolai Haehnle 
7860ea4d06eSNicolai Haehnle     for (const RecordVal &Field : Class->getValues()) {
787adcd0268SBenjamin Kramer       std::string FieldName = std::string(Field.getName());
7880ea4d06eSNicolai Haehnle 
7890ea4d06eSNicolai Haehnle       // Skip uninteresting fields: either special to us, or injected
7900ea4d06eSNicolai Haehnle       // template parameters (if they contain a ':').
7910ea4d06eSNicolai Haehnle       if (FieldName.find(':') != std::string::npos ||
7920ea4d06eSNicolai Haehnle           FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
7930ea4d06eSNicolai Haehnle           FieldName == "EnumValueField")
7940ea4d06eSNicolai Haehnle         continue;
7950ea4d06eSNicolai Haehnle 
7960ea4d06eSNicolai Haehnle       Table->Fields.emplace_back(FieldName);
7970ea4d06eSNicolai Haehnle     }
7980ea4d06eSNicolai Haehnle 
7990ea4d06eSNicolai Haehnle     collectTableEntries(*Table, Items);
8000ea4d06eSNicolai Haehnle 
8010ea4d06eSNicolai Haehnle     for (const auto &Field :
8020ea4d06eSNicolai Haehnle          Class->getValueAsListOfStrings("SearchableFields")) {
8030ea4d06eSNicolai Haehnle       std::string Name =
8040ea4d06eSNicolai Haehnle           (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
805b3931188SPaul C. Anagnostopoulos       Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
806b3931188SPaul C. Anagnostopoulos                                                 Name, {Field}, false));
8070ea4d06eSNicolai Haehnle     }
8080ea4d06eSNicolai Haehnle 
8090ea4d06eSNicolai Haehnle     Tables.emplace_back(std::move(Table));
8100ea4d06eSNicolai Haehnle   }
8110ea4d06eSNicolai Haehnle 
8120ea4d06eSNicolai Haehnle   // Emit everything.
8130ea4d06eSNicolai Haehnle   for (const auto &Enum : Enums)
8140ea4d06eSNicolai Haehnle     emitGenericEnum(*Enum, OS);
8150ea4d06eSNicolai Haehnle 
8160ea4d06eSNicolai Haehnle   for (const auto &Table : Tables)
8170ea4d06eSNicolai Haehnle     emitGenericTable(*Table, OS);
8180ea4d06eSNicolai Haehnle 
8190ea4d06eSNicolai Haehnle   // Put all #undefs last, to allow multiple sections guarded by the same
8200ea4d06eSNicolai Haehnle   // define.
8210ea4d06eSNicolai Haehnle   for (const auto &Guard : PreprocessorGuards)
8220ea4d06eSNicolai Haehnle     OS << "#undef " << Guard << "\n";
823e6ae6767STim Northover }
824e6ae6767STim Northover 
825e6ae6767STim Northover namespace llvm {
826e6ae6767STim Northover 
EmitSearchableTables(RecordKeeper & RK,raw_ostream & OS)827e6ae6767STim Northover void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
828e6ae6767STim Northover   SearchableTableEmitter(RK).run(OS);
829e6ae6767STim Northover }
830e6ae6767STim Northover 
831e6ae6767STim Northover } // End llvm namespace.
832