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