llvm.org GIT mirror llvm / 2b1cd51
TableGen/SearchableTables: Support more generic enums and tables Summary: This is essentially a rewrite of the backend which introduces TableGen base classes GenericEnum, GenericTable, and SearchIndex. They allow generating custom enums and tables with lookup functions using separately defined records as the underlying database. Also added as part of this change: - Lookup functions may use indices composed of multiple fields. - Instruction fields are supported similar to Intrinsic fields. - When the lookup key has contiguous numeric values, the lookup function will directly index into the table instead of using a binary search. The existing SearchableTable functionality is internally mapped to the new primitives. Change-Id: I444f3490fa1dbfb262d7286a1660a2c4308e9932 Reviewers: arsenm, tra, t.p.northover Subscribers: wdng, llvm-commits Differential Revision: https://reviews.llvm.org/D48013 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@335225 91177308-0d34-0410-b5e6-96231b3b80d8 Nicolai Haehnle 1 year, 3 months ago
6 changed file(s) with 987 addition(s) and 268 deletion(s). Raw diff Collapse all Expand all
219219 -------------
220220
221221 **Purpose**: Print enum values for a class.
222
223 SearchableTables
224 ----------------
225
226 **Purpose**: Generate custom searchable tables.
227
228 **Output**: Enums, global tables and lookup helper functions.
229
230 **Usage**: This backend allows generating free-form, target-specific tables
231 from TableGen records. The ARM and AArch64 targets use this backend to generate
232 tables of system registers; the AMDGPU target uses it to generate meta-data
233 about complex image and memory buffer instructions.
234
235 More documentation is available in ``include/llvm/TableGen/SearchableTable.td``,
236 which also contains the definitions of TableGen classes which must be
237 instantiated in order to define the enums and tables emitted by this backend.
222238
223239 CTags
224240 -----
77 //===----------------------------------------------------------------------===//
88 //
99 // This file defines the key top-level classes needed to produce a reasonably
10 // generic table that can be binary-searched via int and string entries.
10 // generic table that can be binary-searched. Three types of objects can be
11 // defined using the classes in this file:
1112 //
12 // Each table must instantiate "Mappingkind", listing the fields that should be
13 // included and fields that shoould be searchable. Only two kinds of fields are
14 // searchable at the moment: "strings" (which are compared case-insensitively),
15 // and "bits".
13 // 1. (Generic) Enums. By instantiating the GenericEnum class once, an enum with
14 // the name of the def is generated. It is guarded by the preprocessor define
15 // GET_name_DECL, where name is the name of the def.
1616 //
17 // For each "MappingKind" the generated header will create GET_MAPPINGKIND_DECL
18 // and GET_MAPPINGKIND_IMPL guards.
17 // 2. (Generic) Tables and search indices. By instantiating the GenericTable
18 // class once, a table with the name of the instantiating def is generated and
19 // guarded by the GET_name_IMPL preprocessor guard.
1920 //
20 // Inside the DECL guard will be a set of function declarations:
21 // "lookup{InstanceClass}By{SearchableField}", returning "const {InstanceClass}
22 // *" and accepting either a StringRef or a uintN_t. Additionally, if
23 // EnumNameField is still defined, there will be an "enum {InstanceClass}Values"
24 // allowing C++ code to reference either the primary data table's entries (if
25 // EnumValueField is not defined) or some other field (e.g. encoding) if it is.
26 //
27 // Inside the IMPL guard will be a primary data table "{InstanceClass}sList" and
28 // as many searchable indexes as requested
29 // ("{InstanceClass}sBy{SearchableField}"). Additionally implementations of the
30 // lookup function will be provided.
21 // Both a primary key and additional secondary keys / search indices can also
22 // be defined, which result in the generation of lookup functions. Their
23 // declarations and definitions are all guarded by GET_name_DECL and
24 // GET_name_IMPL, respectively, where name is the name of the underlying table.
3125 //
3226 // See AArch64SystemOperands.td and its generated header for example uses.
3327 //
3428 //===----------------------------------------------------------------------===//
3529
30 // Define a record derived from this class to generate a generic enum.
31 //
32 // The name of the record is used as the type name of the C++ enum.
33 class GenericEnum {
34 // Name of a TableGen class. The enum will have one entry for each record
35 // that derives from that class.
36 string FilterClass;
37
38 // (Optional) Name of a field that is present in all collected records and
39 // contains the name of enum entries.
40 //
41 // If NameField is not set, the record names will be used instead.
42 string NameField;
43
44 // (Optional) Name of a field that is present in all collected records and
45 // contains the numerical value of enum entries.
46 //
47 // If ValueField is not set, enum values will be assigned automatically,
48 // starting at 0, according to a lexicographical sort of the entry names.
49 string ValueField;
50 }
51
52 // Define a record derived from this class to generate a generic table. This
53 // table can have a searchable primary key, and it can also be referenced by
54 // external search indices.
55 //
56 // The name of the record is used as the name of the global primary array of
57 // entries of the table in C++.
58 class GenericTable {
59 // Name of a class. The table will have one entry for each record that
60 // derives from that class.
61 string FilterClass;
62
63 // Name of the C++ struct/class type that holds table entries. The
64 // declaration of this type is not generated automatically.
65 string CppTypeName = FilterClass;
66
67 // List of the names of fields of collected records that contain the data for
68 // table entries, in the order that is used for initialization in C++.
69 //
70 // For each field of the table named XXX, TableGen will look for a value
71 // called TypeOf_XXX and use that as a more detailed description of the
72 // type of the field if present. This is required for fields whose type
73 // cannot be deduced automatically, such as enum fields. For example:
74 //
75 // def MyEnum : GenericEnum {
76 // let FilterClass = "MyEnum";
77 // ...
78 // }
79 //
80 // class MyTableEntry {
81 // MyEnum V;
82 // ...
83 // }
84 //
85 // def MyTable : GenericTable {
86 // let FilterClass = "MyTableEntry";
87 // let Fields = ["V", ...];
88 // GenericEnum TypeOf_V = MyEnum;
89 // }
90 //
91 // Fields of type bit, bits, string, Intrinsic, and Instruction (or
92 // derived classes of those) are supported natively.
93 //
94 // Additionally, fields of type `code` can appear, where the value is used
95 // verbatim as an initializer. However, these fields cannot be used as
96 // search keys.
97 list Fields;
98
99 // (Optional) List of fields that make up the primary key.
100 list PrimaryKey;
101
102 // (Optional) Name of the primary key search function.
103 string PrimaryKeyName;
104
105 // See SearchIndex.EarlyOut
106 bit PrimaryKeyEarlyOut = 0;
107 }
108
109 // Define a record derived from this class to generate an additional search
110 // index for a generic table that has been defined earlier.
111 //
112 // The name of the record will be used as the name of the C++ lookup function.
113 class SearchIndex {
114 // Table that this search index refers to.
115 GenericTable Table;
116
117 // List of fields that make up the key.
118 list Key;
119
120 // If true, the lookup function will check the first field of the key against
121 // the minimum and maximum values in the index before entering the binary
122 // search. This is convenient for tables that add extended data for a subset
123 // of a larger enum-based space, e.g. extended data about a subset of
124 // instructions.
125 //
126 // Can only be used when the first field is an integral (non-string) type.
127 bit EarlyOut = 0;
128 }
129
130 // Legacy table type with integrated enum.
36131 class SearchableTable {
37132 list SearchableFields;
38133 string EnumNameField = "Name";
0 // RUN: llvm-tblgen -gen-searchable-tables -I %p/../../include %s | FileCheck %s
1 // XFAIL: vg_leak
2
3 include "llvm/TableGen/SearchableTable.td"
4
5 // CHECK-LABEL: GET_InstrTable_IMPL
6 // CHECK: const MyInstr InstrTable[] = {
7 // CHECK: { B, 0xA },
8 // CHECK: { C, 0x0 },
9 // CHECK: { A, 0x5 },
10 // CHECK: { D, 0x8 },
11 // CHECK: };
12
13 class Instruction {
14 bit isPseudo = 0;
15 }
16
17 class MyInstr : Instruction {
18 Instruction Opcode = !cast(NAME);
19 bits<16> CustomEncoding = op;
20 }
21
22 def A : MyInstr<5>;
23 def D : MyInstr<8>;
24 let isPseudo = 1 in {
25 def C : MyInstr<0>;
26 def B : MyInstr<10>;
27 }
28
29 def InstrTable : GenericTable {
30 let FilterClass = "MyInstr";
31 let Fields = ["Opcode", "CustomEncoding"];
32
33 let PrimaryKey = ["Opcode"];
34 let PrimaryKeyName = "getCustomEncodingHelper";
35 }
0 // RUN: llvm-tblgen -gen-searchable-tables -I %p/../../include %s | FileCheck %s
1 // XFAIL: vg_leak
2
3 include "llvm/TableGen/SearchableTable.td"
4
5 // CHECK-LABEL: GET_BValues_DECL
6 // CHECK: enum BValues {
7 // CHECK: BAlice = 172,
8 // CHECK: BBob = 20,
9 // CHECK: BCharlie = 128,
10 // CHECK: BEve = 76,
11 // CHECK: }
12
13 // CHECK-LABEL: GET_CEnum_DECL
14 // CHECK: enum CEnum {
15 // CHECK: CBar
16 // CHECK: CBaz
17 // CHECK: CFoo
18 // CHECK: }
19
20 // CHECK-LABEL: GET_ATable_DECL
21 // CHECK: const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2);
22
23 // CHECK-LABEL: GET_ATable_IMPL
24 // CHECK: const AEntry ATable[] = {
25 // CHECK: { "baz"
26 // CHECK: { "foo"
27 // CHECK: { "foobar"
28 // CHECK: { "bar"
29 // CHECK: };
30
31 // CHECK: const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
32 // CHECK: return &*Idx;
33 // CHECK: }
34
35 class AEntry {
36 string Str = str;
37 bits<8> Val1 = val1;
38 bits<10> Val2 = val2;
39 }
40
41 def : AEntry<"bar", 5, 3>;
42 def : AEntry<"baz", 2, 6>;
43 def : AEntry<"foo", 4, 4>;
44 def : AEntry<"foobar", 4, 5>;
45
46 def ATable : GenericTable {
47 let FilterClass = "AEntry";
48 let Fields = ["Str", "Val1", "Val2"];
49
50 let PrimaryKey = ["Val1", "Val2"];
51 let PrimaryKeyName = "lookupATableByValues";
52 }
53
54
55 // CHECK-LABEL: GET_BTable_IMPL
56 // CHECK: const BTypeName *lookupBTableByName(StringRef Name) {
57 // CHECK: return &BTable[Idx->_index];
58 // CHECK: }
59
60 class BEntry enc> {
61 string Name = NAME;
62 bits<16> Encoding = enc;
63 }
64
65 def BAlice : BEntry<0xac>;
66 def BBob : BEntry<0x14>;
67 def BCharlie : BEntry<0x80>;
68 def BEve : BEntry<0x4c>;
69
70 def BValues : GenericEnum {
71 let FilterClass = "BEntry";
72 let NameField = "Name";
73 let ValueField = "Encoding";
74 }
75
76 def BTable : GenericTable {
77 let FilterClass = "BEntry";
78 string CppTypeName = "BTypeName";
79 let Fields = ["Name", "Encoding"];
80 }
81
82 def lookupBTableByName : SearchIndex {
83 let Table = BTable;
84 let Key = ["Name"];
85 }
86
87
88 // CHECK-LABEL: GET_CTable_DECL
89 // CHECK: const CEntry *lookupCEntryByEncoding(uint16_t Encoding);
90 // CHECK: const CEntry *lookupCEntry(StringRef Name, unsigned Kind);
91 // CHECK-LABEL: GET_CTable_IMPL
92 // CHECK: const CEntry *lookupCEntryByEncoding(uint16_t Encoding) {
93 // CHECK: if ((Encoding < 0xA) ||
94 // CHECK: (Encoding > 0xF))
95 // CHECK: return nullptr;
96
97 // CHECK: const CEntry *lookupCEntry(StringRef Name, unsigned Kind) {
98 // CHECK: Index[] = {
99 // CHECK: { "ALICE", CBar, 1 },
100 // CHECK: { "ALICE", CFoo, 0 },
101 // CHECK: { "BOB", CBaz, 2 },
102
103 class CEnum;
104
105 def CFoo : CEnum;
106 def CBar : CEnum;
107 def CBaz : CEnum;
108
109 def CEnum : GenericEnum {
110 let FilterClass = "CEnum";
111 }
112
113 class CEntry {
114 string Name = name;
115 CEnum Kind = kind;
116 bits<16> Encoding = enc;
117 }
118
119 def : CEntry<"alice", CFoo, 10>;
120 def : CEntry<"alice", CBar, 13>;
121 def : CEntry<"bob", CBaz, 15>;
122
123 def CTable : GenericTable {
124 let FilterClass = "CEntry";
125 let Fields = ["Name", "Kind", "Encoding"];
126
127 GenericEnum TypeOf_Kind = CEnum;
128
129 let PrimaryKey = ["Encoding"];
130 let PrimaryKeyName = "lookupCEntryByEncoding";
131 let PrimaryKeyEarlyOut = 1;
132 }
133
134 def lookupCEntry : SearchIndex {
135 let Table = CTable;
136 let Key = ["Name", "Kind"];
137 }
5252 }
5353
5454 // CHECK-LABEL: TablesList[] = {
55 // CHECK-DAG: { Intrinsic::abc, 0x0},
56 // CHECK-DAG: { Intrinsic::xyz, 0x1},
57 // CHECK-DAG: { Intrinsic::gtarget_def, 0x10},
58 // CHECK-DAG: { Intrinsic::gtarget_defg, 0x11},
59 // CHECK-DAG: { Intrinsic::gtarget_uvw, 0x12},
60 // CHECK-DAG: { Intrinsic::ftarget_ghi, 0x20},
61 // CHECK-DAG: { Intrinsic::ftarget_ghi_x, 0x21},
62 // CHECK-DAG: { Intrinsic::ftarget_rst, 0x22},
55 // CHECK-DAG: { Intrinsic::abc, 0x0 },
56 // CHECK-DAG: { Intrinsic::xyz, 0x1 },
57 // CHECK-DAG: { Intrinsic::gtarget_def, 0x10 },
58 // CHECK-DAG: { Intrinsic::gtarget_defg, 0x11 },
59 // CHECK-DAG: { Intrinsic::gtarget_uvw, 0x12 },
60 // CHECK-DAG: { Intrinsic::ftarget_ghi, 0x20 },
61 // CHECK-DAG: { Intrinsic::ftarget_ghi_x, 0x21 },
62 // CHECK-DAG: { Intrinsic::ftarget_rst, 0x22 },
6363
6464 // Check that the index is in the correct order, consistent with the ordering
6565 // of enums: alphabetically, but target intrinsics after generic intrinsics
6666 //
67 // CHECK-LABEL: TablesByIntr[] = {
67 // CHECK-LABEL: lookupTableByIntr(unsigned Intr) {
68 // CHECK: Index[] = {
6869 // CHECK-NEXT: Intrinsic::abc
6970 // CHECK-NEXT: Intrinsic::xyz
7071 // CHECK-NEXT: Intrinsic::ftarget_ghi
2121 #include "llvm/TableGen/Record.h"
2222 #include "CodeGenIntrinsics.h"
2323 #include
24 #include
2425 #include
2526 #include
27
2628 using namespace llvm;
2729
2830 #define DEBUG_TYPE "searchable-table-emitter"
2931
3032 namespace {
33
34 struct GenericTable;
35
36 int getAsInt(Init *B) {
37 return cast(B->convertInitializerTo(IntRecTy::get()))->getValue();
38 }
39 int getInt(Record *R, StringRef Field) {
40 return getAsInt(R->getValueInit(Field));
41 }
42
43 struct GenericEnum {
44 using Entry = std::pair;
45
46 std::string Name;
47 Record *Class;
48 std::string PreprocessorGuard;
49 std::vector> Entries;
50 DenseMap EntryMap;
51 };
52
53 struct GenericField {
54 std::string Name;
55 RecTy *RecType = nullptr;
56 bool IsIntrinsic = false;
57 bool IsInstruction = false;
58 GenericEnum *Enum = nullptr;
59
60 GenericField(StringRef Name) : Name(Name) {}
61 };
62
63 struct SearchIndex {
64 std::string Name;
65 SmallVector Fields;
66 bool EarlyOut;
67 };
68
69 struct GenericTable {
70 std::string Name;
71 std::string PreprocessorGuard;
72 std::string CppTypeName;
73 SmallVector Fields;
74 std::vector Entries;
75
76 std::unique_ptr PrimaryKey;
77 SmallVector, 2> Indices;
78
79 const GenericField *getFieldByName(StringRef Name) const {
80 for (const auto &Field : Fields) {
81 if (Name == Field.Name)
82 return &Field;
83 }
84 return nullptr;
85 }
86 };
3187
3288 class SearchableTableEmitter {
3389 RecordKeeper &Records;
3490 DenseMap> Intrinsics;
91 std::vector> Enums;
92 DenseMap EnumMap;
93 std::set PreprocessorGuards;
3594
3695 public:
3796 SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
41100 private:
42101 typedef std::pair SearchTableEntry;
43102
44 int getAsInt(BitsInit *B) {
45 return cast(B->convertInitializerTo(IntRecTy::get()))->getValue();
46 }
47 int getInt(Record *R, StringRef Field) {
48 return getAsInt(R->getValueAsBitsInit(Field));
49 }
50
51 std::string primaryRepresentation(Init *I) {
103 enum TypeContext {
104 TypeInStaticStruct,
105 TypeInTempStruct,
106 TypeInArgument,
107 };
108
109 std::string primaryRepresentation(const GenericField &Field, Init *I) {
52110 if (StringInit *SI = dyn_cast(I))
53111 return SI->getAsString();
54112 else if (BitsInit *BI = dyn_cast(I))
57115 return BI->getValue() ? "true" : "false";
58116 else if (CodeInit *CI = dyn_cast(I))
59117 return CI->getValue();
60 else if (DefInit *DI = dyn_cast(I)) {
61 if (DI->getDef()->isSubClassOf("Intrinsic"))
62 return "Intrinsic::" + getIntrinsic(I).EnumName;
63 }
64 PrintFatalError(SMLoc(),
65 "invalid field type, expected: string, bits, bit or code");
66 }
67
68 std::string searchRepresentation(Init *I) {
69 std::string PrimaryRep = primaryRepresentation(I);
70 if (!isa(I))
71 return PrimaryRep;
72 return StringRef(PrimaryRep).upper();
118 else if (Field.IsIntrinsic)
119 return "Intrinsic::" + getIntrinsic(I).EnumName;
120 else if (Field.IsInstruction)
121 return I->getAsString();
122 else if (Field.Enum)
123 return Field.Enum->EntryMap[cast(I)->getDef()]->first;
124 PrintFatalError(Twine("invalid field type for field '") + Field.Name +
125 "', expected: string, bits, bit or code");
73126 }
74127
75128 bool isIntrinsic(Init *I) {
85138 return *Intr;
86139 }
87140
141 bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
142
88143 bool isIntegral(Init *I) {
89144 return isa(I) || isIntrinsic(I);
90145 }
91146
92 std::string searchableFieldType(Init *I) {
93 if (isa(I))
94 return "const char *";
95 else if (BitsInit *BI = dyn_cast(I)) {
147 std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) {
148 if (isa(Field.RecType)) {
149 if (Ctx == TypeInStaticStruct)
150 return "const char *";
151 if (Ctx == TypeInTempStruct)
152 return "std::string";
153 return "StringRef";
154 } else if (BitsRecTy *BI = dyn_cast(Field.RecType)) {
96155 unsigned NumBits = BI->getNumBits();
97156 if (NumBits <= 8)
98157 NumBits = 8;
103162 else if (NumBits <= 64)
104163 NumBits = 64;
105164 else
106 PrintFatalError(SMLoc(), "bitfield too large to search");
165 PrintFatalError(Twine("bitfield '") + Field.Name +
166 "' too large to search");
107167 return "uint" + utostr(NumBits) + "_t";
108 } else if (isIntrinsic(I))
168 } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
109169 return "unsigned";
110 PrintFatalError(SMLoc(), "Unknown type to search by");
111 }
112
113 void emitMapping(Record *MappingDesc, raw_ostream &OS);
114 void emitMappingEnum(std::vector &Items, Record *InstanceClass,
115 raw_ostream &OS);
116 void
117 emitPrimaryTable(StringRef Name, std::vector &FieldNames,
118 std::vector &SearchFieldNames,
119 std::vector> &SearchTables,
120 std::vector &Items, raw_ostream &OS);
121 void emitSearchTable(StringRef Name, StringRef Field,
122 std::vector &SearchTable,
123 raw_ostream &OS);
124 void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I,
125 raw_ostream &OS);
126 void emitLookupFunction(StringRef Name, StringRef Field, Init *I,
127 raw_ostream &OS);
170 PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" +
171 Field.RecType->getAsString() + "' to search by");
172 }
173
174 void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
175 void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
176 void emitLookupDeclaration(const GenericTable &Table,
177 const SearchIndex &Index, raw_ostream &OS);
178 void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
179 bool IsPrimary, raw_ostream &OS);
180 void emitIfdef(StringRef Guard, raw_ostream &OS);
181
182 bool parseFieldType(GenericField &Field, Init *II);
183 std::unique_ptr
184 parseSearchIndex(GenericTable &Table, StringRef Name,
185 const std::vector &Key, bool EarlyOut);
186 void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
187 StringRef ValueField,
188 const std::vector &Items);
189 void collectTableEntries(GenericTable &Table,
190 const std::vector &Items);
128191 };
129192
130193 } // End anonymous namespace.
131194
132 /// Emit an enum providing symbolic access to some preferred field from
133 /// C++.
134 void SearchableTableEmitter::emitMappingEnum(std::vector &Items,
135 Record *InstanceClass,
195 // For search indices that consists of a single field whose numeric value is
196 // known, return that numeric value.
197 static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
198 assert(Index.Fields.size() == 1);
199
200 if (Index.Fields[0].Enum) {
201 Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);
202 return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;
203 }
204
205 return getInt(Rec, Index.Fields[0].Name);
206 }
207
208 /// Less-than style comparison between \p LHS and \p RHS according to the
209 /// key of \p Index.
210 bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
211 const SearchIndex &Index) {
212 for (const auto &Field : Index.Fields) {
213 Init *LHSI = LHS->getValueInit(Field.Name);
214 Init *RHSI = RHS->getValueInit(Field.Name);
215
216 if (isa(Field.RecType) || isa(Field.RecType)) {
217 int64_t LHSi = getAsInt(LHSI);
218 int64_t RHSi = getAsInt(RHSI);
219 if (LHSi < RHSi)
220 return true;
221 if (LHSi > RHSi)
222 return false;
223 } else if (Field.IsIntrinsic) {
224 CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);
225 CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);
226 if (std::tie(LHSi.TargetPrefix, LHSi.Name) <
227 std::tie(RHSi.TargetPrefix, RHSi.Name))
228 return true;
229 if (std::tie(LHSi.TargetPrefix, LHSi.Name) >
230 std::tie(RHSi.TargetPrefix, RHSi.Name))
231 return false;
232 } else if (Field.IsInstruction) {
233 // This does not correctly compare the predefined instructions!
234 Record *LHSr = cast(LHSI)->getDef();
235 Record *RHSr = cast(RHSI)->getDef();
236
237 bool LHSpseudo = LHSr->getValueAsBit("isPseudo");
238 bool RHSpseudo = RHSr->getValueAsBit("isPseudo");
239 if (LHSpseudo && !RHSpseudo)
240 return true;
241 if (!LHSpseudo && RHSpseudo)
242 return false;
243
244 int comp = LHSr->getName().compare(RHSr->getName());
245 if (comp < 0)
246 return true;
247 if (comp > 0)
248 return false;
249 } else if (Field.Enum) {
250 auto LHSr = cast(LHSI)->getDef();
251 auto RHSr = cast(RHSI)->getDef();
252 int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
253 int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
254 if (LHSv < RHSv)
255 return true;
256 if (LHSv > RHSv)
257 return false;
258 } else {
259 std::string LHSs = primaryRepresentation(Field, LHSI);
260 std::string RHSs = primaryRepresentation(Field, RHSI);
261
262 if (isa(Field.RecType)) {
263 LHSs = StringRef(LHSs).upper();
264 RHSs = StringRef(RHSs).upper();
265 }
266
267 int comp = LHSs.compare(RHSs);
268 if (comp < 0)
269 return true;
270 if (comp > 0)
271 return false;
272 }
273 }
274 return false;
275 }
276
277 void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {
278 OS << "#ifdef " << Guard << "\n";
279 PreprocessorGuards.insert(Guard);
280 }
281
282 /// Emit a generic enum.
283 void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
136284 raw_ostream &OS) {
137 StringRef EnumNameField = InstanceClass->getValueAsString("EnumNameField");
138 StringRef EnumValueField;
139 if (!InstanceClass->isValueUnset("EnumValueField"))
140 EnumValueField = InstanceClass->getValueAsString("EnumValueField");
141
142 OS << "enum " << InstanceClass->getName() << "Values {\n";
143 for (auto Item : Items) {
144 OS << " " << Item->getValueAsString(EnumNameField);
145 if (EnumValueField != StringRef())
146 OS << " = " << getInt(Item, EnumValueField);
147 OS << ",\n";
148 }
149 OS << "};\n\n";
150 }
151
152 void SearchableTableEmitter::emitPrimaryTable(
153 StringRef Name, std::vector &FieldNames,
154 std::vector &SearchFieldNames,
155 std::vector> &SearchTables,
156 std::vector &Items, raw_ostream &OS) {
157 OS << "const " << Name << " " << Name << "sList[] = {\n";
158
159 for (auto Item : Items) {
285 emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
286
287 OS << "enum " << Enum.Name << " {\n";
288 for (const auto &Entry : Enum.Entries)
289 OS << " " << Entry->first << " = " << Entry->second << ",\n";
290 OS << "};\n";
291
292 OS << "#endif\n\n";
293 }
294
295 void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
296 const SearchIndex &Index,
297 bool IsPrimary,
298 raw_ostream &OS) {
299 OS << "\n";
300 emitLookupDeclaration(Table, Index, OS);
301 OS << " {\n";
302
303 std::vector IndexRowsStorage;
304 ArrayRef IndexRows;
305 StringRef IndexTypeName;
306 StringRef IndexName;
307
308 if (IsPrimary) {
309 IndexTypeName = Table.CppTypeName;
310 IndexName = Table.Name;
311 IndexRows = Table.Entries;
312 } else {
313 OS << " struct IndexType {\n";
314 for (const auto &Field : Index.Fields) {
315 OS << " " << searchableFieldType(Field, TypeInStaticStruct) << " "
316 << Field.Name << ";\n";
317 }
318 OS << " unsigned _index;\n";
319 OS << " };\n";
320
321 OS << " static const struct IndexType Index[] = {\n";
322
323 std::vector> Entries;
324 Entries.reserve(Table.Entries.size());
325 for (unsigned i = 0; i < Table.Entries.size(); ++i)
326 Entries.emplace_back(Table.Entries[i], i);
327
328 std::stable_sort(Entries.begin(), Entries.end(),
329 [&](const std::pair &LHS,
330 const std::pair &RHS) {
331 return compareBy(LHS.first, RHS.first, Index);
332 });
333
334 IndexRowsStorage.reserve(Entries.size());
335 for (const auto &Entry : Entries) {
336 IndexRowsStorage.push_back(Entry.first);
337
338 OS << " { ";
339 bool NeedComma = false;
340 for (const auto &Field : Index.Fields) {
341 if (NeedComma)
342 OS << ", ";
343 NeedComma = true;
344
345 std::string Repr =
346 primaryRepresentation(Field, Entry.first->getValueInit(Field.Name));
347 if (isa(Field.RecType))
348 Repr = StringRef(Repr).upper();
349 OS << Repr;
350 }
351 OS << ", " << Entry.second << " },\n";
352 }
353
354 OS << " };\n\n";
355
356 IndexTypeName = "IndexType";
357 IndexName = "Index";
358 IndexRows = IndexRowsStorage;
359 }
360
361 bool IsContiguous = false;
362
363 if (Index.Fields.size() == 1 &&
364 (Index.Fields[0].Enum || isa(Index.Fields[0].RecType))) {
365 IsContiguous = true;
366 for (unsigned i = 0; i < IndexRows.size(); ++i) {
367 if (getNumericKey(Index, IndexRows[i]) != i) {
368 IsContiguous = false;
369 break;
370 }
371 }
372 }
373
374 if (IsContiguous) {
375 OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
376 OS << " size_t Idx = " << Index.Fields[0].Name << ";\n";
377 OS << " return Idx >= Table.size() ? nullptr : ";
378 if (IsPrimary)
379 OS << "&Table[Idx]";
380 else
381 OS << "&" << Table.Name << "[Table[Idx]._index]";
382 OS << ";\n";
383 OS << "}\n";
384 return;
385 }
386
387 if (Index.EarlyOut) {
388 const GenericField &Field = Index.Fields[0];
389 std::string FirstRepr =
390 primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name));
391 std::string LastRepr = primaryRepresentation(
392 Field, IndexRows.back()->getValueInit(Field.Name));
393 OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
394 OS << " (" << Field.Name << " > " << LastRepr << "))\n";
395 OS << " return nullptr;\n\n";
396 }
397
398 OS << " struct KeyType {\n";
399 for (const auto &Field : Index.Fields) {
400 OS << " " << searchableFieldType(Field, TypeInTempStruct) << " "
401 << Field.Name << ";\n";
402 }
403 OS << " };\n";
404 OS << " KeyType Key = { ";
405 bool NeedComma = false;
406 for (const auto &Field : Index.Fields) {
407 if (NeedComma)
408 OS << ", ";
409 NeedComma = true;
410
411 OS << Field.Name;
412 if (isa(Field.RecType)) {
413 OS << ".upper()";
414 if (IsPrimary)
415 PrintFatalError(Twine("Use a secondary index for case-insensitive "
416 "comparison of field '") +
417 Field.Name + "' in table '" + Table.Name + "'");
418 }
419 }
420 OS << " };\n";
421
422 OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
423 OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
424 OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
425
426 for (const auto &Field : Index.Fields) {
427 if (isa(Field.RecType)) {
428 OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
429 << ").compare(RHS." << Field.Name << ");\n";
430 OS << " if (Cmp" << Field.Name << " < 0) return true;\n";
431 OS << " if (Cmp" << Field.Name << " > 0) return false;\n";
432 } else {
433 OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
434 OS << " return true;\n";
435 OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
436 OS << " return false;\n";
437 }
438 }
439
440 OS << " return false;\n";
441 OS << " });\n\n";
442
443 OS << " if (Idx == Table.end()";
444
445 for (const auto &Field : Index.Fields)
446 OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
447 OS << ")\n return nullptr;\n";
448
449 if (IsPrimary)
450 OS << " return &*Idx;\n";
451 else
452 OS << " return &" << Table.Name << "[Idx->_index];\n";
453
454 OS << "}\n";
455 }
456
457 void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
458 const SearchIndex &Index,
459 raw_ostream &OS) {
460 OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
461
462 bool NeedComma = false;
463 for (const auto &Field : Index.Fields) {
464 if (NeedComma)
465 OS << ", ";
466 NeedComma = true;
467
468 OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name;
469 }
470 OS << ")";
471 }
472
473 void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
474 raw_ostream &OS) {
475 emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);
476
477 // Emit the declarations for the functions that will perform lookup.
478 if (Table.PrimaryKey) {
479 emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
480 OS << ";\n";
481 }
482 for (const auto &Index : Table.Indices) {
483 emitLookupDeclaration(Table, *Index, OS);
484 OS << ";\n";
485 }
486
487 OS << "#endif\n\n";
488
489 emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
490
491 // The primary data table contains all the fields defined for this map.
492 OS << "const " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
493 for (unsigned i = 0; i < Table.Entries.size(); ++i) {
494 Record *Entry = Table.Entries[i];
160495 OS << " { ";
161 for (unsigned i = 0; i < FieldNames.size(); ++i) {
162 OS << primaryRepresentation(Item->getValueInit(FieldNames[i]));
163 if (i != FieldNames.size() - 1)
496
497 bool NeedComma = false;
498 for (const auto &Field : Table.Fields) {
499 if (NeedComma)
164500 OS << ", ";
165 }
166 OS << "},\n";
167 }
168 OS << "};\n\n";
169 }
170
171 void SearchableTableEmitter::emitSearchTable(
172 StringRef Name, StringRef Field, std::vector &SearchTable,
173 raw_ostream &OS) {
174 OS << "const std::pair<" << searchableFieldType(SearchTable[0].first)
175 << ", int> " << Name << "sBy" << Field << "[] = {\n";
176
177 if (isa(SearchTable[0].first)) {
178 std::stable_sort(SearchTable.begin(), SearchTable.end(),
179 [this](const SearchTableEntry &LHS,
180 const SearchTableEntry &RHS) {
181 return getAsInt(cast(LHS.first)) <
182 getAsInt(cast(RHS.first));
183 });
184 } else if (isIntrinsic(SearchTable[0].first)) {
185 std::stable_sort(SearchTable.begin(), SearchTable.end(),
186 [this](const SearchTableEntry &LHS,
187 const SearchTableEntry &RHS) {
188 CodeGenIntrinsic &LHSi = getIntrinsic(LHS.first);
189 CodeGenIntrinsic &RHSi = getIntrinsic(RHS.first);
190 return std::tie(LHSi.TargetPrefix, LHSi.Name) <
191 std::tie(RHSi.TargetPrefix, RHSi.Name);
192 });
193 } else {
194 std::stable_sort(SearchTable.begin(), SearchTable.end(),
195 [this](const SearchTableEntry &LHS,
196 const SearchTableEntry &RHS) {
197 return searchRepresentation(LHS.first) <
198 searchRepresentation(RHS.first);
199 });
200 }
201
202 for (auto Entry : SearchTable) {
203 OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second
204 << " },\n";
205 }
206 OS << "};\n\n";
207 }
208
209 void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field,
210 Init *I, raw_ostream &OS) {
211 bool IsIntegral = isIntegral(I);
212 std::string FieldType = searchableFieldType(I);
213 std::string PairType = "std::pair<" + FieldType + ", int>";
214
215 // const SysRegs *lookupSysRegByName(const char *Name) {
216 OS << "const " << Name << " *"
217 << "lookup" << Name << "By" << Field;
218 OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
219 << ") {\n";
220
221 if (IsIntegral) {
222 OS << " auto CanonicalVal = " << Field << ";\n";
223 OS << " " << PairType << " Val = {CanonicalVal, 0};\n";
224 } else {
225 // Make sure the result is null terminated because it's going via "char *".
226 OS << " std::string CanonicalVal = " << Field << ".upper();\n";
227 OS << " " << PairType << " Val = {CanonicalVal.c_str(), 0};\n";
228 }
229
230 OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field
231 << ");\n";
232 OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val";
233
234 if (IsIntegral)
235 OS << ");\n";
236 else {
237 OS << ",\n ";
238 OS << "[](const " << PairType << " &LHS, const " << PairType
239 << " &RHS) {\n";
240 OS << " return std::strcmp(LHS.first, RHS.first) < 0;\n";
241 OS << " });\n\n";
242 }
243
244 OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n";
245 OS << " return nullptr;\n";
246
247 OS << " return &" << Name << "sList[Idx->second];\n";
248 OS << "}\n\n";
249 }
250
251 void SearchableTableEmitter::emitLookupDeclaration(StringRef Name,
252 StringRef Field, Init *I,
253 raw_ostream &OS) {
254 bool IsIntegral = isIntegral(I);
255 std::string FieldType = searchableFieldType(I);
256 OS << "const " << Name << " *"
257 << "lookup" << Name << "By" << Field;
258 OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
259 << ");\n\n";
260 }
261
262 void SearchableTableEmitter::emitMapping(Record *InstanceClass,
263 raw_ostream &OS) {
264 StringRef TableName = InstanceClass->getName();
265 std::vector Items = Records.getAllDerivedDefinitions(TableName);
266
267 // Gather all the records we're going to need for this particular mapping.
268 std::vector> SearchTables;
269 std::vector SearchFieldNames;
270
271 std::vector FieldNames;
272 for (const RecordVal &Field : InstanceClass->getValues()) {
273 std::string FieldName = Field.getName();
274
275 // Skip uninteresting fields: either built-in, special to us, or injected
276 // template parameters (if they contain a ':').
277 if (FieldName.find(':') != std::string::npos || FieldName == "NAME" ||
278 FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
279 FieldName == "EnumValueField")
280 continue;
281
282 FieldNames.push_back(FieldName);
283 }
284
285 for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) {
286 SearchTables.emplace_back();
287 SearchFieldNames.push_back(Field->getAsUnquotedString());
288 }
289
290 int Idx = 0;
291 for (Record *Item : Items) {
292 for (unsigned i = 0; i < SearchFieldNames.size(); ++i) {
293 Init *SearchVal = Item->getValueInit(SearchFieldNames[i]);
294 SearchTables[i].emplace_back(SearchVal, Idx);
295 }
296 ++Idx;
297 }
298
299 OS << "#ifdef GET_" << TableName.upper() << "_DECL\n";
300 OS << "#undef GET_" << TableName.upper() << "_DECL\n";
301
302 // Next emit the enum containing the top-level names for use in C++ code if
303 // requested
304 if (!InstanceClass->isValueUnset("EnumNameField")) {
305 emitMappingEnum(Items, InstanceClass, OS);
306 }
307
308 // And the declarations for the functions that will perform lookup.
309 for (unsigned i = 0; i < SearchFieldNames.size(); ++i)
310 emitLookupDeclaration(TableName, SearchFieldNames[i],
311 SearchTables[i][0].first, OS);
312
313 OS << "#endif\n\n";
314
315 OS << "#ifdef GET_" << TableName.upper() << "_IMPL\n";
316 OS << "#undef GET_" << TableName.upper() << "_IMPL\n";
317
318 // The primary data table contains all the fields defined for this map.
319 emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items,
320 OS);
501 NeedComma = true;
502
503 OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name));
504 }
505
506 OS << " }, // " << i << "\n";
507 }
508 OS << " };\n";
321509
322510 // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
323511 // search can be performed by "Thing".
324 for (unsigned i = 0; i < SearchTables.size(); ++i) {
325 emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS);
326 emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first,
327 OS);
328 }
329
330 OS << "#endif\n";
512 if (Table.PrimaryKey)
513 emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
514 for (const auto &Index : Table.Indices)
515 emitLookupFunction(Table, *Index, false, OS);
516
517 OS << "#endif\n\n";
518 }
519
520 bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) {
521 if (auto DI = dyn_cast(II)) {
522 Record *TypeRec = DI->getDef();
523 if (TypeRec->isSubClassOf("GenericEnum")) {
524 Field.Enum = EnumMap[TypeRec];
525 Field.RecType = RecordRecTy::get(Field.Enum->Class);
526 return true;
527 }
528 }
529
530 return false;
531 }
532
533 std::unique_ptr
534 SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name,
535 const std::vector &Key,
536 bool EarlyOut) {
537 auto Index = llvm::make_unique();
538 Index->Name = Name;
539 Index->EarlyOut = EarlyOut;
540
541 for (const auto &FieldName : Key) {
542 const GenericField *Field = Table.getFieldByName(FieldName);
543 if (!Field)
544 PrintFatalError(Twine("Search index '") + Name +
545 "' refers to non-existing field '" + FieldName +
546 "' in table '" + Table.Name + "'");
547 Index->Fields.push_back(*Field);
548 }
549
550 if (EarlyOut && isa(Index->Fields[0].RecType)) {
551 PrintFatalError(
552 "Early-out is not supported for string types (in search index '" +
553 Twine(Name) + "'");
554 }
555
556 return Index;
557 }
558
559 void SearchableTableEmitter::collectEnumEntries(
560 GenericEnum &Enum, StringRef NameField, StringRef ValueField,
561 const std::vector &Items) {
562 for (auto EntryRec : Items) {
563 StringRef Name;
564 if (NameField.empty())
565 Name = EntryRec->getName();
566 else
567 Name = EntryRec->getValueAsString(NameField);
568
569 int64_t Value = 0;
570 if (!ValueField.empty())
571 Value = getInt(EntryRec, ValueField);
572
573 Enum.Entries.push_back(llvm::make_unique(Name, Value));
574 Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
575 }
576
577 if (ValueField.empty()) {
578 std::stable_sort(Enum.Entries.begin(), Enum.Entries.end(),
579 [](const std::unique_ptr &LHS,
580 const std::unique_ptr &RHS) {
581 return LHS->first < RHS->first;
582 });
583
584 for (size_t i = 0; i < Enum.Entries.size(); ++i)
585 Enum.Entries[i]->second = i;
586 }
587 }
588
589 void SearchableTableEmitter::collectTableEntries(
590 GenericTable &Table, const std::vector &Items) {
591 for (auto EntryRec : Items) {
592 for (auto &Field : Table.Fields) {
593 auto TI = dyn_cast(EntryRec->getValueInit(Field.Name));
594 if (!TI) {
595 PrintFatalError(Twine("Record '") + EntryRec->getName() +
596 "' in table '" + Table.Name + "' is missing field '" +
597 Field.Name + "'");
598 }
599 if (!Field.RecType) {
600 Field.RecType = TI->getType();
601 } else {
602 RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
603 if (!Ty)
604 PrintFatalError(Twine("Field '") + Field.Name + "' of table '" +
605 Table.Name + "' has incompatible type: " +
606 Ty->getAsString() + " vs. " +
607 TI->getType()->getAsString());
608 Field.RecType = Ty;
609 }
610 }
611
612 Table.Entries.push_back(EntryRec);
613 }
614
615 Record *IntrinsicClass = Records.getClass("Intrinsic");
616 Record *InstructionClass = Records.getClass("Instruction");
617 for (auto &Field : Table.Fields) {
618 if (auto RecordTy = dyn_cast(Field.RecType)) {
619 if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))
620 Field.IsIntrinsic = true;
621 else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))
622 Field.IsInstruction = true;
623 }
624 }
331625 }
332626
333627 void SearchableTableEmitter::run(raw_ostream &OS) {
334 // Tables are defined to be the direct descendents of "SearchableEntry".
628 // Emit tables in a deterministic order to avoid needless rebuilds.
629 SmallVector, 4> Tables;
630 DenseMap TableMap;
631
632 // Collect all definitions first.
633 for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
634 StringRef NameField;
635 if (!EnumRec->isValueUnset("NameField"))
636 NameField = EnumRec->getValueAsString("NameField");
637
638 StringRef ValueField;
639 if (!EnumRec->isValueUnset("ValueField"))
640 ValueField = EnumRec->getValueAsString("ValueField");
641
642 auto Enum = llvm::make_unique();
643 Enum->Name = EnumRec->getName();
644 Enum->PreprocessorGuard = EnumRec->getName();
645
646 StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
647 Enum->Class = Records.getClass(FilterClass);
648 if (!Enum->Class)
649 PrintFatalError(Twine("Enum FilterClass '") + FilterClass +
650 "' does not exist");
651
652 collectEnumEntries(*Enum, NameField, ValueField,
653 Records.getAllDerivedDefinitions(FilterClass));
654 EnumMap.insert(std::make_pair(EnumRec, Enum.get()));
655 Enums.emplace_back(std::move(Enum));
656 }
657
658 for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
659 auto Table = llvm::make_unique();
660 Table->Name = TableRec->getName();
661 Table->PreprocessorGuard = TableRec->getName();
662 Table->CppTypeName = TableRec->getValueAsString("CppTypeName");
663
664 std::vector Fields = TableRec->getValueAsListOfStrings("Fields");
665 for (const auto &FieldName : Fields) {
666 Table->Fields.emplace_back(FieldName);
667
668 if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
669 if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) {
670 PrintFatalError(Twine("Table '") + Table->Name +
671 "' has bad 'TypeOf_" + FieldName + "': " +
672 TypeOfVal->getValue()->getAsString());
673 }
674 }
675 }
676
677 collectTableEntries(*Table, Records.getAllDerivedDefinitions(
678 TableRec->getValueAsString("FilterClass")));
679
680 if (!TableRec->isValueUnset("PrimaryKey")) {
681 Table->PrimaryKey =
682 parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"),
683 TableRec->getValueAsListOfStrings("PrimaryKey"),
684 TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
685
686 std::stable_sort(Table->Entries.begin(), Table->Entries.end(),
687 [&](Record *LHS, Record *RHS) {
688 return compareBy(LHS, RHS, *Table->PrimaryKey);
689 });
690 }
691
692 TableMap.insert(std::make_pair(TableRec, Table.get()));
693 Tables.emplace_back(std::move(Table));
694 }
695
696 for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {
697 Record *TableRec = IndexRec->getValueAsDef("Table");
698 auto It = TableMap.find(TableRec);
699 if (It == TableMap.end())
700 PrintFatalError(Twine("SearchIndex '") + IndexRec->getName() +
701 "' refers to non-existing table '" + TableRec->getName());
702
703 GenericTable &Table = *It->second;
704 Table.Indices.push_back(parseSearchIndex(
705 Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"),
706 IndexRec->getValueAsBit("EarlyOut")));
707 }
708
709 // Translate legacy tables.
335710 Record *SearchableTable = Records.getClass("SearchableTable");
336711 for (auto &NameRec : Records.getClasses()) {
337712 Record *Class = NameRec.second.get();
338713 if (Class->getSuperClasses().size() != 1 ||
339714 !Class->isSubClassOf(SearchableTable))
340715 continue;
341 emitMapping(Class, OS);
342 }
716
717 StringRef TableName = Class->getName();
718 std::vector Items = Records.getAllDerivedDefinitions(TableName);
719 if (!Class->isValueUnset("EnumNameField")) {
720 StringRef NameField = Class->getValueAsString("EnumNameField");
721 StringRef ValueField;
722 if (!Class->isValueUnset("EnumValueField"))
723 ValueField = Class->getValueAsString("EnumValueField");
724
725 auto Enum = llvm::make_unique();
726 Enum->Name = (Twine(Class->getName()) + "Values").str();
727 Enum->PreprocessorGuard = Class->getName().upper();
728 Enum->Class = Class;
729
730 collectEnumEntries(*Enum, NameField, ValueField, Items);
731
732 Enums.emplace_back(std::move(Enum));
733 }
734
735 auto Table = llvm::make_unique();
736 Table->Name = (Twine(Class->getName()) + "sList").str();
737 Table->PreprocessorGuard = Class->getName().upper();
738 Table->CppTypeName = Class->getName();
739
740 for (const RecordVal &Field : Class->getValues()) {
741 std::string FieldName = Field.getName();
742
743 // Skip uninteresting fields: either special to us, or injected
744 // template parameters (if they contain a ':').
745 if (FieldName.find(':') != std::string::npos ||
746 FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
747 FieldName == "EnumValueField")
748 continue;
749
750 Table->Fields.emplace_back(FieldName);
751 }
752
753 collectTableEntries(*Table, Items);
754
755 for (const auto &Field :
756 Class->getValueAsListOfStrings("SearchableFields")) {
757 std::string Name =
758 (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
759 Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false));
760 }
761
762 Tables.emplace_back(std::move(Table));
763 }
764
765 // Emit everything.
766 for (const auto &Enum : Enums)
767 emitGenericEnum(*Enum, OS);
768
769 for (const auto &Table : Tables)
770 emitGenericTable(*Table, OS);
771
772 // Put all #undefs last, to allow multiple sections guarded by the same
773 // define.
774 for (const auto &Guard : PreprocessorGuards)
775 OS << "#undef " << Guard << "\n";
343776 }
344777
345778 namespace llvm {