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