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