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