123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827 |
- //===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This tablegen backend emits a generic array initialized by specified fields,
- // together with companion index tables and lookup functions (binary search,
- // currently).
- //
- //===----------------------------------------------------------------------===//
- #include "CodeGenIntrinsics.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/TableGen/Error.h"
- #include "llvm/TableGen/Record.h"
- #include <algorithm>
- #include <set>
- #include <string>
- #include <vector>
- using namespace llvm;
- #define DEBUG_TYPE "searchable-table-emitter"
- namespace {
- int getAsInt(Init *B) {
- return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
- }
- int getInt(Record *R, StringRef Field) {
- return getAsInt(R->getValueInit(Field));
- }
- struct GenericEnum {
- using Entry = std::pair<StringRef, int64_t>;
- std::string Name;
- Record *Class = nullptr;
- std::string PreprocessorGuard;
- std::vector<std::unique_ptr<Entry>> Entries;
- DenseMap<Record *, Entry *> EntryMap;
- };
- struct GenericField {
- std::string Name;
- RecTy *RecType = nullptr;
- bool IsCode = false;
- bool IsIntrinsic = false;
- bool IsInstruction = false;
- GenericEnum *Enum = nullptr;
- GenericField(StringRef Name) : Name(std::string(Name)) {}
- };
- struct SearchIndex {
- std::string Name;
- SMLoc Loc; // Source location of PrimaryKey or Key field definition.
- SmallVector<GenericField, 1> Fields;
- bool EarlyOut = false;
- };
- struct GenericTable {
- std::string Name;
- ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
- std::string PreprocessorGuard;
- std::string CppTypeName;
- SmallVector<GenericField, 2> Fields;
- std::vector<Record *> Entries;
- std::unique_ptr<SearchIndex> PrimaryKey;
- SmallVector<std::unique_ptr<SearchIndex>, 2> Indices;
- const GenericField *getFieldByName(StringRef Name) const {
- for (const auto &Field : Fields) {
- if (Name == Field.Name)
- return &Field;
- }
- return nullptr;
- }
- };
- class SearchableTableEmitter {
- RecordKeeper &Records;
- DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;
- std::vector<std::unique_ptr<GenericEnum>> Enums;
- DenseMap<Record *, GenericEnum *> EnumMap;
- std::set<std::string> PreprocessorGuards;
- public:
- SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
- void run(raw_ostream &OS);
- private:
- typedef std::pair<Init *, int> SearchTableEntry;
- enum TypeContext {
- TypeInStaticStruct,
- TypeInTempStruct,
- TypeInArgument,
- };
- std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
- Init *I) {
- if (StringInit *SI = dyn_cast<StringInit>(I)) {
- if (Field.IsCode || SI->hasCodeFormat())
- return std::string(SI->getValue());
- else
- return SI->getAsString();
- } else if (BitsInit *BI = dyn_cast<BitsInit>(I))
- return "0x" + utohexstr(getAsInt(BI));
- else if (BitInit *BI = dyn_cast<BitInit>(I))
- return BI->getValue() ? "true" : "false";
- else if (Field.IsIntrinsic)
- return "Intrinsic::" + getIntrinsic(I).EnumName;
- else if (Field.IsInstruction)
- return I->getAsString();
- else if (Field.Enum) {
- auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
- if (!Entry)
- PrintFatalError(Loc,
- Twine("Entry for field '") + Field.Name + "' is null");
- return std::string(Entry->first);
- }
- PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
- "'; expected: bit, bits, string, or code");
- }
- bool isIntrinsic(Init *I) {
- if (DefInit *DI = dyn_cast<DefInit>(I))
- return DI->getDef()->isSubClassOf("Intrinsic");
- return false;
- }
- CodeGenIntrinsic &getIntrinsic(Init *I) {
- std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
- if (!Intr)
- Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),
- std::vector<Record *>());
- return *Intr;
- }
- bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
- std::string searchableFieldType(const GenericTable &Table,
- const SearchIndex &Index,
- const GenericField &Field, TypeContext Ctx) {
- if (isa<StringRecTy>(Field.RecType)) {
- if (Ctx == TypeInStaticStruct)
- return "const char *";
- if (Ctx == TypeInTempStruct)
- return "std::string";
- return "StringRef";
- } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
- unsigned NumBits = BI->getNumBits();
- if (NumBits <= 8)
- return "uint8_t";
- if (NumBits <= 16)
- return "uint16_t";
- if (NumBits <= 32)
- return "uint32_t";
- if (NumBits <= 64)
- return "uint64_t";
- PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
- "' lookup method '" + Index.Name +
- "', key field '" + Field.Name +
- "' of type bits is too large");
- } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
- return "unsigned";
- PrintFatalError(Index.Loc,
- Twine("In table '") + Table.Name + "' lookup method '" +
- Index.Name + "', key field '" + Field.Name +
- "' has invalid type: " + Field.RecType->getAsString());
- }
- void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
- void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);
- void emitLookupDeclaration(const GenericTable &Table,
- const SearchIndex &Index, raw_ostream &OS);
- void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
- bool IsPrimary, raw_ostream &OS);
- void emitIfdef(StringRef Guard, raw_ostream &OS);
- bool parseFieldType(GenericField &Field, Init *II);
- std::unique_ptr<SearchIndex>
- parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
- const std::vector<StringRef> &Key, bool EarlyOut);
- void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
- StringRef ValueField,
- const std::vector<Record *> &Items);
- void collectTableEntries(GenericTable &Table,
- const std::vector<Record *> &Items);
- };
- } // End anonymous namespace.
- // For search indices that consists of a single field whose numeric value is
- // known, return that numeric value.
- static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
- assert(Index.Fields.size() == 1);
- if (Index.Fields[0].Enum) {
- Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);
- return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;
- }
- return getInt(Rec, Index.Fields[0].Name);
- }
- /// Less-than style comparison between \p LHS and \p RHS according to the
- /// key of \p Index.
- bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
- const SearchIndex &Index) {
- for (const auto &Field : Index.Fields) {
- Init *LHSI = LHS->getValueInit(Field.Name);
- Init *RHSI = RHS->getValueInit(Field.Name);
- if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) {
- int64_t LHSi = getAsInt(LHSI);
- int64_t RHSi = getAsInt(RHSI);
- if (LHSi < RHSi)
- return true;
- if (LHSi > RHSi)
- return false;
- } else if (Field.IsIntrinsic) {
- CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);
- CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);
- if (std::tie(LHSi.TargetPrefix, LHSi.Name) <
- std::tie(RHSi.TargetPrefix, RHSi.Name))
- return true;
- if (std::tie(LHSi.TargetPrefix, LHSi.Name) >
- std::tie(RHSi.TargetPrefix, RHSi.Name))
- return false;
- } else if (Field.IsInstruction) {
- // This does not correctly compare the predefined instructions!
- Record *LHSr = cast<DefInit>(LHSI)->getDef();
- Record *RHSr = cast<DefInit>(RHSI)->getDef();
- bool LHSpseudo = LHSr->getValueAsBit("isPseudo");
- bool RHSpseudo = RHSr->getValueAsBit("isPseudo");
- if (LHSpseudo && !RHSpseudo)
- return true;
- if (!LHSpseudo && RHSpseudo)
- return false;
- int comp = LHSr->getName().compare(RHSr->getName());
- if (comp < 0)
- return true;
- if (comp > 0)
- return false;
- } else if (Field.Enum) {
- auto LHSr = cast<DefInit>(LHSI)->getDef();
- auto RHSr = cast<DefInit>(RHSI)->getDef();
- int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
- int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
- if (LHSv < RHSv)
- return true;
- if (LHSv > RHSv)
- return false;
- } else {
- std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);
- std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);
- if (isa<StringRecTy>(Field.RecType)) {
- LHSs = StringRef(LHSs).upper();
- RHSs = StringRef(RHSs).upper();
- }
- int comp = LHSs.compare(RHSs);
- if (comp < 0)
- return true;
- if (comp > 0)
- return false;
- }
- }
- return false;
- }
- void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {
- OS << "#ifdef " << Guard << "\n";
- PreprocessorGuards.insert(std::string(Guard));
- }
- /// Emit a generic enum.
- void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
- raw_ostream &OS) {
- emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
- OS << "enum " << Enum.Name << " {\n";
- for (const auto &Entry : Enum.Entries)
- OS << " " << Entry->first << " = " << Entry->second << ",\n";
- OS << "};\n";
- OS << "#endif\n\n";
- }
- void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
- const SearchIndex &Index,
- bool IsPrimary,
- raw_ostream &OS) {
- OS << "\n";
- emitLookupDeclaration(Table, Index, OS);
- OS << " {\n";
- std::vector<Record *> IndexRowsStorage;
- ArrayRef<Record *> IndexRows;
- StringRef IndexTypeName;
- StringRef IndexName;
- if (IsPrimary) {
- IndexTypeName = Table.CppTypeName;
- IndexName = Table.Name;
- IndexRows = Table.Entries;
- } else {
- OS << " struct IndexType {\n";
- for (const auto &Field : Index.Fields) {
- OS << " "
- << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "
- << Field.Name << ";\n";
- }
- OS << " unsigned _index;\n";
- OS << " };\n";
- OS << " static const struct IndexType Index[] = {\n";
- std::vector<std::pair<Record *, unsigned>> Entries;
- Entries.reserve(Table.Entries.size());
- for (unsigned i = 0; i < Table.Entries.size(); ++i)
- Entries.emplace_back(Table.Entries[i], i);
- llvm::stable_sort(Entries, [&](const std::pair<Record *, unsigned> &LHS,
- const std::pair<Record *, unsigned> &RHS) {
- return compareBy(LHS.first, RHS.first, Index);
- });
- IndexRowsStorage.reserve(Entries.size());
- for (const auto &Entry : Entries) {
- IndexRowsStorage.push_back(Entry.first);
- OS << " { ";
- ListSeparator LS;
- for (const auto &Field : Index.Fields) {
- std::string Repr = primaryRepresentation(
- Index.Loc, Field, Entry.first->getValueInit(Field.Name));
- if (isa<StringRecTy>(Field.RecType))
- Repr = StringRef(Repr).upper();
- OS << LS << Repr;
- }
- OS << ", " << Entry.second << " },\n";
- }
- OS << " };\n\n";
- IndexTypeName = "IndexType";
- IndexName = "Index";
- IndexRows = IndexRowsStorage;
- }
- bool IsContiguous = false;
- if (Index.Fields.size() == 1 &&
- (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) {
- IsContiguous = true;
- for (unsigned i = 0; i < IndexRows.size(); ++i) {
- if (getNumericKey(Index, IndexRows[i]) != i) {
- IsContiguous = false;
- break;
- }
- }
- }
- if (IsContiguous) {
- OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
- OS << " size_t Idx = " << Index.Fields[0].Name << ";\n";
- OS << " return Idx >= Table.size() ? nullptr : ";
- if (IsPrimary)
- OS << "&Table[Idx]";
- else
- OS << "&" << Table.Name << "[Table[Idx]._index]";
- OS << ";\n";
- OS << "}\n";
- return;
- }
- if (Index.EarlyOut) {
- const GenericField &Field = Index.Fields[0];
- std::string FirstRepr = primaryRepresentation(
- Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));
- std::string LastRepr = primaryRepresentation(
- Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));
- OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
- OS << " (" << Field.Name << " > " << LastRepr << "))\n";
- OS << " return nullptr;\n\n";
- }
- OS << " struct KeyType {\n";
- for (const auto &Field : Index.Fields) {
- OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
- << " " << Field.Name << ";\n";
- }
- OS << " };\n";
- OS << " KeyType Key = {";
- ListSeparator LS;
- for (const auto &Field : Index.Fields) {
- OS << LS << Field.Name;
- if (isa<StringRecTy>(Field.RecType)) {
- OS << ".upper()";
- if (IsPrimary)
- PrintFatalError(Index.Loc,
- Twine("In table '") + Table.Name +
- "', use a secondary lookup method for "
- "case-insensitive comparison of field '" +
- Field.Name + "'");
- }
- }
- OS << "};\n";
- OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
- OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
- OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
- for (const auto &Field : Index.Fields) {
- if (isa<StringRecTy>(Field.RecType)) {
- OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
- << ").compare(RHS." << Field.Name << ");\n";
- OS << " if (Cmp" << Field.Name << " < 0) return true;\n";
- OS << " if (Cmp" << Field.Name << " > 0) return false;\n";
- } else if (Field.Enum) {
- // Explicitly cast to unsigned, because the signedness of enums is
- // compiler-dependent.
- OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."
- << Field.Name << ")\n";
- OS << " return true;\n";
- OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."
- << Field.Name << ")\n";
- OS << " return false;\n";
- } else {
- OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n";
- OS << " return true;\n";
- OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n";
- OS << " return false;\n";
- }
- }
- OS << " return false;\n";
- OS << " });\n\n";
- OS << " if (Idx == Table.end()";
- for (const auto &Field : Index.Fields)
- OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;
- OS << ")\n return nullptr;\n";
- if (IsPrimary)
- OS << " return &*Idx;\n";
- else
- OS << " return &" << Table.Name << "[Idx->_index];\n";
- OS << "}\n";
- }
- void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
- const SearchIndex &Index,
- raw_ostream &OS) {
- OS << "const " << Table.CppTypeName << " *" << Index.Name << "(";
- ListSeparator LS;
- for (const auto &Field : Index.Fields)
- OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
- << Field.Name;
- OS << ")";
- }
- void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
- raw_ostream &OS) {
- emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);
- // Emit the declarations for the functions that will perform lookup.
- if (Table.PrimaryKey) {
- emitLookupDeclaration(Table, *Table.PrimaryKey, OS);
- OS << ";\n";
- }
- for (const auto &Index : Table.Indices) {
- emitLookupDeclaration(Table, *Index, OS);
- OS << ";\n";
- }
- OS << "#endif\n\n";
- emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
- // The primary data table contains all the fields defined for this map.
- OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
- for (unsigned i = 0; i < Table.Entries.size(); ++i) {
- Record *Entry = Table.Entries[i];
- OS << " { ";
- ListSeparator LS;
- for (const auto &Field : Table.Fields)
- OS << LS
- << primaryRepresentation(Table.Locs[0], Field,
- Entry->getValueInit(Field.Name));
- OS << " }, // " << i << "\n";
- }
- OS << " };\n";
- // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
- // search can be performed by "Thing".
- if (Table.PrimaryKey)
- emitLookupFunction(Table, *Table.PrimaryKey, true, OS);
- for (const auto &Index : Table.Indices)
- emitLookupFunction(Table, *Index, false, OS);
- OS << "#endif\n\n";
- }
- bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
- if (auto Type = dyn_cast<StringInit>(TypeOf)) {
- if (Type->getValue() == "code") {
- Field.IsCode = true;
- return true;
- } else {
- if (Record *TypeRec = Records.getDef(Type->getValue())) {
- if (TypeRec->isSubClassOf("GenericEnum")) {
- Field.Enum = EnumMap[TypeRec];
- Field.RecType = RecordRecTy::get(Field.Enum->Class);
- return true;
- }
- }
- }
- }
- return false;
- }
- std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
- GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
- const std::vector<StringRef> &Key, bool EarlyOut) {
- auto Index = std::make_unique<SearchIndex>();
- Index->Name = std::string(Name);
- Index->Loc = KeyRecVal->getLoc();
- Index->EarlyOut = EarlyOut;
- for (const auto &FieldName : Key) {
- const GenericField *Field = Table.getFieldByName(FieldName);
- if (!Field)
- PrintFatalError(
- KeyRecVal,
- Twine("In table '") + Table.Name +
- "', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
- FieldName + "'");
-
- Index->Fields.push_back(*Field);
- }
- if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
- PrintFatalError(
- KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +
- "supported for a first key field of type string");
- }
- return Index;
- }
- void SearchableTableEmitter::collectEnumEntries(
- GenericEnum &Enum, StringRef NameField, StringRef ValueField,
- const std::vector<Record *> &Items) {
- for (auto EntryRec : Items) {
- StringRef Name;
- if (NameField.empty())
- Name = EntryRec->getName();
- else
- Name = EntryRec->getValueAsString(NameField);
- int64_t Value = 0;
- if (!ValueField.empty())
- Value = getInt(EntryRec, ValueField);
- Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));
- Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
- }
- if (ValueField.empty()) {
- llvm::stable_sort(Enum.Entries,
- [](const std::unique_ptr<GenericEnum::Entry> &LHS,
- const std::unique_ptr<GenericEnum::Entry> &RHS) {
- return LHS->first < RHS->first;
- });
- for (size_t i = 0; i < Enum.Entries.size(); ++i)
- Enum.Entries[i]->second = i;
- }
- }
- void SearchableTableEmitter::collectTableEntries(
- GenericTable &Table, const std::vector<Record *> &Items) {
- if (Items.empty())
- PrintFatalError(Table.Locs,
- Twine("Table '") + Table.Name + "' has no entries");
- for (auto EntryRec : Items) {
- for (auto &Field : Table.Fields) {
- auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
- if (!TI || !TI->isComplete()) {
- PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +
- "' for table '" + Table.Name +
- "' is missing field '" + Field.Name +
- "'");
- }
- if (!Field.RecType) {
- Field.RecType = TI->getType();
- } else {
- RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
- if (!Ty)
- PrintFatalError(EntryRec->getValue(Field.Name),
- Twine("Field '") + Field.Name + "' of table '" +
- Table.Name + "' entry has incompatible type: " +
- TI->getType()->getAsString() + " vs. " +
- Field.RecType->getAsString());
- Field.RecType = Ty;
- }
- }
- Table.Entries.push_back(EntryRec); // Add record to table's record list.
- }
- Record *IntrinsicClass = Records.getClass("Intrinsic");
- Record *InstructionClass = Records.getClass("Instruction");
- for (auto &Field : Table.Fields) {
- if (!Field.RecType)
- PrintFatalError(Twine("Cannot determine type of field '") + Field.Name +
- "' in table '" + Table.Name + "'. Maybe it is not used?");
- if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) {
- if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))
- Field.IsIntrinsic = true;
- else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))
- Field.IsInstruction = true;
- }
- }
- SearchIndex Idx;
- std::copy(Table.Fields.begin(), Table.Fields.end(),
- std::back_inserter(Idx.Fields));
- std::sort(Table.Entries.begin(), Table.Entries.end(),
- [&](Record *LHS, Record *RHS) { return compareBy(LHS, RHS, Idx); });
- }
- void SearchableTableEmitter::run(raw_ostream &OS) {
- // Emit tables in a deterministic order to avoid needless rebuilds.
- SmallVector<std::unique_ptr<GenericTable>, 4> Tables;
- DenseMap<Record *, GenericTable *> TableMap;
- // Collect all definitions first.
- for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
- StringRef NameField;
- if (!EnumRec->isValueUnset("NameField"))
- NameField = EnumRec->getValueAsString("NameField");
- StringRef ValueField;
- if (!EnumRec->isValueUnset("ValueField"))
- ValueField = EnumRec->getValueAsString("ValueField");
- auto Enum = std::make_unique<GenericEnum>();
- Enum->Name = std::string(EnumRec->getName());
- Enum->PreprocessorGuard = std::string(EnumRec->getName());
- StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
- Enum->Class = Records.getClass(FilterClass);
- if (!Enum->Class)
- PrintFatalError(EnumRec->getValue("FilterClass"),
- Twine("Enum FilterClass '") + FilterClass +
- "' does not exist");
- collectEnumEntries(*Enum, NameField, ValueField,
- Records.getAllDerivedDefinitions(FilterClass));
- EnumMap.insert(std::make_pair(EnumRec, Enum.get()));
- Enums.emplace_back(std::move(Enum));
- }
- for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
- auto Table = std::make_unique<GenericTable>();
- Table->Name = std::string(TableRec->getName());
- Table->Locs = TableRec->getLoc();
- Table->PreprocessorGuard = std::string(TableRec->getName());
- Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName"));
- std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");
- for (const auto &FieldName : Fields) {
- Table->Fields.emplace_back(FieldName); // Construct a GenericField.
- if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
- if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
- PrintError(TypeOfRecordVal,
- Twine("Table '") + Table->Name +
- "' has invalid 'TypeOf_" + FieldName +
- "': " + TypeOfRecordVal->getValue()->getAsString());
- PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
- "GenericEnum record, or \"code\"");
- }
- }
- }
- StringRef FilterClass = TableRec->getValueAsString("FilterClass");
- if (!Records.getClass(FilterClass))
- PrintFatalError(TableRec->getValue("FilterClass"),
- Twine("Table FilterClass '") +
- FilterClass + "' does not exist");
- collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
- if (!TableRec->isValueUnset("PrimaryKey")) {
- Table->PrimaryKey =
- parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
- TableRec->getValueAsString("PrimaryKeyName"),
- TableRec->getValueAsListOfStrings("PrimaryKey"),
- TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
- llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
- return compareBy(LHS, RHS, *Table->PrimaryKey);
- });
- }
- TableMap.insert(std::make_pair(TableRec, Table.get()));
- Tables.emplace_back(std::move(Table));
- }
- for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {
- Record *TableRec = IndexRec->getValueAsDef("Table");
- auto It = TableMap.find(TableRec);
- if (It == TableMap.end())
- PrintFatalError(IndexRec->getValue("Table"),
- Twine("SearchIndex '") + IndexRec->getName() +
- "' refers to nonexistent table '" +
- TableRec->getName());
- GenericTable &Table = *It->second;
- Table.Indices.push_back(
- parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
- IndexRec->getValueAsListOfStrings("Key"),
- IndexRec->getValueAsBit("EarlyOut")));
- }
- // Translate legacy tables.
- Record *SearchableTable = Records.getClass("SearchableTable");
- for (auto &NameRec : Records.getClasses()) {
- Record *Class = NameRec.second.get();
- if (Class->getSuperClasses().size() != 1 ||
- !Class->isSubClassOf(SearchableTable))
- continue;
- StringRef TableName = Class->getName();
- std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
- if (!Class->isValueUnset("EnumNameField")) {
- StringRef NameField = Class->getValueAsString("EnumNameField");
- StringRef ValueField;
- if (!Class->isValueUnset("EnumValueField"))
- ValueField = Class->getValueAsString("EnumValueField");
- auto Enum = std::make_unique<GenericEnum>();
- Enum->Name = (Twine(Class->getName()) + "Values").str();
- Enum->PreprocessorGuard = Class->getName().upper();
- Enum->Class = Class;
- collectEnumEntries(*Enum, NameField, ValueField, Items);
- Enums.emplace_back(std::move(Enum));
- }
- auto Table = std::make_unique<GenericTable>();
- Table->Name = (Twine(Class->getName()) + "sList").str();
- Table->Locs = Class->getLoc();
- Table->PreprocessorGuard = Class->getName().upper();
- Table->CppTypeName = std::string(Class->getName());
- for (const RecordVal &Field : Class->getValues()) {
- std::string FieldName = std::string(Field.getName());
- // Skip uninteresting fields: either special to us, or injected
- // template parameters (if they contain a ':').
- if (FieldName.find(':') != std::string::npos ||
- FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
- FieldName == "EnumValueField")
- continue;
- Table->Fields.emplace_back(FieldName);
- }
- collectTableEntries(*Table, Items);
- for (const auto &Field :
- Class->getValueAsListOfStrings("SearchableFields")) {
- std::string Name =
- (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
- Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
- Name, {Field}, false));
- }
- Tables.emplace_back(std::move(Table));
- }
- // Emit everything.
- for (const auto &Enum : Enums)
- emitGenericEnum(*Enum, OS);
- for (const auto &Table : Tables)
- emitGenericTable(*Table, OS);
- // Put all #undefs last, to allow multiple sections guarded by the same
- // define.
- for (const auto &Guard : PreprocessorGuards)
- OS << "#undef " << Guard << "\n";
- }
- namespace llvm {
- void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
- SearchableTableEmitter(RK).run(OS);
- }
- } // End llvm namespace.
|