blob: 63252e8c0391f57dae96494d55923a0bb6c0cc4f [file] [log] [blame]
Tim Northovere6ae6762016-07-05 21:23:04 +00001//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This tablegen backend emits a generic array initialized by specified fields,
11// together with companion index tables and lookup functions (binary search,
12// currently).
13//
14//===----------------------------------------------------------------------===//
15
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 <algorithm>
Tim Northovere6ae6762016-07-05 21:23:04 +000023#include <string>
24#include <vector>
25using namespace llvm;
26
27#define DEBUG_TYPE "searchable-table-emitter"
28
29namespace {
30
31class SearchableTableEmitter {
32 RecordKeeper &Records;
33
34public:
35 SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
36
37 void run(raw_ostream &OS);
38
39private:
40 typedef std::pair<Init *, int> SearchTableEntry;
41
42 int getAsInt(BitsInit *B) {
43 return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
44 }
45 int getInt(Record *R, StringRef Field) {
46 return getAsInt(R->getValueAsBitsInit(Field));
47 }
48
49 std::string primaryRepresentation(Init *I) {
50 if (StringInit *SI = dyn_cast<StringInit>(I))
51 return SI->getAsString();
52 else if (BitsInit *BI = dyn_cast<BitsInit>(I))
53 return "0x" + utohexstr(getAsInt(BI));
54 else if (BitInit *BI = dyn_cast<BitInit>(I))
55 return BI->getValue() ? "true" : "false";
56 else if (CodeInit *CI = dyn_cast<CodeInit>(I)) {
57 return CI->getValue();
58 }
59 PrintFatalError(SMLoc(),
60 "invalid field type, expected: string, bits, bit or code");
61 }
62
63 std::string searchRepresentation(Init *I) {
64 std::string PrimaryRep = primaryRepresentation(I);
65 if (!isa<StringInit>(I))
66 return PrimaryRep;
67 return StringRef(PrimaryRep).upper();
68 }
69
70 std::string searchableFieldType(Init *I) {
71 if (isa<StringInit>(I))
72 return "const char *";
73 else if (BitsInit *BI = dyn_cast<BitsInit>(I)) {
74 unsigned NumBits = BI->getNumBits();
75 if (NumBits <= 8)
76 NumBits = 8;
77 else if (NumBits <= 16)
78 NumBits = 16;
79 else if (NumBits <= 32)
80 NumBits = 32;
81 else if (NumBits <= 64)
82 NumBits = 64;
83 else
84 PrintFatalError(SMLoc(), "bitfield too large to search");
85 return "uint" + utostr(NumBits) + "_t";
86 }
87 PrintFatalError(SMLoc(), "Unknown type to search by");
88 }
89
90 void emitMapping(Record *MappingDesc, raw_ostream &OS);
91 void emitMappingEnum(std::vector<Record *> &Items, Record *InstanceClass,
92 raw_ostream &OS);
93 void
94 emitPrimaryTable(StringRef Name, std::vector<std::string> &FieldNames,
95 std::vector<std::string> &SearchFieldNames,
96 std::vector<std::vector<SearchTableEntry>> &SearchTables,
97 std::vector<Record *> &Items, raw_ostream &OS);
98 void emitSearchTable(StringRef Name, StringRef Field,
99 std::vector<SearchTableEntry> &SearchTable,
100 raw_ostream &OS);
101 void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I,
102 raw_ostream &OS);
103 void emitLookupFunction(StringRef Name, StringRef Field, Init *I,
104 raw_ostream &OS);
105};
106
107} // End anonymous namespace.
108
109/// Emit an enum providing symbolic access to some preferred field from
110/// C++.
111void SearchableTableEmitter::emitMappingEnum(std::vector<Record *> &Items,
112 Record *InstanceClass,
113 raw_ostream &OS) {
Craig Topperbcd3c372017-05-31 21:12:46 +0000114 StringRef EnumNameField = InstanceClass->getValueAsString("EnumNameField");
115 StringRef EnumValueField;
Tim Northovere6ae6762016-07-05 21:23:04 +0000116 if (!InstanceClass->isValueUnset("EnumValueField"))
117 EnumValueField = InstanceClass->getValueAsString("EnumValueField");
118
119 OS << "enum " << InstanceClass->getName() << "Values {\n";
120 for (auto Item : Items) {
121 OS << " " << Item->getValueAsString(EnumNameField);
122 if (EnumValueField != StringRef())
123 OS << " = " << getInt(Item, EnumValueField);
124 OS << ",\n";
125 }
126 OS << "};\n\n";
127}
128
129void SearchableTableEmitter::emitPrimaryTable(
130 StringRef Name, std::vector<std::string> &FieldNames,
131 std::vector<std::string> &SearchFieldNames,
132 std::vector<std::vector<SearchTableEntry>> &SearchTables,
133 std::vector<Record *> &Items, raw_ostream &OS) {
134 OS << "const " << Name << " " << Name << "sList[] = {\n";
135
136 for (auto Item : Items) {
137 OS << " { ";
138 for (unsigned i = 0; i < FieldNames.size(); ++i) {
139 OS << primaryRepresentation(Item->getValueInit(FieldNames[i]));
140 if (i != FieldNames.size() - 1)
141 OS << ", ";
142 }
143 OS << "},\n";
144 }
145 OS << "};\n\n";
146}
147
148void SearchableTableEmitter::emitSearchTable(
149 StringRef Name, StringRef Field, std::vector<SearchTableEntry> &SearchTable,
150 raw_ostream &OS) {
151 OS << "const std::pair<" << searchableFieldType(SearchTable[0].first)
152 << ", int> " << Name << "sBy" << Field << "[] = {\n";
153
154 if (isa<BitsInit>(SearchTable[0].first)) {
155 std::stable_sort(SearchTable.begin(), SearchTable.end(),
156 [this](const SearchTableEntry &LHS,
157 const SearchTableEntry &RHS) {
158 return getAsInt(cast<BitsInit>(LHS.first)) <
159 getAsInt(cast<BitsInit>(RHS.first));
160 });
161 } else {
162 std::stable_sort(SearchTable.begin(), SearchTable.end(),
163 [this](const SearchTableEntry &LHS,
164 const SearchTableEntry &RHS) {
165 return searchRepresentation(LHS.first) <
166 searchRepresentation(RHS.first);
167 });
168 }
169
170 for (auto Entry : SearchTable) {
171 OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second
172 << " },\n";
173 }
174 OS << "};\n\n";
175}
176
177void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field,
178 Init *I, raw_ostream &OS) {
179 bool IsIntegral = isa<BitsInit>(I);
180 std::string FieldType = searchableFieldType(I);
181 std::string PairType = "std::pair<" + FieldType + ", int>";
182
183 // const SysRegs *lookupSysRegByName(const char *Name) {
184 OS << "const " << Name << " *"
185 << "lookup" << Name << "By" << Field;
186 OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
187 << ") {\n";
188
189 if (IsIntegral) {
190 OS << " auto CanonicalVal = " << Field << ";\n";
191 OS << " " << PairType << " Val = {CanonicalVal, 0};\n";
192 } else {
193 // Make sure the result is null terminated because it's going via "char *".
194 OS << " std::string CanonicalVal = " << Field << ".upper();\n";
Benjamin Kramer729d3612016-07-26 09:27:51 +0000195 OS << " " << PairType << " Val = {CanonicalVal.c_str(), 0};\n";
Tim Northovere6ae6762016-07-05 21:23:04 +0000196 }
197
198 OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field
199 << ");\n";
200 OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val";
201
202 if (IsIntegral)
203 OS << ");\n";
204 else {
205 OS << ",\n ";
206 OS << "[](const " << PairType << " &LHS, const " << PairType
207 << " &RHS) {\n";
Benjamin Kramer729d3612016-07-26 09:27:51 +0000208 OS << " return std::strcmp(LHS.first, RHS.first) < 0;\n";
Tim Northovere6ae6762016-07-05 21:23:04 +0000209 OS << " });\n\n";
210 }
211
212 OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n";
213 OS << " return nullptr;\n";
214
215 OS << " return &" << Name << "sList[Idx->second];\n";
216 OS << "}\n\n";
217}
218
219void SearchableTableEmitter::emitLookupDeclaration(StringRef Name,
220 StringRef Field, Init *I,
221 raw_ostream &OS) {
222 bool IsIntegral = isa<BitsInit>(I);
223 std::string FieldType = searchableFieldType(I);
224 OS << "const " << Name << " *"
225 << "lookup" << Name << "By" << Field;
226 OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
227 << ");\n\n";
228}
229
230void SearchableTableEmitter::emitMapping(Record *InstanceClass,
231 raw_ostream &OS) {
Alexander Shaposhnikovd968f6f2017-07-05 20:14:54 +0000232 StringRef TableName = InstanceClass->getName();
Tim Northovere6ae6762016-07-05 21:23:04 +0000233 std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
234
235 // Gather all the records we're going to need for this particular mapping.
236 std::vector<std::vector<SearchTableEntry>> SearchTables;
237 std::vector<std::string> SearchFieldNames;
238
239 std::vector<std::string> FieldNames;
240 for (const RecordVal &Field : InstanceClass->getValues()) {
241 std::string FieldName = Field.getName();
242
243 // Skip uninteresting fields: either built-in, special to us, or injected
244 // template parameters (if they contain a ':').
245 if (FieldName.find(':') != std::string::npos || FieldName == "NAME" ||
246 FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
247 FieldName == "EnumValueField")
248 continue;
249
250 FieldNames.push_back(FieldName);
251 }
252
253 for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) {
254 SearchTables.emplace_back();
255 SearchFieldNames.push_back(Field->getAsUnquotedString());
256 }
257
258 int Idx = 0;
259 for (Record *Item : Items) {
260 for (unsigned i = 0; i < SearchFieldNames.size(); ++i) {
261 Init *SearchVal = Item->getValueInit(SearchFieldNames[i]);
262 SearchTables[i].emplace_back(SearchVal, Idx);
263 }
264 ++Idx;
265 }
266
Alexander Shaposhnikovd968f6f2017-07-05 20:14:54 +0000267 OS << "#ifdef GET_" << TableName.upper() << "_DECL\n";
268 OS << "#undef GET_" << TableName.upper() << "_DECL\n";
Tim Northovere6ae6762016-07-05 21:23:04 +0000269
270 // Next emit the enum containing the top-level names for use in C++ code if
271 // requested
272 if (!InstanceClass->isValueUnset("EnumNameField")) {
273 emitMappingEnum(Items, InstanceClass, OS);
274 }
275
276 // And the declarations for the functions that will perform lookup.
277 for (unsigned i = 0; i < SearchFieldNames.size(); ++i)
278 emitLookupDeclaration(TableName, SearchFieldNames[i],
279 SearchTables[i][0].first, OS);
280
281 OS << "#endif\n\n";
282
Alexander Shaposhnikovd968f6f2017-07-05 20:14:54 +0000283 OS << "#ifdef GET_" << TableName.upper() << "_IMPL\n";
284 OS << "#undef GET_" << TableName.upper() << "_IMPL\n";
Tim Northovere6ae6762016-07-05 21:23:04 +0000285
286 // The primary data table contains all the fields defined for this map.
287 emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items,
288 OS);
289
290 // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
291 // search can be performed by "Thing".
292 for (unsigned i = 0; i < SearchTables.size(); ++i) {
293 emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS);
294 emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first,
295 OS);
296 }
297
298 OS << "#endif\n";
299}
300
301void SearchableTableEmitter::run(raw_ostream &OS) {
302 // Tables are defined to be the direct descendents of "SearchableEntry".
303 Record *SearchableTable = Records.getClass("SearchableTable");
304 for (auto &NameRec : Records.getClasses()) {
305 Record *Class = NameRec.second.get();
306 if (Class->getSuperClasses().size() != 1 ||
307 !Class->isSubClassOf(SearchableTable))
308 continue;
309 emitMapping(Class, OS);
310 }
311}
312
313namespace llvm {
314
315void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
316 SearchableTableEmitter(RK).run(OS);
317}
318
319} // End llvm namespace.