13ca95b02SDimitry Andric //===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric // The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // This tablegen backend emits a generic array initialized by specified fields,
113ca95b02SDimitry Andric // together with companion index tables and lookup functions (binary search,
123ca95b02SDimitry Andric // currently).
133ca95b02SDimitry Andric //
143ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
153ca95b02SDimitry Andric
164ba319b5SDimitry Andric #include "llvm/ADT/DenseMap.h"
173ca95b02SDimitry Andric #include "llvm/ADT/StringExtras.h"
183ca95b02SDimitry Andric #include "llvm/Support/Format.h"
193ca95b02SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
203ca95b02SDimitry Andric #include "llvm/Support/SourceMgr.h"
213ca95b02SDimitry Andric #include "llvm/TableGen/Error.h"
223ca95b02SDimitry Andric #include "llvm/TableGen/Record.h"
234ba319b5SDimitry Andric #include "CodeGenIntrinsics.h"
243ca95b02SDimitry Andric #include <algorithm>
254ba319b5SDimitry Andric #include <set>
263ca95b02SDimitry Andric #include <string>
273ca95b02SDimitry Andric #include <vector>
284ba319b5SDimitry Andric
293ca95b02SDimitry Andric using namespace llvm;
303ca95b02SDimitry Andric
313ca95b02SDimitry Andric #define DEBUG_TYPE "searchable-table-emitter"
323ca95b02SDimitry Andric
333ca95b02SDimitry Andric namespace {
343ca95b02SDimitry Andric
354ba319b5SDimitry Andric struct GenericTable;
364ba319b5SDimitry Andric
getAsInt(Init * B)374ba319b5SDimitry Andric int getAsInt(Init *B) {
384ba319b5SDimitry Andric return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
394ba319b5SDimitry Andric }
getInt(Record * R,StringRef Field)404ba319b5SDimitry Andric int getInt(Record *R, StringRef Field) {
414ba319b5SDimitry Andric return getAsInt(R->getValueInit(Field));
424ba319b5SDimitry Andric }
434ba319b5SDimitry Andric
444ba319b5SDimitry Andric struct GenericEnum {
454ba319b5SDimitry Andric using Entry = std::pair<StringRef, int64_t>;
464ba319b5SDimitry Andric
474ba319b5SDimitry Andric std::string Name;
484ba319b5SDimitry Andric Record *Class;
494ba319b5SDimitry Andric std::string PreprocessorGuard;
504ba319b5SDimitry Andric std::vector<std::unique_ptr<Entry>> Entries;
514ba319b5SDimitry Andric DenseMap<Record *, Entry *> EntryMap;
524ba319b5SDimitry Andric };
534ba319b5SDimitry Andric
544ba319b5SDimitry Andric struct GenericField {
554ba319b5SDimitry Andric std::string Name;
564ba319b5SDimitry Andric RecTy *RecType = nullptr;
574ba319b5SDimitry Andric bool IsIntrinsic = false;
584ba319b5SDimitry Andric bool IsInstruction = false;
594ba319b5SDimitry Andric GenericEnum *Enum = nullptr;
604ba319b5SDimitry Andric
GenericField__anonbf4f26ac0111::GenericField614ba319b5SDimitry Andric GenericField(StringRef Name) : Name(Name) {}
624ba319b5SDimitry Andric };
634ba319b5SDimitry Andric
644ba319b5SDimitry Andric struct SearchIndex {
654ba319b5SDimitry Andric std::string Name;
664ba319b5SDimitry Andric SmallVector<GenericField, 1> Fields;
674ba319b5SDimitry Andric bool EarlyOut;
684ba319b5SDimitry Andric };
694ba319b5SDimitry Andric
704ba319b5SDimitry Andric struct GenericTable {
714ba319b5SDimitry Andric std::string Name;
724ba319b5SDimitry Andric std::string PreprocessorGuard;
734ba319b5SDimitry Andric std::string CppTypeName;
744ba319b5SDimitry Andric SmallVector<GenericField, 2> Fields;
754ba319b5SDimitry Andric std::vector<Record *> Entries;
764ba319b5SDimitry Andric
774ba319b5SDimitry Andric std::unique_ptr<SearchIndex> PrimaryKey;
784ba319b5SDimitry Andric SmallVector<std::unique_ptr<SearchIndex>, 2> Indices;
794ba319b5SDimitry Andric
getFieldByName__anonbf4f26ac0111::GenericTable804ba319b5SDimitry Andric const GenericField *getFieldByName(StringRef Name) const {
814ba319b5SDimitry Andric for (const auto &Field : Fields) {
824ba319b5SDimitry Andric if (Name == Field.Name)
834ba319b5SDimitry Andric return &Field;
844ba319b5SDimitry Andric }
854ba319b5SDimitry Andric return nullptr;
864ba319b5SDimitry Andric }
874ba319b5SDimitry Andric };
884ba319b5SDimitry Andric
893ca95b02SDimitry Andric class SearchableTableEmitter {
903ca95b02SDimitry Andric RecordKeeper &Records;
914ba319b5SDimitry Andric DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;
924ba319b5SDimitry Andric std::vector<std::unique_ptr<GenericEnum>> Enums;
934ba319b5SDimitry Andric DenseMap<Record *, GenericEnum *> EnumMap;
944ba319b5SDimitry Andric std::set<std::string> PreprocessorGuards;
953ca95b02SDimitry Andric
963ca95b02SDimitry Andric public:
SearchableTableEmitter(RecordKeeper & R)973ca95b02SDimitry Andric SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
983ca95b02SDimitry Andric
993ca95b02SDimitry Andric void run(raw_ostream &OS);
1003ca95b02SDimitry Andric
1013ca95b02SDimitry Andric private:
1023ca95b02SDimitry Andric typedef std::pair<Init *, int> SearchTableEntry;
1033ca95b02SDimitry Andric
1044ba319b5SDimitry Andric enum TypeContext {
1054ba319b5SDimitry Andric TypeInStaticStruct,
1064ba319b5SDimitry Andric TypeInTempStruct,
1074ba319b5SDimitry Andric TypeInArgument,
1084ba319b5SDimitry Andric };
1093ca95b02SDimitry Andric
primaryRepresentation(const GenericField & Field,Init * I)1104ba319b5SDimitry Andric std::string primaryRepresentation(const GenericField &Field, Init *I) {
1113ca95b02SDimitry Andric if (StringInit *SI = dyn_cast<StringInit>(I))
1123ca95b02SDimitry Andric return SI->getAsString();
1133ca95b02SDimitry Andric else if (BitsInit *BI = dyn_cast<BitsInit>(I))
1143ca95b02SDimitry Andric return "0x" + utohexstr(getAsInt(BI));
1153ca95b02SDimitry Andric else if (BitInit *BI = dyn_cast<BitInit>(I))
1163ca95b02SDimitry Andric return BI->getValue() ? "true" : "false";
1174ba319b5SDimitry Andric else if (CodeInit *CI = dyn_cast<CodeInit>(I))
1183ca95b02SDimitry Andric return CI->getValue();
1194ba319b5SDimitry Andric else if (Field.IsIntrinsic)
1204ba319b5SDimitry Andric return "Intrinsic::" + getIntrinsic(I).EnumName;
1214ba319b5SDimitry Andric else if (Field.IsInstruction)
1224ba319b5SDimitry Andric return I->getAsString();
1234ba319b5SDimitry Andric else if (Field.Enum)
1244ba319b5SDimitry Andric return Field.Enum->EntryMap[cast<DefInit>(I)->getDef()]->first;
1254ba319b5SDimitry Andric PrintFatalError(Twine("invalid field type for field '") + Field.Name +
1264ba319b5SDimitry Andric "', expected: string, bits, bit or code");
1273ca95b02SDimitry Andric }
1283ca95b02SDimitry Andric
isIntrinsic(Init * I)1294ba319b5SDimitry Andric bool isIntrinsic(Init *I) {
1304ba319b5SDimitry Andric if (DefInit *DI = dyn_cast<DefInit>(I))
1314ba319b5SDimitry Andric return DI->getDef()->isSubClassOf("Intrinsic");
1324ba319b5SDimitry Andric return false;
1333ca95b02SDimitry Andric }
1343ca95b02SDimitry Andric
getIntrinsic(Init * I)1354ba319b5SDimitry Andric CodeGenIntrinsic &getIntrinsic(Init *I) {
1364ba319b5SDimitry Andric std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
1374ba319b5SDimitry Andric if (!Intr)
1384ba319b5SDimitry Andric Intr = make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef());
1394ba319b5SDimitry Andric return *Intr;
1404ba319b5SDimitry Andric }
1414ba319b5SDimitry Andric
1424ba319b5SDimitry Andric bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
1434ba319b5SDimitry Andric
isIntegral(Init * I)1444ba319b5SDimitry Andric bool isIntegral(Init *I) {
1454ba319b5SDimitry Andric return isa<BitsInit>(I) || isIntrinsic(I);
1464ba319b5SDimitry Andric }
1474ba319b5SDimitry Andric
searchableFieldType(const GenericField & Field,TypeContext Ctx)1484ba319b5SDimitry Andric std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) {
1494ba319b5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) {
1504ba319b5SDimitry Andric if (Ctx == TypeInStaticStruct)
1513ca95b02SDimitry Andric return "const char *";
1524ba319b5SDimitry Andric if (Ctx == TypeInTempStruct)
1534ba319b5SDimitry Andric return "std::string";
1544ba319b5SDimitry Andric return "StringRef";
1554ba319b5SDimitry Andric } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
1563ca95b02SDimitry Andric unsigned NumBits = BI->getNumBits();
1573ca95b02SDimitry Andric if (NumBits <= 8)
158*b5893f02SDimitry Andric return "uint8_t";
159*b5893f02SDimitry Andric if (NumBits <= 16)
160*b5893f02SDimitry Andric return "uint16_t";
161*b5893f02SDimitry Andric if (NumBits <= 32)
162*b5893f02SDimitry Andric return "uint32_t";
163*b5893f02SDimitry Andric if (NumBits <= 64)
164*b5893f02SDimitry Andric return "uint64_t";
1654ba319b5SDimitry Andric PrintFatalError(Twine("bitfield '") + Field.Name +
1664ba319b5SDimitry Andric "' too large to search");
1674ba319b5SDimitry Andric } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
1684ba319b5SDimitry Andric return "unsigned";
1694ba319b5SDimitry Andric PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" +
1704ba319b5SDimitry Andric Field.RecType->getAsString() + "' to search by");
1713ca95b02SDimitry Andric }
1723ca95b02SDimitry Andric
1734ba319b5SDimitry Andric void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
1744ba319b5SDimitry Andric void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
1754ba319b5SDimitry Andric void emitLookupDeclaration(const GenericTable &Table,
1764ba319b5SDimitry Andric const SearchIndex &Index, raw_ostream &OS);
1774ba319b5SDimitry Andric void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
1784ba319b5SDimitry Andric bool IsPrimary, raw_ostream &OS);
1794ba319b5SDimitry Andric void emitIfdef(StringRef Guard, raw_ostream &OS);
1804ba319b5SDimitry Andric
1814ba319b5SDimitry Andric bool parseFieldType(GenericField &Field, Init *II);
1824ba319b5SDimitry Andric std::unique_ptr<SearchIndex>
1834ba319b5SDimitry Andric parseSearchIndex(GenericTable &Table, StringRef Name,
1844ba319b5SDimitry Andric const std::vector<StringRef> &Key, bool EarlyOut);
1854ba319b5SDimitry Andric void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
1864ba319b5SDimitry Andric StringRef ValueField,
1874ba319b5SDimitry Andric const std::vector<Record *> &Items);
1884ba319b5SDimitry Andric void collectTableEntries(GenericTable &Table,
1894ba319b5SDimitry Andric const std::vector<Record *> &Items);
1903ca95b02SDimitry Andric };
1913ca95b02SDimitry Andric
1923ca95b02SDimitry Andric } // End anonymous namespace.
1933ca95b02SDimitry Andric
1944ba319b5SDimitry Andric // For search indices that consists of a single field whose numeric value is
1954ba319b5SDimitry Andric // known, return that numeric value.
getNumericKey(const SearchIndex & Index,Record * Rec)1964ba319b5SDimitry Andric static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
1974ba319b5SDimitry Andric assert(Index.Fields.size() == 1);
1984ba319b5SDimitry Andric
1994ba319b5SDimitry Andric if (Index.Fields[0].Enum) {
2004ba319b5SDimitry Andric Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);
2014ba319b5SDimitry Andric return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;
2024ba319b5SDimitry Andric }
2034ba319b5SDimitry Andric
2044ba319b5SDimitry Andric return getInt(Rec, Index.Fields[0].Name);
2054ba319b5SDimitry Andric }
2064ba319b5SDimitry Andric
2074ba319b5SDimitry Andric /// Less-than style comparison between \p LHS and \p RHS according to the
2084ba319b5SDimitry Andric /// key of \p Index.
compareBy(Record * LHS,Record * RHS,const SearchIndex & Index)2094ba319b5SDimitry Andric bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
2104ba319b5SDimitry Andric const SearchIndex &Index) {
2114ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
2124ba319b5SDimitry Andric Init *LHSI = LHS->getValueInit(Field.Name);
2134ba319b5SDimitry Andric Init *RHSI = RHS->getValueInit(Field.Name);
2144ba319b5SDimitry Andric
2154ba319b5SDimitry Andric if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) {
2164ba319b5SDimitry Andric int64_t LHSi = getAsInt(LHSI);
2174ba319b5SDimitry Andric int64_t RHSi = getAsInt(RHSI);
2184ba319b5SDimitry Andric if (LHSi < RHSi)
2194ba319b5SDimitry Andric return true;
2204ba319b5SDimitry Andric if (LHSi > RHSi)
2214ba319b5SDimitry Andric return false;
2224ba319b5SDimitry Andric } else if (Field.IsIntrinsic) {
2234ba319b5SDimitry Andric CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);
2244ba319b5SDimitry Andric CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);
2254ba319b5SDimitry Andric if (std::tie(LHSi.TargetPrefix, LHSi.Name) <
2264ba319b5SDimitry Andric std::tie(RHSi.TargetPrefix, RHSi.Name))
2274ba319b5SDimitry Andric return true;
2284ba319b5SDimitry Andric if (std::tie(LHSi.TargetPrefix, LHSi.Name) >
2294ba319b5SDimitry Andric std::tie(RHSi.TargetPrefix, RHSi.Name))
2304ba319b5SDimitry Andric return false;
2314ba319b5SDimitry Andric } else if (Field.IsInstruction) {
2324ba319b5SDimitry Andric // This does not correctly compare the predefined instructions!
2334ba319b5SDimitry Andric Record *LHSr = cast<DefInit>(LHSI)->getDef();
2344ba319b5SDimitry Andric Record *RHSr = cast<DefInit>(RHSI)->getDef();
2354ba319b5SDimitry Andric
2364ba319b5SDimitry Andric bool LHSpseudo = LHSr->getValueAsBit("isPseudo");
2374ba319b5SDimitry Andric bool RHSpseudo = RHSr->getValueAsBit("isPseudo");
2384ba319b5SDimitry Andric if (LHSpseudo && !RHSpseudo)
2394ba319b5SDimitry Andric return true;
2404ba319b5SDimitry Andric if (!LHSpseudo && RHSpseudo)
2414ba319b5SDimitry Andric return false;
2424ba319b5SDimitry Andric
2434ba319b5SDimitry Andric int comp = LHSr->getName().compare(RHSr->getName());
2444ba319b5SDimitry Andric if (comp < 0)
2454ba319b5SDimitry Andric return true;
2464ba319b5SDimitry Andric if (comp > 0)
2474ba319b5SDimitry Andric return false;
2484ba319b5SDimitry Andric } else if (Field.Enum) {
2494ba319b5SDimitry Andric auto LHSr = cast<DefInit>(LHSI)->getDef();
2504ba319b5SDimitry Andric auto RHSr = cast<DefInit>(RHSI)->getDef();
2514ba319b5SDimitry Andric int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
2524ba319b5SDimitry Andric int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
2534ba319b5SDimitry Andric if (LHSv < RHSv)
2544ba319b5SDimitry Andric return true;
2554ba319b5SDimitry Andric if (LHSv > RHSv)
2564ba319b5SDimitry Andric return false;
2574ba319b5SDimitry Andric } else {
2584ba319b5SDimitry Andric std::string LHSs = primaryRepresentation(Field, LHSI);
2594ba319b5SDimitry Andric std::string RHSs = primaryRepresentation(Field, RHSI);
2604ba319b5SDimitry Andric
2614ba319b5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) {
2624ba319b5SDimitry Andric LHSs = StringRef(LHSs).upper();
2634ba319b5SDimitry Andric RHSs = StringRef(RHSs).upper();
2644ba319b5SDimitry Andric }
2654ba319b5SDimitry Andric
2664ba319b5SDimitry Andric int comp = LHSs.compare(RHSs);
2674ba319b5SDimitry Andric if (comp < 0)
2684ba319b5SDimitry Andric return true;
2694ba319b5SDimitry Andric if (comp > 0)
2704ba319b5SDimitry Andric return false;
2714ba319b5SDimitry Andric }
2724ba319b5SDimitry Andric }
2734ba319b5SDimitry Andric return false;
2744ba319b5SDimitry Andric }
2754ba319b5SDimitry Andric
emitIfdef(StringRef Guard,raw_ostream & OS)2764ba319b5SDimitry Andric void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {
2774ba319b5SDimitry Andric OS << "#ifdef " << Guard << "\n";
2784ba319b5SDimitry Andric PreprocessorGuards.insert(Guard);
2794ba319b5SDimitry Andric }
2804ba319b5SDimitry Andric
2814ba319b5SDimitry Andric /// Emit a generic enum.
emitGenericEnum(const GenericEnum & Enum,raw_ostream & OS)2824ba319b5SDimitry Andric void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
2833ca95b02SDimitry Andric raw_ostream &OS) {
2844ba319b5SDimitry Andric emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
2853ca95b02SDimitry Andric
2864ba319b5SDimitry Andric OS << "enum " << Enum.Name << " {\n";
2874ba319b5SDimitry Andric for (const auto &Entry : Enum.Entries)
2884ba319b5SDimitry Andric OS << " " << Entry->first << " = " << Entry->second << ",\n";
2894ba319b5SDimitry Andric OS << "};\n";
2904ba319b5SDimitry Andric
2914ba319b5SDimitry Andric OS << "#endif\n\n";
2923ca95b02SDimitry Andric }
2933ca95b02SDimitry Andric
emitLookupFunction(const GenericTable & Table,const SearchIndex & Index,bool IsPrimary,raw_ostream & OS)2944ba319b5SDimitry Andric void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
2954ba319b5SDimitry Andric const SearchIndex &Index,
2964ba319b5SDimitry Andric bool IsPrimary,
2974ba319b5SDimitry Andric raw_ostream &OS) {
2984ba319b5SDimitry Andric OS << "\n";
2994ba319b5SDimitry Andric emitLookupDeclaration(Table, Index, OS);
3004ba319b5SDimitry Andric OS << " {\n";
3013ca95b02SDimitry Andric
3024ba319b5SDimitry Andric std::vector<Record *> IndexRowsStorage;
3034ba319b5SDimitry Andric ArrayRef<Record *> IndexRows;
3044ba319b5SDimitry Andric StringRef IndexTypeName;
3054ba319b5SDimitry Andric StringRef IndexName;
3064ba319b5SDimitry Andric
3074ba319b5SDimitry Andric if (IsPrimary) {
3084ba319b5SDimitry Andric IndexTypeName = Table.CppTypeName;
3094ba319b5SDimitry Andric IndexName = Table.Name;
3104ba319b5SDimitry Andric IndexRows = Table.Entries;
3114ba319b5SDimitry Andric } else {
3124ba319b5SDimitry Andric OS << " struct IndexType {\n";
3134ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
3144ba319b5SDimitry Andric OS << " " << searchableFieldType(Field, TypeInStaticStruct) << " "
3154ba319b5SDimitry Andric << Field.Name << ";\n";
3164ba319b5SDimitry Andric }
3174ba319b5SDimitry Andric OS << " unsigned _index;\n";
3184ba319b5SDimitry Andric OS << " };\n";
3194ba319b5SDimitry Andric
3204ba319b5SDimitry Andric OS << " static const struct IndexType Index[] = {\n";
3214ba319b5SDimitry Andric
3224ba319b5SDimitry Andric std::vector<std::pair<Record *, unsigned>> Entries;
3234ba319b5SDimitry Andric Entries.reserve(Table.Entries.size());
3244ba319b5SDimitry Andric for (unsigned i = 0; i < Table.Entries.size(); ++i)
3254ba319b5SDimitry Andric Entries.emplace_back(Table.Entries[i], i);
3264ba319b5SDimitry Andric
3274ba319b5SDimitry Andric std::stable_sort(Entries.begin(), Entries.end(),
3284ba319b5SDimitry Andric [&](const std::pair<Record *, unsigned> &LHS,
3294ba319b5SDimitry Andric const std::pair<Record *, unsigned> &RHS) {
3304ba319b5SDimitry Andric return compareBy(LHS.first, RHS.first, Index);
3314ba319b5SDimitry Andric });
3324ba319b5SDimitry Andric
3334ba319b5SDimitry Andric IndexRowsStorage.reserve(Entries.size());
3344ba319b5SDimitry Andric for (const auto &Entry : Entries) {
3354ba319b5SDimitry Andric IndexRowsStorage.push_back(Entry.first);
3364ba319b5SDimitry Andric
3373ca95b02SDimitry Andric OS << " { ";
3384ba319b5SDimitry Andric bool NeedComma = false;
3394ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
3404ba319b5SDimitry Andric if (NeedComma)
3413ca95b02SDimitry Andric OS << ", ";
3424ba319b5SDimitry Andric NeedComma = true;
3434ba319b5SDimitry Andric
3444ba319b5SDimitry Andric std::string Repr =
3454ba319b5SDimitry Andric primaryRepresentation(Field, Entry.first->getValueInit(Field.Name));
3464ba319b5SDimitry Andric if (isa<StringRecTy>(Field.RecType))
3474ba319b5SDimitry Andric Repr = StringRef(Repr).upper();
3484ba319b5SDimitry Andric OS << Repr;
3493ca95b02SDimitry Andric }
3504ba319b5SDimitry Andric OS << ", " << Entry.second << " },\n";
3513ca95b02SDimitry Andric }
3524ba319b5SDimitry Andric
3533ca95b02SDimitry Andric OS << " };\n\n";
3544ba319b5SDimitry Andric
3554ba319b5SDimitry Andric IndexTypeName = "IndexType";
3564ba319b5SDimitry Andric IndexName = "Index";
3574ba319b5SDimitry Andric IndexRows = IndexRowsStorage;
3583ca95b02SDimitry Andric }
3593ca95b02SDimitry Andric
3604ba319b5SDimitry Andric bool IsContiguous = false;
3613ca95b02SDimitry Andric
3624ba319b5SDimitry Andric if (Index.Fields.size() == 1 &&
3634ba319b5SDimitry Andric (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) {
3644ba319b5SDimitry Andric IsContiguous = true;
3654ba319b5SDimitry Andric for (unsigned i = 0; i < IndexRows.size(); ++i) {
3664ba319b5SDimitry Andric if (getNumericKey(Index, IndexRows[i]) != i) {
3674ba319b5SDimitry Andric IsContiguous = false;
3684ba319b5SDimitry Andric break;
3694ba319b5SDimitry Andric }
3704ba319b5SDimitry Andric }
3714ba319b5SDimitry Andric }
3724ba319b5SDimitry Andric
3734ba319b5SDimitry Andric if (IsContiguous) {
3744ba319b5SDimitry Andric OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
3754ba319b5SDimitry Andric OS << " size_t Idx = " << Index.Fields[0].Name << ";\n";
3764ba319b5SDimitry Andric OS << " return Idx >= Table.size() ? nullptr : ";
3774ba319b5SDimitry Andric if (IsPrimary)
3784ba319b5SDimitry Andric OS << "&Table[Idx]";
3794ba319b5SDimitry Andric else
3804ba319b5SDimitry Andric OS << "&" << Table.Name << "[Table[Idx]._index]";
3814ba319b5SDimitry Andric OS << ";\n";
3824ba319b5SDimitry Andric OS << "}\n";
3834ba319b5SDimitry Andric return;
3844ba319b5SDimitry Andric }
3854ba319b5SDimitry Andric
3864ba319b5SDimitry Andric if (Index.EarlyOut) {
3874ba319b5SDimitry Andric const GenericField &Field = Index.Fields[0];
3884ba319b5SDimitry Andric std::string FirstRepr =
3894ba319b5SDimitry Andric primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name));
3904ba319b5SDimitry Andric std::string LastRepr = primaryRepresentation(
3914ba319b5SDimitry Andric Field, IndexRows.back()->getValueInit(Field.Name));
3924ba319b5SDimitry Andric OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
3934ba319b5SDimitry Andric OS << " (" << Field.Name << " > " << LastRepr << "))\n";
3944ba319b5SDimitry Andric OS << " return nullptr;\n\n";
3954ba319b5SDimitry Andric }
3964ba319b5SDimitry Andric
3974ba319b5SDimitry Andric OS << " struct KeyType {\n";
3984ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
3994ba319b5SDimitry Andric OS << " " << searchableFieldType(Field, TypeInTempStruct) << " "
4004ba319b5SDimitry Andric << Field.Name << ";\n";
4014ba319b5SDimitry Andric }
4024ba319b5SDimitry Andric OS << " };\n";
4034ba319b5SDimitry Andric OS << " KeyType Key = { ";
4044ba319b5SDimitry Andric bool NeedComma = false;
4054ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
4064ba319b5SDimitry Andric if (NeedComma)
4074ba319b5SDimitry Andric OS << ", ";
4084ba319b5SDimitry Andric NeedComma = true;
4094ba319b5SDimitry Andric
4104ba319b5SDimitry Andric OS << Field.Name;
4114ba319b5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) {
4124ba319b5SDimitry Andric OS << ".upper()";
4134ba319b5SDimitry Andric if (IsPrimary)
4144ba319b5SDimitry Andric PrintFatalError(Twine("Use a secondary index for case-insensitive "
4154ba319b5SDimitry Andric "comparison of field '") +
4164ba319b5SDimitry Andric Field.Name + "' in table '" + Table.Name + "'");
4174ba319b5SDimitry Andric }
4184ba319b5SDimitry Andric }
4194ba319b5SDimitry Andric OS << " };\n";
4204ba319b5SDimitry Andric
4214ba319b5SDimitry Andric OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
4224ba319b5SDimitry Andric OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
4234ba319b5SDimitry Andric OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
4244ba319b5SDimitry Andric
4254ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
4264ba319b5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) {
4274ba319b5SDimitry Andric OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
4284ba319b5SDimitry Andric << ").compare(RHS." << Field.Name << ");\n";
4294ba319b5SDimitry Andric OS << " if (Cmp" << Field.Name << " < 0) return true;\n";
4304ba319b5SDimitry Andric OS << " if (Cmp" << Field.Name << " > 0) return false;\n";
431*b5893f02SDimitry Andric } else if (Field.Enum) {
432*b5893f02SDimitry Andric // Explicitly cast to unsigned, because the signedness of enums is
433*b5893f02SDimitry Andric // compiler-dependent.
434*b5893f02SDimitry Andric OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
435*b5893f02SDimitry Andric << Field.Name << ")\n";
436*b5893f02SDimitry Andric OS << " return true;\n";
437*b5893f02SDimitry Andric OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
438*b5893f02SDimitry Andric << Field.Name << ")\n";
439*b5893f02SDimitry Andric OS << " return false;\n";
4403ca95b02SDimitry Andric } else {
4414ba319b5SDimitry Andric OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
4424ba319b5SDimitry Andric OS << " return true;\n";
4434ba319b5SDimitry Andric OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
4444ba319b5SDimitry Andric OS << " return false;\n";
4454ba319b5SDimitry Andric }
4463ca95b02SDimitry Andric }
4473ca95b02SDimitry Andric
4484ba319b5SDimitry Andric OS << " return false;\n";
4493ca95b02SDimitry Andric OS << " });\n\n";
4504ba319b5SDimitry Andric
4514ba319b5SDimitry Andric OS << " if (Idx == Table.end()";
4524ba319b5SDimitry Andric
4534ba319b5SDimitry Andric for (const auto &Field : Index.Fields)
4544ba319b5SDimitry Andric OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
4554ba319b5SDimitry Andric OS << ")\n return nullptr;\n";
4564ba319b5SDimitry Andric
4574ba319b5SDimitry Andric if (IsPrimary)
4584ba319b5SDimitry Andric OS << " return &*Idx;\n";
4594ba319b5SDimitry Andric else
4604ba319b5SDimitry Andric OS << " return &" << Table.Name << "[Idx->_index];\n";
4614ba319b5SDimitry Andric
4624ba319b5SDimitry Andric OS << "}\n";
4633ca95b02SDimitry Andric }
4643ca95b02SDimitry Andric
emitLookupDeclaration(const GenericTable & Table,const SearchIndex & Index,raw_ostream & OS)4654ba319b5SDimitry Andric void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
4664ba319b5SDimitry Andric const SearchIndex &Index,
4673ca95b02SDimitry Andric raw_ostream &OS) {
4684ba319b5SDimitry Andric OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
4694ba319b5SDimitry Andric
4704ba319b5SDimitry Andric bool NeedComma = false;
4714ba319b5SDimitry Andric for (const auto &Field : Index.Fields) {
4724ba319b5SDimitry Andric if (NeedComma)
4734ba319b5SDimitry Andric OS << ", ";
4744ba319b5SDimitry Andric NeedComma = true;
4754ba319b5SDimitry Andric
4764ba319b5SDimitry Andric OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name;
4774ba319b5SDimitry Andric }
4784ba319b5SDimitry Andric OS << ")";
4793ca95b02SDimitry Andric }
4803ca95b02SDimitry Andric
emitGenericTable(const GenericTable & Table,raw_ostream & OS)4814ba319b5SDimitry Andric void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
4823ca95b02SDimitry Andric raw_ostream &OS) {
4834ba319b5SDimitry Andric emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);
4843ca95b02SDimitry Andric
4854ba319b5SDimitry Andric // Emit the declarations for the functions that will perform lookup.
4864ba319b5SDimitry Andric if (Table.PrimaryKey) {
4874ba319b5SDimitry Andric emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
4884ba319b5SDimitry Andric OS << ";\n";
4893ca95b02SDimitry Andric }
4904ba319b5SDimitry Andric for (const auto &Index : Table.Indices) {
4914ba319b5SDimitry Andric emitLookupDeclaration(Table, *Index, OS);
4924ba319b5SDimitry Andric OS << ";\n";
4933ca95b02SDimitry Andric }
4943ca95b02SDimitry Andric
4953ca95b02SDimitry Andric OS << "#endif\n\n";
4963ca95b02SDimitry Andric
4974ba319b5SDimitry Andric emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
4983ca95b02SDimitry Andric
4993ca95b02SDimitry Andric // The primary data table contains all the fields defined for this map.
5004ba319b5SDimitry Andric OS << "const " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
5014ba319b5SDimitry Andric for (unsigned i = 0; i < Table.Entries.size(); ++i) {
5024ba319b5SDimitry Andric Record *Entry = Table.Entries[i];
5034ba319b5SDimitry Andric OS << " { ";
5044ba319b5SDimitry Andric
5054ba319b5SDimitry Andric bool NeedComma = false;
5064ba319b5SDimitry Andric for (const auto &Field : Table.Fields) {
5074ba319b5SDimitry Andric if (NeedComma)
5084ba319b5SDimitry Andric OS << ", ";
5094ba319b5SDimitry Andric NeedComma = true;
5104ba319b5SDimitry Andric
5114ba319b5SDimitry Andric OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name));
5124ba319b5SDimitry Andric }
5134ba319b5SDimitry Andric
5144ba319b5SDimitry Andric OS << " }, // " << i << "\n";
5154ba319b5SDimitry Andric }
5164ba319b5SDimitry Andric OS << " };\n";
5173ca95b02SDimitry Andric
5183ca95b02SDimitry Andric // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
5193ca95b02SDimitry Andric // search can be performed by "Thing".
5204ba319b5SDimitry Andric if (Table.PrimaryKey)
5214ba319b5SDimitry Andric emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
5224ba319b5SDimitry Andric for (const auto &Index : Table.Indices)
5234ba319b5SDimitry Andric emitLookupFunction(Table, *Index, false, OS);
5244ba319b5SDimitry Andric
5254ba319b5SDimitry Andric OS << "#endif\n\n";
5263ca95b02SDimitry Andric }
5273ca95b02SDimitry Andric
parseFieldType(GenericField & Field,Init * II)5284ba319b5SDimitry Andric bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) {
5294ba319b5SDimitry Andric if (auto DI = dyn_cast<DefInit>(II)) {
5304ba319b5SDimitry Andric Record *TypeRec = DI->getDef();
5314ba319b5SDimitry Andric if (TypeRec->isSubClassOf("GenericEnum")) {
5324ba319b5SDimitry Andric Field.Enum = EnumMap[TypeRec];
5334ba319b5SDimitry Andric Field.RecType = RecordRecTy::get(Field.Enum->Class);
5344ba319b5SDimitry Andric return true;
5354ba319b5SDimitry Andric }
5364ba319b5SDimitry Andric }
5374ba319b5SDimitry Andric
5384ba319b5SDimitry Andric return false;
5394ba319b5SDimitry Andric }
5404ba319b5SDimitry Andric
5414ba319b5SDimitry Andric std::unique_ptr<SearchIndex>
parseSearchIndex(GenericTable & Table,StringRef Name,const std::vector<StringRef> & Key,bool EarlyOut)5424ba319b5SDimitry Andric SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name,
5434ba319b5SDimitry Andric const std::vector<StringRef> &Key,
5444ba319b5SDimitry Andric bool EarlyOut) {
5454ba319b5SDimitry Andric auto Index = llvm::make_unique<SearchIndex>();
5464ba319b5SDimitry Andric Index->Name = Name;
5474ba319b5SDimitry Andric Index->EarlyOut = EarlyOut;
5484ba319b5SDimitry Andric
5494ba319b5SDimitry Andric for (const auto &FieldName : Key) {
5504ba319b5SDimitry Andric const GenericField *Field = Table.getFieldByName(FieldName);
5514ba319b5SDimitry Andric if (!Field)
5524ba319b5SDimitry Andric PrintFatalError(Twine("Search index '") + Name +
5534ba319b5SDimitry Andric "' refers to non-existing field '" + FieldName +
5544ba319b5SDimitry Andric "' in table '" + Table.Name + "'");
5554ba319b5SDimitry Andric Index->Fields.push_back(*Field);
5564ba319b5SDimitry Andric }
5574ba319b5SDimitry Andric
5584ba319b5SDimitry Andric if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
5594ba319b5SDimitry Andric PrintFatalError(
5604ba319b5SDimitry Andric "Early-out is not supported for string types (in search index '" +
5614ba319b5SDimitry Andric Twine(Name) + "'");
5624ba319b5SDimitry Andric }
5634ba319b5SDimitry Andric
5644ba319b5SDimitry Andric return Index;
5654ba319b5SDimitry Andric }
5664ba319b5SDimitry Andric
collectEnumEntries(GenericEnum & Enum,StringRef NameField,StringRef ValueField,const std::vector<Record * > & Items)5674ba319b5SDimitry Andric void SearchableTableEmitter::collectEnumEntries(
5684ba319b5SDimitry Andric GenericEnum &Enum, StringRef NameField, StringRef ValueField,
5694ba319b5SDimitry Andric const std::vector<Record *> &Items) {
5704ba319b5SDimitry Andric for (auto EntryRec : Items) {
5714ba319b5SDimitry Andric StringRef Name;
5724ba319b5SDimitry Andric if (NameField.empty())
5734ba319b5SDimitry Andric Name = EntryRec->getName();
5744ba319b5SDimitry Andric else
5754ba319b5SDimitry Andric Name = EntryRec->getValueAsString(NameField);
5764ba319b5SDimitry Andric
5774ba319b5SDimitry Andric int64_t Value = 0;
5784ba319b5SDimitry Andric if (!ValueField.empty())
5794ba319b5SDimitry Andric Value = getInt(EntryRec, ValueField);
5804ba319b5SDimitry Andric
5814ba319b5SDimitry Andric Enum.Entries.push_back(llvm::make_unique<GenericEnum::Entry>(Name, Value));
5824ba319b5SDimitry Andric Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
5834ba319b5SDimitry Andric }
5844ba319b5SDimitry Andric
5854ba319b5SDimitry Andric if (ValueField.empty()) {
5864ba319b5SDimitry Andric std::stable_sort(Enum.Entries.begin(), Enum.Entries.end(),
5874ba319b5SDimitry Andric [](const std::unique_ptr<GenericEnum::Entry> &LHS,
5884ba319b5SDimitry Andric const std::unique_ptr<GenericEnum::Entry> &RHS) {
5894ba319b5SDimitry Andric return LHS->first < RHS->first;
5904ba319b5SDimitry Andric });
5914ba319b5SDimitry Andric
5924ba319b5SDimitry Andric for (size_t i = 0; i < Enum.Entries.size(); ++i)
5934ba319b5SDimitry Andric Enum.Entries[i]->second = i;
5944ba319b5SDimitry Andric }
5954ba319b5SDimitry Andric }
5964ba319b5SDimitry Andric
collectTableEntries(GenericTable & Table,const std::vector<Record * > & Items)5974ba319b5SDimitry Andric void SearchableTableEmitter::collectTableEntries(
5984ba319b5SDimitry Andric GenericTable &Table, const std::vector<Record *> &Items) {
5994ba319b5SDimitry Andric for (auto EntryRec : Items) {
6004ba319b5SDimitry Andric for (auto &Field : Table.Fields) {
6014ba319b5SDimitry Andric auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
6024ba319b5SDimitry Andric if (!TI) {
6034ba319b5SDimitry Andric PrintFatalError(Twine("Record '") + EntryRec->getName() +
6044ba319b5SDimitry Andric "' in table '" + Table.Name + "' is missing field '" +
6054ba319b5SDimitry Andric Field.Name + "'");
6064ba319b5SDimitry Andric }
6074ba319b5SDimitry Andric if (!Field.RecType) {
6084ba319b5SDimitry Andric Field.RecType = TI->getType();
6094ba319b5SDimitry Andric } else {
6104ba319b5SDimitry Andric RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
6114ba319b5SDimitry Andric if (!Ty)
6124ba319b5SDimitry Andric PrintFatalError(Twine("Field '") + Field.Name + "' of table '" +
6134ba319b5SDimitry Andric Table.Name + "' has incompatible type: " +
6144ba319b5SDimitry Andric Ty->getAsString() + " vs. " +
6154ba319b5SDimitry Andric TI->getType()->getAsString());
6164ba319b5SDimitry Andric Field.RecType = Ty;
6174ba319b5SDimitry Andric }
6184ba319b5SDimitry Andric }
6194ba319b5SDimitry Andric
6204ba319b5SDimitry Andric Table.Entries.push_back(EntryRec);
6214ba319b5SDimitry Andric }
6224ba319b5SDimitry Andric
6234ba319b5SDimitry Andric Record *IntrinsicClass = Records.getClass("Intrinsic");
6244ba319b5SDimitry Andric Record *InstructionClass = Records.getClass("Instruction");
6254ba319b5SDimitry Andric for (auto &Field : Table.Fields) {
6264ba319b5SDimitry Andric if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) {
6274ba319b5SDimitry Andric if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))
6284ba319b5SDimitry Andric Field.IsIntrinsic = true;
6294ba319b5SDimitry Andric else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))
6304ba319b5SDimitry Andric Field.IsInstruction = true;
6314ba319b5SDimitry Andric }
6324ba319b5SDimitry Andric }
6333ca95b02SDimitry Andric }
6343ca95b02SDimitry Andric
run(raw_ostream & OS)6353ca95b02SDimitry Andric void SearchableTableEmitter::run(raw_ostream &OS) {
6364ba319b5SDimitry Andric // Emit tables in a deterministic order to avoid needless rebuilds.
6374ba319b5SDimitry Andric SmallVector<std::unique_ptr<GenericTable>, 4> Tables;
6384ba319b5SDimitry Andric DenseMap<Record *, GenericTable *> TableMap;
6394ba319b5SDimitry Andric
6404ba319b5SDimitry Andric // Collect all definitions first.
6414ba319b5SDimitry Andric for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
6424ba319b5SDimitry Andric StringRef NameField;
6434ba319b5SDimitry Andric if (!EnumRec->isValueUnset("NameField"))
6444ba319b5SDimitry Andric NameField = EnumRec->getValueAsString("NameField");
6454ba319b5SDimitry Andric
6464ba319b5SDimitry Andric StringRef ValueField;
6474ba319b5SDimitry Andric if (!EnumRec->isValueUnset("ValueField"))
6484ba319b5SDimitry Andric ValueField = EnumRec->getValueAsString("ValueField");
6494ba319b5SDimitry Andric
6504ba319b5SDimitry Andric auto Enum = llvm::make_unique<GenericEnum>();
6514ba319b5SDimitry Andric Enum->Name = EnumRec->getName();
6524ba319b5SDimitry Andric Enum->PreprocessorGuard = EnumRec->getName();
6534ba319b5SDimitry Andric
6544ba319b5SDimitry Andric StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
6554ba319b5SDimitry Andric Enum->Class = Records.getClass(FilterClass);
6564ba319b5SDimitry Andric if (!Enum->Class)
6574ba319b5SDimitry Andric PrintFatalError(Twine("Enum FilterClass '") + FilterClass +
6584ba319b5SDimitry Andric "' does not exist");
6594ba319b5SDimitry Andric
6604ba319b5SDimitry Andric collectEnumEntries(*Enum, NameField, ValueField,
6614ba319b5SDimitry Andric Records.getAllDerivedDefinitions(FilterClass));
6624ba319b5SDimitry Andric EnumMap.insert(std::make_pair(EnumRec, Enum.get()));
6634ba319b5SDimitry Andric Enums.emplace_back(std::move(Enum));
6644ba319b5SDimitry Andric }
6654ba319b5SDimitry Andric
6664ba319b5SDimitry Andric for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
6674ba319b5SDimitry Andric auto Table = llvm::make_unique<GenericTable>();
6684ba319b5SDimitry Andric Table->Name = TableRec->getName();
6694ba319b5SDimitry Andric Table->PreprocessorGuard = TableRec->getName();
6704ba319b5SDimitry Andric Table->CppTypeName = TableRec->getValueAsString("CppTypeName");
6714ba319b5SDimitry Andric
6724ba319b5SDimitry Andric std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");
6734ba319b5SDimitry Andric for (const auto &FieldName : Fields) {
6744ba319b5SDimitry Andric Table->Fields.emplace_back(FieldName);
6754ba319b5SDimitry Andric
6764ba319b5SDimitry Andric if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
6774ba319b5SDimitry Andric if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) {
6784ba319b5SDimitry Andric PrintFatalError(Twine("Table '") + Table->Name +
6794ba319b5SDimitry Andric "' has bad 'TypeOf_" + FieldName + "': " +
6804ba319b5SDimitry Andric TypeOfVal->getValue()->getAsString());
6814ba319b5SDimitry Andric }
6824ba319b5SDimitry Andric }
6834ba319b5SDimitry Andric }
6844ba319b5SDimitry Andric
6854ba319b5SDimitry Andric collectTableEntries(*Table, Records.getAllDerivedDefinitions(
6864ba319b5SDimitry Andric TableRec->getValueAsString("FilterClass")));
6874ba319b5SDimitry Andric
6884ba319b5SDimitry Andric if (!TableRec->isValueUnset("PrimaryKey")) {
6894ba319b5SDimitry Andric Table->PrimaryKey =
6904ba319b5SDimitry Andric parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"),
6914ba319b5SDimitry Andric TableRec->getValueAsListOfStrings("PrimaryKey"),
6924ba319b5SDimitry Andric TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
6934ba319b5SDimitry Andric
6944ba319b5SDimitry Andric std::stable_sort(Table->Entries.begin(), Table->Entries.end(),
6954ba319b5SDimitry Andric [&](Record *LHS, Record *RHS) {
6964ba319b5SDimitry Andric return compareBy(LHS, RHS, *Table->PrimaryKey);
6974ba319b5SDimitry Andric });
6984ba319b5SDimitry Andric }
6994ba319b5SDimitry Andric
7004ba319b5SDimitry Andric TableMap.insert(std::make_pair(TableRec, Table.get()));
7014ba319b5SDimitry Andric Tables.emplace_back(std::move(Table));
7024ba319b5SDimitry Andric }
7034ba319b5SDimitry Andric
7044ba319b5SDimitry Andric for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {
7054ba319b5SDimitry Andric Record *TableRec = IndexRec->getValueAsDef("Table");
7064ba319b5SDimitry Andric auto It = TableMap.find(TableRec);
7074ba319b5SDimitry Andric if (It == TableMap.end())
7084ba319b5SDimitry Andric PrintFatalError(Twine("SearchIndex '") + IndexRec->getName() +
7094ba319b5SDimitry Andric "' refers to non-existing table '" + TableRec->getName());
7104ba319b5SDimitry Andric
7114ba319b5SDimitry Andric GenericTable &Table = *It->second;
7124ba319b5SDimitry Andric Table.Indices.push_back(parseSearchIndex(
7134ba319b5SDimitry Andric Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"),
7144ba319b5SDimitry Andric IndexRec->getValueAsBit("EarlyOut")));
7154ba319b5SDimitry Andric }
7164ba319b5SDimitry Andric
7174ba319b5SDimitry Andric // Translate legacy tables.
7183ca95b02SDimitry Andric Record *SearchableTable = Records.getClass("SearchableTable");
7193ca95b02SDimitry Andric for (auto &NameRec : Records.getClasses()) {
7203ca95b02SDimitry Andric Record *Class = NameRec.second.get();
7213ca95b02SDimitry Andric if (Class->getSuperClasses().size() != 1 ||
7223ca95b02SDimitry Andric !Class->isSubClassOf(SearchableTable))
7233ca95b02SDimitry Andric continue;
7244ba319b5SDimitry Andric
7254ba319b5SDimitry Andric StringRef TableName = Class->getName();
7264ba319b5SDimitry Andric std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
7274ba319b5SDimitry Andric if (!Class->isValueUnset("EnumNameField")) {
7284ba319b5SDimitry Andric StringRef NameField = Class->getValueAsString("EnumNameField");
7294ba319b5SDimitry Andric StringRef ValueField;
7304ba319b5SDimitry Andric if (!Class->isValueUnset("EnumValueField"))
7314ba319b5SDimitry Andric ValueField = Class->getValueAsString("EnumValueField");
7324ba319b5SDimitry Andric
7334ba319b5SDimitry Andric auto Enum = llvm::make_unique<GenericEnum>();
7344ba319b5SDimitry Andric Enum->Name = (Twine(Class->getName()) + "Values").str();
7354ba319b5SDimitry Andric Enum->PreprocessorGuard = Class->getName().upper();
7364ba319b5SDimitry Andric Enum->Class = Class;
7374ba319b5SDimitry Andric
7384ba319b5SDimitry Andric collectEnumEntries(*Enum, NameField, ValueField, Items);
7394ba319b5SDimitry Andric
7404ba319b5SDimitry Andric Enums.emplace_back(std::move(Enum));
7413ca95b02SDimitry Andric }
7424ba319b5SDimitry Andric
7434ba319b5SDimitry Andric auto Table = llvm::make_unique<GenericTable>();
7444ba319b5SDimitry Andric Table->Name = (Twine(Class->getName()) + "sList").str();
7454ba319b5SDimitry Andric Table->PreprocessorGuard = Class->getName().upper();
7464ba319b5SDimitry Andric Table->CppTypeName = Class->getName();
7474ba319b5SDimitry Andric
7484ba319b5SDimitry Andric for (const RecordVal &Field : Class->getValues()) {
7494ba319b5SDimitry Andric std::string FieldName = Field.getName();
7504ba319b5SDimitry Andric
7514ba319b5SDimitry Andric // Skip uninteresting fields: either special to us, or injected
7524ba319b5SDimitry Andric // template parameters (if they contain a ':').
7534ba319b5SDimitry Andric if (FieldName.find(':') != std::string::npos ||
7544ba319b5SDimitry Andric FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
7554ba319b5SDimitry Andric FieldName == "EnumValueField")
7564ba319b5SDimitry Andric continue;
7574ba319b5SDimitry Andric
7584ba319b5SDimitry Andric Table->Fields.emplace_back(FieldName);
7594ba319b5SDimitry Andric }
7604ba319b5SDimitry Andric
7614ba319b5SDimitry Andric collectTableEntries(*Table, Items);
7624ba319b5SDimitry Andric
7634ba319b5SDimitry Andric for (const auto &Field :
7644ba319b5SDimitry Andric Class->getValueAsListOfStrings("SearchableFields")) {
7654ba319b5SDimitry Andric std::string Name =
7664ba319b5SDimitry Andric (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
7674ba319b5SDimitry Andric Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false));
7684ba319b5SDimitry Andric }
7694ba319b5SDimitry Andric
7704ba319b5SDimitry Andric Tables.emplace_back(std::move(Table));
7714ba319b5SDimitry Andric }
7724ba319b5SDimitry Andric
7734ba319b5SDimitry Andric // Emit everything.
7744ba319b5SDimitry Andric for (const auto &Enum : Enums)
7754ba319b5SDimitry Andric emitGenericEnum(*Enum, OS);
7764ba319b5SDimitry Andric
7774ba319b5SDimitry Andric for (const auto &Table : Tables)
7784ba319b5SDimitry Andric emitGenericTable(*Table, OS);
7794ba319b5SDimitry Andric
7804ba319b5SDimitry Andric // Put all #undefs last, to allow multiple sections guarded by the same
7814ba319b5SDimitry Andric // define.
7824ba319b5SDimitry Andric for (const auto &Guard : PreprocessorGuards)
7834ba319b5SDimitry Andric OS << "#undef " << Guard << "\n";
7843ca95b02SDimitry Andric }
7853ca95b02SDimitry Andric
7863ca95b02SDimitry Andric namespace llvm {
7873ca95b02SDimitry Andric
EmitSearchableTables(RecordKeeper & RK,raw_ostream & OS)7883ca95b02SDimitry Andric void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
7893ca95b02SDimitry Andric SearchableTableEmitter(RK).run(OS);
7903ca95b02SDimitry Andric }
7913ca95b02SDimitry Andric
7923ca95b02SDimitry Andric } // End llvm namespace.
793