1 //===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This tablegen backend emits a generic array initialized by specified fields,
10 // together with companion index tables and lookup functions (binary search,
13 //===----------------------------------------------------------------------===//
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/TableGen/Error.h"
21 #include "llvm/TableGen/Record.h"
22 #include "CodeGenIntrinsics.h"
30 #define DEBUG_TYPE "searchable-table-emitter"
36 int getAsInt(Init
*B
) {
37 return cast
<IntInit
>(B
->convertInitializerTo(IntRecTy::get()))->getValue();
39 int getInt(Record
*R
, StringRef Field
) {
40 return getAsInt(R
->getValueInit(Field
));
44 using Entry
= std::pair
<StringRef
, int64_t>;
48 std::string PreprocessorGuard
;
49 std::vector
<std::unique_ptr
<Entry
>> Entries
;
50 DenseMap
<Record
*, Entry
*> EntryMap
;
55 RecTy
*RecType
= nullptr;
56 bool IsIntrinsic
= false;
57 bool IsInstruction
= false;
58 GenericEnum
*Enum
= nullptr;
60 GenericField(StringRef Name
) : Name(Name
) {}
65 SmallVector
<GenericField
, 1> Fields
;
71 std::string PreprocessorGuard
;
72 std::string CppTypeName
;
73 SmallVector
<GenericField
, 2> Fields
;
74 std::vector
<Record
*> Entries
;
76 std::unique_ptr
<SearchIndex
> PrimaryKey
;
77 SmallVector
<std::unique_ptr
<SearchIndex
>, 2> Indices
;
79 const GenericField
*getFieldByName(StringRef Name
) const {
80 for (const auto &Field
: Fields
) {
81 if (Name
== Field
.Name
)
88 class SearchableTableEmitter
{
89 RecordKeeper
&Records
;
90 DenseMap
<Init
*, std::unique_ptr
<CodeGenIntrinsic
>> Intrinsics
;
91 std::vector
<std::unique_ptr
<GenericEnum
>> Enums
;
92 DenseMap
<Record
*, GenericEnum
*> EnumMap
;
93 std::set
<std::string
> PreprocessorGuards
;
96 SearchableTableEmitter(RecordKeeper
&R
) : Records(R
) {}
98 void run(raw_ostream
&OS
);
101 typedef std::pair
<Init
*, int> SearchTableEntry
;
109 std::string
primaryRepresentation(const GenericField
&Field
, Init
*I
) {
110 if (StringInit
*SI
= dyn_cast
<StringInit
>(I
))
111 return SI
->getAsString();
112 else if (BitsInit
*BI
= dyn_cast
<BitsInit
>(I
))
113 return "0x" + utohexstr(getAsInt(BI
));
114 else if (BitInit
*BI
= dyn_cast
<BitInit
>(I
))
115 return BI
->getValue() ? "true" : "false";
116 else if (CodeInit
*CI
= dyn_cast
<CodeInit
>(I
))
117 return CI
->getValue();
118 else if (Field
.IsIntrinsic
)
119 return "Intrinsic::" + getIntrinsic(I
).EnumName
;
120 else if (Field
.IsInstruction
)
121 return I
->getAsString();
123 return Field
.Enum
->EntryMap
[cast
<DefInit
>(I
)->getDef()]->first
;
124 PrintFatalError(Twine("invalid field type for field '") + Field
.Name
+
125 "', expected: string, bits, bit or code");
128 bool isIntrinsic(Init
*I
) {
129 if (DefInit
*DI
= dyn_cast
<DefInit
>(I
))
130 return DI
->getDef()->isSubClassOf("Intrinsic");
134 CodeGenIntrinsic
&getIntrinsic(Init
*I
) {
135 std::unique_ptr
<CodeGenIntrinsic
> &Intr
= Intrinsics
[I
];
137 Intr
= std::make_unique
<CodeGenIntrinsic
>(cast
<DefInit
>(I
)->getDef());
141 bool compareBy(Record
*LHS
, Record
*RHS
, const SearchIndex
&Index
);
143 bool isIntegral(Init
*I
) {
144 return isa
<BitsInit
>(I
) || isa
<CodeInit
>(I
) || isIntrinsic(I
);
147 std::string
searchableFieldType(const GenericField
&Field
, TypeContext Ctx
) {
148 if (isa
<StringRecTy
>(Field
.RecType
)) {
149 if (Ctx
== TypeInStaticStruct
)
150 return "const char *";
151 if (Ctx
== TypeInTempStruct
)
152 return "std::string";
154 } else if (BitsRecTy
*BI
= dyn_cast
<BitsRecTy
>(Field
.RecType
)) {
155 unsigned NumBits
= BI
->getNumBits();
164 PrintFatalError(Twine("bitfield '") + Field
.Name
+
165 "' too large to search");
166 } else if (Field
.Enum
|| Field
.IsIntrinsic
|| Field
.IsInstruction
)
168 PrintFatalError(Twine("Field '") + Field
.Name
+ "' has unknown type '" +
169 Field
.RecType
->getAsString() + "' to search by");
172 void emitGenericTable(const GenericTable
&Table
, raw_ostream
&OS
);
173 void emitGenericEnum(const GenericEnum
&Enum
, raw_ostream
&OS
);
174 void emitLookupDeclaration(const GenericTable
&Table
,
175 const SearchIndex
&Index
, raw_ostream
&OS
);
176 void emitLookupFunction(const GenericTable
&Table
, const SearchIndex
&Index
,
177 bool IsPrimary
, raw_ostream
&OS
);
178 void emitIfdef(StringRef Guard
, raw_ostream
&OS
);
180 bool parseFieldType(GenericField
&Field
, Init
*II
);
181 std::unique_ptr
<SearchIndex
>
182 parseSearchIndex(GenericTable
&Table
, StringRef Name
,
183 const std::vector
<StringRef
> &Key
, bool EarlyOut
);
184 void collectEnumEntries(GenericEnum
&Enum
, StringRef NameField
,
185 StringRef ValueField
,
186 const std::vector
<Record
*> &Items
);
187 void collectTableEntries(GenericTable
&Table
,
188 const std::vector
<Record
*> &Items
);
191 } // End anonymous namespace.
193 // For search indices that consists of a single field whose numeric value is
194 // known, return that numeric value.
195 static int64_t getNumericKey(const SearchIndex
&Index
, Record
*Rec
) {
196 assert(Index
.Fields
.size() == 1);
198 if (Index
.Fields
[0].Enum
) {
199 Record
*EnumEntry
= Rec
->getValueAsDef(Index
.Fields
[0].Name
);
200 return Index
.Fields
[0].Enum
->EntryMap
[EnumEntry
]->second
;
203 return getInt(Rec
, Index
.Fields
[0].Name
);
206 /// Less-than style comparison between \p LHS and \p RHS according to the
208 bool SearchableTableEmitter::compareBy(Record
*LHS
, Record
*RHS
,
209 const SearchIndex
&Index
) {
210 for (const auto &Field
: Index
.Fields
) {
211 Init
*LHSI
= LHS
->getValueInit(Field
.Name
);
212 Init
*RHSI
= RHS
->getValueInit(Field
.Name
);
214 if (isa
<BitsRecTy
>(Field
.RecType
) || isa
<IntRecTy
>(Field
.RecType
)) {
215 int64_t LHSi
= getAsInt(LHSI
);
216 int64_t RHSi
= getAsInt(RHSI
);
221 } else if (Field
.IsIntrinsic
) {
222 CodeGenIntrinsic
&LHSi
= getIntrinsic(LHSI
);
223 CodeGenIntrinsic
&RHSi
= getIntrinsic(RHSI
);
224 if (std::tie(LHSi
.TargetPrefix
, LHSi
.Name
) <
225 std::tie(RHSi
.TargetPrefix
, RHSi
.Name
))
227 if (std::tie(LHSi
.TargetPrefix
, LHSi
.Name
) >
228 std::tie(RHSi
.TargetPrefix
, RHSi
.Name
))
230 } else if (Field
.IsInstruction
) {
231 // This does not correctly compare the predefined instructions!
232 Record
*LHSr
= cast
<DefInit
>(LHSI
)->getDef();
233 Record
*RHSr
= cast
<DefInit
>(RHSI
)->getDef();
235 bool LHSpseudo
= LHSr
->getValueAsBit("isPseudo");
236 bool RHSpseudo
= RHSr
->getValueAsBit("isPseudo");
237 if (LHSpseudo
&& !RHSpseudo
)
239 if (!LHSpseudo
&& RHSpseudo
)
242 int comp
= LHSr
->getName().compare(RHSr
->getName());
247 } else if (Field
.Enum
) {
248 auto LHSr
= cast
<DefInit
>(LHSI
)->getDef();
249 auto RHSr
= cast
<DefInit
>(RHSI
)->getDef();
250 int64_t LHSv
= Field
.Enum
->EntryMap
[LHSr
]->second
;
251 int64_t RHSv
= Field
.Enum
->EntryMap
[RHSr
]->second
;
257 std::string LHSs
= primaryRepresentation(Field
, LHSI
);
258 std::string RHSs
= primaryRepresentation(Field
, RHSI
);
260 if (isa
<StringRecTy
>(Field
.RecType
)) {
261 LHSs
= StringRef(LHSs
).upper();
262 RHSs
= StringRef(RHSs
).upper();
265 int comp
= LHSs
.compare(RHSs
);
275 void SearchableTableEmitter::emitIfdef(StringRef Guard
, raw_ostream
&OS
) {
276 OS
<< "#ifdef " << Guard
<< "\n";
277 PreprocessorGuards
.insert(Guard
);
280 /// Emit a generic enum.
281 void SearchableTableEmitter::emitGenericEnum(const GenericEnum
&Enum
,
283 emitIfdef((Twine("GET_") + Enum
.PreprocessorGuard
+ "_DECL").str(), OS
);
285 OS
<< "enum " << Enum
.Name
<< " {\n";
286 for (const auto &Entry
: Enum
.Entries
)
287 OS
<< " " << Entry
->first
<< " = " << Entry
->second
<< ",\n";
293 void SearchableTableEmitter::emitLookupFunction(const GenericTable
&Table
,
294 const SearchIndex
&Index
,
298 emitLookupDeclaration(Table
, Index
, OS
);
301 std::vector
<Record
*> IndexRowsStorage
;
302 ArrayRef
<Record
*> IndexRows
;
303 StringRef IndexTypeName
;
307 IndexTypeName
= Table
.CppTypeName
;
308 IndexName
= Table
.Name
;
309 IndexRows
= Table
.Entries
;
311 OS
<< " struct IndexType {\n";
312 for (const auto &Field
: Index
.Fields
) {
313 OS
<< " " << searchableFieldType(Field
, TypeInStaticStruct
) << " "
314 << Field
.Name
<< ";\n";
316 OS
<< " unsigned _index;\n";
319 OS
<< " static const struct IndexType Index[] = {\n";
321 std::vector
<std::pair
<Record
*, unsigned>> Entries
;
322 Entries
.reserve(Table
.Entries
.size());
323 for (unsigned i
= 0; i
< Table
.Entries
.size(); ++i
)
324 Entries
.emplace_back(Table
.Entries
[i
], i
);
326 std::stable_sort(Entries
.begin(), Entries
.end(),
327 [&](const std::pair
<Record
*, unsigned> &LHS
,
328 const std::pair
<Record
*, unsigned> &RHS
) {
329 return compareBy(LHS
.first
, RHS
.first
, Index
);
332 IndexRowsStorage
.reserve(Entries
.size());
333 for (const auto &Entry
: Entries
) {
334 IndexRowsStorage
.push_back(Entry
.first
);
337 bool NeedComma
= false;
338 for (const auto &Field
: Index
.Fields
) {
344 primaryRepresentation(Field
, Entry
.first
->getValueInit(Field
.Name
));
345 if (isa
<StringRecTy
>(Field
.RecType
))
346 Repr
= StringRef(Repr
).upper();
349 OS
<< ", " << Entry
.second
<< " },\n";
354 IndexTypeName
= "IndexType";
356 IndexRows
= IndexRowsStorage
;
359 bool IsContiguous
= false;
361 if (Index
.Fields
.size() == 1 &&
362 (Index
.Fields
[0].Enum
|| isa
<BitsRecTy
>(Index
.Fields
[0].RecType
))) {
364 for (unsigned i
= 0; i
< IndexRows
.size(); ++i
) {
365 if (getNumericKey(Index
, IndexRows
[i
]) != i
) {
366 IsContiguous
= false;
373 OS
<< " auto Table = makeArrayRef(" << IndexName
<< ");\n";
374 OS
<< " size_t Idx = " << Index
.Fields
[0].Name
<< ";\n";
375 OS
<< " return Idx >= Table.size() ? nullptr : ";
379 OS
<< "&" << Table
.Name
<< "[Table[Idx]._index]";
385 if (Index
.EarlyOut
) {
386 const GenericField
&Field
= Index
.Fields
[0];
387 std::string FirstRepr
=
388 primaryRepresentation(Field
, IndexRows
[0]->getValueInit(Field
.Name
));
389 std::string LastRepr
= primaryRepresentation(
390 Field
, IndexRows
.back()->getValueInit(Field
.Name
));
391 OS
<< " if ((" << Field
.Name
<< " < " << FirstRepr
<< ") ||\n";
392 OS
<< " (" << Field
.Name
<< " > " << LastRepr
<< "))\n";
393 OS
<< " return nullptr;\n\n";
396 OS
<< " struct KeyType {\n";
397 for (const auto &Field
: Index
.Fields
) {
398 OS
<< " " << searchableFieldType(Field
, TypeInTempStruct
) << " "
399 << Field
.Name
<< ";\n";
402 OS
<< " KeyType Key = { ";
403 bool NeedComma
= false;
404 for (const auto &Field
: Index
.Fields
) {
410 if (isa
<StringRecTy
>(Field
.RecType
)) {
413 PrintFatalError(Twine("Use a secondary index for case-insensitive "
414 "comparison of field '") +
415 Field
.Name
+ "' in table '" + Table
.Name
+ "'");
420 OS
<< " auto Table = makeArrayRef(" << IndexName
<< ");\n";
421 OS
<< " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
422 OS
<< " [](const " << IndexTypeName
<< " &LHS, const KeyType &RHS) {\n";
424 for (const auto &Field
: Index
.Fields
) {
425 if (isa
<StringRecTy
>(Field
.RecType
)) {
426 OS
<< " int Cmp" << Field
.Name
<< " = StringRef(LHS." << Field
.Name
427 << ").compare(RHS." << Field
.Name
<< ");\n";
428 OS
<< " if (Cmp" << Field
.Name
<< " < 0) return true;\n";
429 OS
<< " if (Cmp" << Field
.Name
<< " > 0) return false;\n";
430 } else if (Field
.Enum
) {
431 // Explicitly cast to unsigned, because the signedness of enums is
432 // compiler-dependent.
433 OS
<< " if ((unsigned)LHS." << Field
.Name
<< " < (unsigned)RHS."
434 << Field
.Name
<< ")\n";
435 OS
<< " return true;\n";
436 OS
<< " if ((unsigned)LHS." << Field
.Name
<< " > (unsigned)RHS."
437 << Field
.Name
<< ")\n";
438 OS
<< " return false;\n";
440 OS
<< " if (LHS." << Field
.Name
<< " < RHS." << Field
.Name
<< ")\n";
441 OS
<< " return true;\n";
442 OS
<< " if (LHS." << Field
.Name
<< " > RHS." << Field
.Name
<< ")\n";
443 OS
<< " return false;\n";
447 OS
<< " return false;\n";
450 OS
<< " if (Idx == Table.end()";
452 for (const auto &Field
: Index
.Fields
)
453 OS
<< " ||\n Key." << Field
.Name
<< " != Idx->" << Field
.Name
;
454 OS
<< ")\n return nullptr;\n";
457 OS
<< " return &*Idx;\n";
459 OS
<< " return &" << Table
.Name
<< "[Idx->_index];\n";
464 void SearchableTableEmitter::emitLookupDeclaration(const GenericTable
&Table
,
465 const SearchIndex
&Index
,
467 OS
<< "const " << Table
.CppTypeName
<< " *" << Index
.Name
<< "(";
469 bool NeedComma
= false;
470 for (const auto &Field
: Index
.Fields
) {
475 OS
<< searchableFieldType(Field
, TypeInArgument
) << " " << Field
.Name
;
480 void SearchableTableEmitter::emitGenericTable(const GenericTable
&Table
,
482 emitIfdef((Twine("GET_") + Table
.PreprocessorGuard
+ "_DECL").str(), OS
);
484 // Emit the declarations for the functions that will perform lookup.
485 if (Table
.PrimaryKey
) {
486 emitLookupDeclaration(Table
, *Table
.PrimaryKey
, OS
);
489 for (const auto &Index
: Table
.Indices
) {
490 emitLookupDeclaration(Table
, *Index
, OS
);
496 emitIfdef((Twine("GET_") + Table
.PreprocessorGuard
+ "_IMPL").str(), OS
);
498 // The primary data table contains all the fields defined for this map.
499 OS
<< "constexpr " << Table
.CppTypeName
<< " " << Table
.Name
<< "[] = {\n";
500 for (unsigned i
= 0; i
< Table
.Entries
.size(); ++i
) {
501 Record
*Entry
= Table
.Entries
[i
];
504 bool NeedComma
= false;
505 for (const auto &Field
: Table
.Fields
) {
510 OS
<< primaryRepresentation(Field
, Entry
->getValueInit(Field
.Name
));
513 OS
<< " }, // " << i
<< "\n";
517 // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
518 // search can be performed by "Thing".
519 if (Table
.PrimaryKey
)
520 emitLookupFunction(Table
, *Table
.PrimaryKey
, true, OS
);
521 for (const auto &Index
: Table
.Indices
)
522 emitLookupFunction(Table
, *Index
, false, OS
);
527 bool SearchableTableEmitter::parseFieldType(GenericField
&Field
, Init
*II
) {
528 if (auto DI
= dyn_cast
<DefInit
>(II
)) {
529 Record
*TypeRec
= DI
->getDef();
530 if (TypeRec
->isSubClassOf("GenericEnum")) {
531 Field
.Enum
= EnumMap
[TypeRec
];
532 Field
.RecType
= RecordRecTy::get(Field
.Enum
->Class
);
540 std::unique_ptr
<SearchIndex
>
541 SearchableTableEmitter::parseSearchIndex(GenericTable
&Table
, StringRef Name
,
542 const std::vector
<StringRef
> &Key
,
544 auto Index
= std::make_unique
<SearchIndex
>();
546 Index
->EarlyOut
= EarlyOut
;
548 for (const auto &FieldName
: Key
) {
549 const GenericField
*Field
= Table
.getFieldByName(FieldName
);
551 PrintFatalError(Twine("Search index '") + Name
+
552 "' refers to non-existing field '" + FieldName
+
553 "' in table '" + Table
.Name
+ "'");
554 Index
->Fields
.push_back(*Field
);
557 if (EarlyOut
&& isa
<StringRecTy
>(Index
->Fields
[0].RecType
)) {
559 "Early-out is not supported for string types (in search index '" +
566 void SearchableTableEmitter::collectEnumEntries(
567 GenericEnum
&Enum
, StringRef NameField
, StringRef ValueField
,
568 const std::vector
<Record
*> &Items
) {
569 for (auto EntryRec
: Items
) {
571 if (NameField
.empty())
572 Name
= EntryRec
->getName();
574 Name
= EntryRec
->getValueAsString(NameField
);
577 if (!ValueField
.empty())
578 Value
= getInt(EntryRec
, ValueField
);
580 Enum
.Entries
.push_back(std::make_unique
<GenericEnum::Entry
>(Name
, Value
));
581 Enum
.EntryMap
.insert(std::make_pair(EntryRec
, Enum
.Entries
.back().get()));
584 if (ValueField
.empty()) {
585 std::stable_sort(Enum
.Entries
.begin(), Enum
.Entries
.end(),
586 [](const std::unique_ptr
<GenericEnum::Entry
> &LHS
,
587 const std::unique_ptr
<GenericEnum::Entry
> &RHS
) {
588 return LHS
->first
< RHS
->first
;
591 for (size_t i
= 0; i
< Enum
.Entries
.size(); ++i
)
592 Enum
.Entries
[i
]->second
= i
;
596 void SearchableTableEmitter::collectTableEntries(
597 GenericTable
&Table
, const std::vector
<Record
*> &Items
) {
598 for (auto EntryRec
: Items
) {
599 for (auto &Field
: Table
.Fields
) {
600 auto TI
= dyn_cast
<TypedInit
>(EntryRec
->getValueInit(Field
.Name
));
602 PrintFatalError(EntryRec
->getLoc(),
603 Twine("Record '") + EntryRec
->getName() +
604 "' in table '" + Table
.Name
+
605 "' is missing field '" + Field
.Name
+ "'");
607 if (!Field
.RecType
) {
608 Field
.RecType
= TI
->getType();
610 RecTy
*Ty
= resolveTypes(Field
.RecType
, TI
->getType());
612 PrintFatalError(Twine("Field '") + Field
.Name
+ "' of table '" +
613 Table
.Name
+ "' has incompatible type: " +
614 Field
.RecType
->getAsString() + " vs. " +
615 TI
->getType()->getAsString());
620 Table
.Entries
.push_back(EntryRec
);
623 Record
*IntrinsicClass
= Records
.getClass("Intrinsic");
624 Record
*InstructionClass
= Records
.getClass("Instruction");
625 for (auto &Field
: Table
.Fields
) {
626 if (auto RecordTy
= dyn_cast
<RecordRecTy
>(Field
.RecType
)) {
627 if (IntrinsicClass
&& RecordTy
->isSubClassOf(IntrinsicClass
))
628 Field
.IsIntrinsic
= true;
629 else if (InstructionClass
&& RecordTy
->isSubClassOf(InstructionClass
))
630 Field
.IsInstruction
= true;
635 void SearchableTableEmitter::run(raw_ostream
&OS
) {
636 // Emit tables in a deterministic order to avoid needless rebuilds.
637 SmallVector
<std::unique_ptr
<GenericTable
>, 4> Tables
;
638 DenseMap
<Record
*, GenericTable
*> TableMap
;
640 // Collect all definitions first.
641 for (auto EnumRec
: Records
.getAllDerivedDefinitions("GenericEnum")) {
643 if (!EnumRec
->isValueUnset("NameField"))
644 NameField
= EnumRec
->getValueAsString("NameField");
646 StringRef ValueField
;
647 if (!EnumRec
->isValueUnset("ValueField"))
648 ValueField
= EnumRec
->getValueAsString("ValueField");
650 auto Enum
= std::make_unique
<GenericEnum
>();
651 Enum
->Name
= EnumRec
->getName();
652 Enum
->PreprocessorGuard
= EnumRec
->getName();
654 StringRef FilterClass
= EnumRec
->getValueAsString("FilterClass");
655 Enum
->Class
= Records
.getClass(FilterClass
);
657 PrintFatalError(EnumRec
->getLoc(), Twine("Enum FilterClass '") +
658 FilterClass
+ "' does not exist");
660 collectEnumEntries(*Enum
, NameField
, ValueField
,
661 Records
.getAllDerivedDefinitions(FilterClass
));
662 EnumMap
.insert(std::make_pair(EnumRec
, Enum
.get()));
663 Enums
.emplace_back(std::move(Enum
));
666 for (auto TableRec
: Records
.getAllDerivedDefinitions("GenericTable")) {
667 auto Table
= std::make_unique
<GenericTable
>();
668 Table
->Name
= TableRec
->getName();
669 Table
->PreprocessorGuard
= TableRec
->getName();
670 Table
->CppTypeName
= TableRec
->getValueAsString("CppTypeName");
672 std::vector
<StringRef
> Fields
= TableRec
->getValueAsListOfStrings("Fields");
673 for (const auto &FieldName
: Fields
) {
674 Table
->Fields
.emplace_back(FieldName
);
676 if (auto TypeOfVal
= TableRec
->getValue(("TypeOf_" + FieldName
).str())) {
677 if (!parseFieldType(Table
->Fields
.back(), TypeOfVal
->getValue())) {
678 PrintFatalError(TableRec
->getLoc(),
679 Twine("Table '") + Table
->Name
+
680 "' has bad 'TypeOf_" + FieldName
+
681 "': " + TypeOfVal
->getValue()->getAsString());
686 collectTableEntries(*Table
, Records
.getAllDerivedDefinitions(
687 TableRec
->getValueAsString("FilterClass")));
689 if (!TableRec
->isValueUnset("PrimaryKey")) {
691 parseSearchIndex(*Table
, TableRec
->getValueAsString("PrimaryKeyName"),
692 TableRec
->getValueAsListOfStrings("PrimaryKey"),
693 TableRec
->getValueAsBit("PrimaryKeyEarlyOut"));
695 std::stable_sort(Table
->Entries
.begin(), Table
->Entries
.end(),
696 [&](Record
*LHS
, Record
*RHS
) {
697 return compareBy(LHS
, RHS
, *Table
->PrimaryKey
);
701 TableMap
.insert(std::make_pair(TableRec
, Table
.get()));
702 Tables
.emplace_back(std::move(Table
));
705 for (Record
*IndexRec
: Records
.getAllDerivedDefinitions("SearchIndex")) {
706 Record
*TableRec
= IndexRec
->getValueAsDef("Table");
707 auto It
= TableMap
.find(TableRec
);
708 if (It
== TableMap
.end())
709 PrintFatalError(IndexRec
->getLoc(),
710 Twine("SearchIndex '") + IndexRec
->getName() +
711 "' refers to non-existing table '" +
712 TableRec
->getName());
714 GenericTable
&Table
= *It
->second
;
715 Table
.Indices
.push_back(parseSearchIndex(
716 Table
, IndexRec
->getName(), IndexRec
->getValueAsListOfStrings("Key"),
717 IndexRec
->getValueAsBit("EarlyOut")));
720 // Translate legacy tables.
721 Record
*SearchableTable
= Records
.getClass("SearchableTable");
722 for (auto &NameRec
: Records
.getClasses()) {
723 Record
*Class
= NameRec
.second
.get();
724 if (Class
->getSuperClasses().size() != 1 ||
725 !Class
->isSubClassOf(SearchableTable
))
728 StringRef TableName
= Class
->getName();
729 std::vector
<Record
*> Items
= Records
.getAllDerivedDefinitions(TableName
);
730 if (!Class
->isValueUnset("EnumNameField")) {
731 StringRef NameField
= Class
->getValueAsString("EnumNameField");
732 StringRef ValueField
;
733 if (!Class
->isValueUnset("EnumValueField"))
734 ValueField
= Class
->getValueAsString("EnumValueField");
736 auto Enum
= std::make_unique
<GenericEnum
>();
737 Enum
->Name
= (Twine(Class
->getName()) + "Values").str();
738 Enum
->PreprocessorGuard
= Class
->getName().upper();
741 collectEnumEntries(*Enum
, NameField
, ValueField
, Items
);
743 Enums
.emplace_back(std::move(Enum
));
746 auto Table
= std::make_unique
<GenericTable
>();
747 Table
->Name
= (Twine(Class
->getName()) + "sList").str();
748 Table
->PreprocessorGuard
= Class
->getName().upper();
749 Table
->CppTypeName
= Class
->getName();
751 for (const RecordVal
&Field
: Class
->getValues()) {
752 std::string FieldName
= Field
.getName();
754 // Skip uninteresting fields: either special to us, or injected
755 // template parameters (if they contain a ':').
756 if (FieldName
.find(':') != std::string::npos
||
757 FieldName
== "SearchableFields" || FieldName
== "EnumNameField" ||
758 FieldName
== "EnumValueField")
761 Table
->Fields
.emplace_back(FieldName
);
764 collectTableEntries(*Table
, Items
);
766 for (const auto &Field
:
767 Class
->getValueAsListOfStrings("SearchableFields")) {
769 (Twine("lookup") + Table
->CppTypeName
+ "By" + Field
).str();
770 Table
->Indices
.push_back(parseSearchIndex(*Table
, Name
, {Field
}, false));
773 Tables
.emplace_back(std::move(Table
));
777 for (const auto &Enum
: Enums
)
778 emitGenericEnum(*Enum
, OS
);
780 for (const auto &Table
: Tables
)
781 emitGenericTable(*Table
, OS
);
783 // Put all #undefs last, to allow multiple sections guarded by the same
785 for (const auto &Guard
: PreprocessorGuards
)
786 OS
<< "#undef " << Guard
<< "\n";
791 void EmitSearchableTables(RecordKeeper
&RK
, raw_ostream
&OS
) {
792 SearchableTableEmitter(RK
).run(OS
);
795 } // End llvm namespace.