Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/SearchableTableEmitter.cpp
35258 views
//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend emits a generic array initialized by specified fields,9// together with companion index tables and lookup functions. The lookup10// function generated is either a direct lookup (when a single primary key field11// is integral and densely numbered) or a binary search otherwise.12//13//===----------------------------------------------------------------------===//1415#include "Basic/CodeGenIntrinsics.h"16#include "Common/CodeGenTarget.h"17#include "llvm/ADT/ArrayRef.h"18#include "llvm/ADT/DenseMap.h"19#include "llvm/ADT/STLExtras.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/TableGen/Error.h"22#include "llvm/TableGen/Record.h"23#include "llvm/TableGen/TableGenBackend.h"24#include <algorithm>25#include <set>26#include <string>27#include <vector>2829using namespace llvm;3031#define DEBUG_TYPE "searchable-table-emitter"3233namespace {3435int64_t getAsInt(Init *B) {36return cast<IntInit>(37B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper())))38->getValue();39}40int64_t getInt(Record *R, StringRef Field) {41return getAsInt(R->getValueInit(Field));42}4344struct GenericEnum {45using Entry = std::pair<StringRef, int64_t>;4647std::string Name;48Record *Class = nullptr;49std::string PreprocessorGuard;50std::vector<std::unique_ptr<Entry>> Entries;51DenseMap<Record *, Entry *> EntryMap;52};5354struct GenericField {55std::string Name;56RecTy *RecType = nullptr;57bool IsCode = false;58bool IsIntrinsic = false;59bool IsInstruction = false;60GenericEnum *Enum = nullptr;6162GenericField(StringRef Name) : Name(std::string(Name)) {}63};6465struct SearchIndex {66std::string Name;67SMLoc Loc; // Source location of PrimaryKey or Key field definition.68SmallVector<GenericField, 1> Fields;69bool EarlyOut = false;70bool ReturnRange = false;71};7273struct GenericTable {74std::string Name;75ArrayRef<SMLoc> Locs; // Source locations from the Record instance.76std::string PreprocessorGuard;77std::string CppTypeName;78SmallVector<GenericField, 2> Fields;79std::vector<Record *> Entries;8081std::unique_ptr<SearchIndex> PrimaryKey;82SmallVector<std::unique_ptr<SearchIndex>, 2> Indices;8384const GenericField *getFieldByName(StringRef Name) const {85for (const auto &Field : Fields) {86if (Name == Field.Name)87return &Field;88}89return nullptr;90}91};9293class SearchableTableEmitter {94RecordKeeper &Records;95std::unique_ptr<CodeGenTarget> Target;96DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics;97std::vector<std::unique_ptr<GenericEnum>> Enums;98DenseMap<Record *, GenericEnum *> EnumMap;99std::set<std::string> PreprocessorGuards;100101public:102SearchableTableEmitter(RecordKeeper &R) : Records(R) {}103104void run(raw_ostream &OS);105106private:107typedef std::pair<Init *, int> SearchTableEntry;108109enum TypeContext {110TypeInStaticStruct,111TypeInTempStruct,112TypeInArgument,113};114115std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,116Init *I) {117if (StringInit *SI = dyn_cast<StringInit>(I)) {118if (Field.IsCode || SI->hasCodeFormat())119return std::string(SI->getValue());120else121return SI->getAsString();122} else if (BitsInit *BI = dyn_cast<BitsInit>(I))123return "0x" + utohexstr(getAsInt(BI));124else if (BitInit *BI = dyn_cast<BitInit>(I))125return BI->getValue() ? "true" : "false";126else if (Field.IsIntrinsic)127return "Intrinsic::" + getIntrinsic(I).EnumName;128else if (Field.IsInstruction)129return I->getAsString();130else if (Field.Enum) {131auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];132if (!Entry)133PrintFatalError(Loc,134Twine("Entry for field '") + Field.Name + "' is null");135return std::string(Entry->first);136}137PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +138"'; expected: bit, bits, string, or code");139}140141bool isIntrinsic(Init *I) {142if (DefInit *DI = dyn_cast<DefInit>(I))143return DI->getDef()->isSubClassOf("Intrinsic");144return false;145}146147CodeGenIntrinsic &getIntrinsic(Init *I) {148std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];149if (!Intr)150Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),151std::vector<Record *>());152return *Intr;153}154155bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);156157std::string searchableFieldType(const GenericTable &Table,158const SearchIndex &Index,159const GenericField &Field, TypeContext Ctx) {160if (isa<StringRecTy>(Field.RecType)) {161if (Ctx == TypeInStaticStruct)162return "const char *";163if (Ctx == TypeInTempStruct)164return "std::string";165return "StringRef";166} else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) {167unsigned NumBits = BI->getNumBits();168if (NumBits <= 8)169return "uint8_t";170if (NumBits <= 16)171return "uint16_t";172if (NumBits <= 32)173return "uint32_t";174if (NumBits <= 64)175return "uint64_t";176PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +177"' lookup method '" + Index.Name +178"', key field '" + Field.Name +179"' of type bits is too large");180} else if (isa<BitRecTy>(Field.RecType)) {181return "bool";182} else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)183return "unsigned";184PrintFatalError(Index.Loc,185Twine("In table '") + Table.Name + "' lookup method '" +186Index.Name + "', key field '" + Field.Name +187"' has invalid type: " + Field.RecType->getAsString());188}189190void emitGenericTable(const GenericTable &Table, raw_ostream &OS);191void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS);192void emitLookupDeclaration(const GenericTable &Table,193const SearchIndex &Index, raw_ostream &OS);194void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,195bool IsPrimary, raw_ostream &OS);196void emitIfdef(StringRef Guard, raw_ostream &OS);197198bool parseFieldType(GenericField &Field, Init *II);199std::unique_ptr<SearchIndex>200parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,201const std::vector<StringRef> &Key, bool EarlyOut,202bool ReturnRange);203void collectEnumEntries(GenericEnum &Enum, StringRef NameField,204StringRef ValueField,205const std::vector<Record *> &Items);206void collectTableEntries(GenericTable &Table,207const std::vector<Record *> &Items);208int64_t getNumericKey(const SearchIndex &Index, Record *Rec);209};210211} // End anonymous namespace.212213// For search indices that consists of a single field whose numeric value is214// known, return that numeric value.215int64_t SearchableTableEmitter::getNumericKey(const SearchIndex &Index,216Record *Rec) {217assert(Index.Fields.size() == 1);218219// To be consistent with compareBy and primaryRepresentation elsewhere,220// we check for IsInstruction before Enum-- these fields are not exclusive.221if (Index.Fields[0].IsInstruction) {222Record *TheDef = Rec->getValueAsDef(Index.Fields[0].Name);223return Target->getInstrIntValue(TheDef);224}225if (Index.Fields[0].Enum) {226Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name);227return Index.Fields[0].Enum->EntryMap[EnumEntry]->second;228}229230return getInt(Rec, Index.Fields[0].Name);231}232233/// Less-than style comparison between \p LHS and \p RHS according to the234/// key of \p Index.235bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,236const SearchIndex &Index) {237for (const auto &Field : Index.Fields) {238Init *LHSI = LHS->getValueInit(Field.Name);239Init *RHSI = RHS->getValueInit(Field.Name);240241if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) {242int64_t LHSi = getAsInt(LHSI);243int64_t RHSi = getAsInt(RHSI);244if (LHSi < RHSi)245return true;246if (LHSi > RHSi)247return false;248} else if (Field.IsIntrinsic) {249CodeGenIntrinsic &LHSi = getIntrinsic(LHSI);250CodeGenIntrinsic &RHSi = getIntrinsic(RHSI);251if (std::tie(LHSi.TargetPrefix, LHSi.Name) <252std::tie(RHSi.TargetPrefix, RHSi.Name))253return true;254if (std::tie(LHSi.TargetPrefix, LHSi.Name) >255std::tie(RHSi.TargetPrefix, RHSi.Name))256return false;257} else if (Field.IsInstruction) {258// This does not correctly compare the predefined instructions!259Record *LHSr = cast<DefInit>(LHSI)->getDef();260Record *RHSr = cast<DefInit>(RHSI)->getDef();261262bool LHSpseudo = LHSr->getValueAsBit("isPseudo");263bool RHSpseudo = RHSr->getValueAsBit("isPseudo");264if (LHSpseudo && !RHSpseudo)265return true;266if (!LHSpseudo && RHSpseudo)267return false;268269int comp = LHSr->getName().compare(RHSr->getName());270if (comp < 0)271return true;272if (comp > 0)273return false;274} else if (Field.Enum) {275auto LHSr = cast<DefInit>(LHSI)->getDef();276auto RHSr = cast<DefInit>(RHSI)->getDef();277int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;278int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;279if (LHSv < RHSv)280return true;281if (LHSv > RHSv)282return false;283} else {284std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);285std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);286287if (isa<StringRecTy>(Field.RecType)) {288LHSs = StringRef(LHSs).upper();289RHSs = StringRef(RHSs).upper();290}291292int comp = LHSs.compare(RHSs);293if (comp < 0)294return true;295if (comp > 0)296return false;297}298}299return false;300}301302void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) {303OS << "#ifdef " << Guard << "\n";304PreprocessorGuards.insert(std::string(Guard));305}306307/// Emit a generic enum.308void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,309raw_ostream &OS) {310emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);311312OS << "enum " << Enum.Name << " {\n";313for (const auto &Entry : Enum.Entries)314OS << " " << Entry->first << " = " << Entry->second << ",\n";315OS << "};\n";316317OS << "#endif\n\n";318}319320void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,321const SearchIndex &Index,322bool IsPrimary,323raw_ostream &OS) {324OS << "\n";325emitLookupDeclaration(Table, Index, OS);326OS << " {\n";327328std::vector<Record *> IndexRowsStorage;329ArrayRef<Record *> IndexRows;330StringRef IndexTypeName;331StringRef IndexName;332333if (IsPrimary) {334IndexTypeName = Table.CppTypeName;335IndexName = Table.Name;336IndexRows = Table.Entries;337} else {338OS << " struct IndexType {\n";339for (const auto &Field : Index.Fields) {340OS << " "341<< searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "342<< Field.Name << ";\n";343}344OS << " unsigned _index;\n";345OS << " };\n";346347OS << " static const struct IndexType Index[] = {\n";348349std::vector<std::pair<Record *, unsigned>> Entries;350Entries.reserve(Table.Entries.size());351for (unsigned i = 0; i < Table.Entries.size(); ++i)352Entries.emplace_back(Table.Entries[i], i);353354llvm::stable_sort(Entries, [&](const std::pair<Record *, unsigned> &LHS,355const std::pair<Record *, unsigned> &RHS) {356return compareBy(LHS.first, RHS.first, Index);357});358359IndexRowsStorage.reserve(Entries.size());360for (const auto &Entry : Entries) {361IndexRowsStorage.push_back(Entry.first);362363OS << " { ";364ListSeparator LS;365for (const auto &Field : Index.Fields) {366std::string Repr = primaryRepresentation(367Index.Loc, Field, Entry.first->getValueInit(Field.Name));368if (isa<StringRecTy>(Field.RecType))369Repr = StringRef(Repr).upper();370OS << LS << Repr;371}372OS << ", " << Entry.second << " },\n";373}374375OS << " };\n\n";376377IndexTypeName = "IndexType";378IndexName = "Index";379IndexRows = IndexRowsStorage;380}381382bool IsContiguous = false;383384if (Index.Fields.size() == 1 &&385(Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType) ||386Index.Fields[0].IsInstruction)) {387int64_t FirstKeyVal = getNumericKey(Index, IndexRows[0]);388IsContiguous = true;389for (unsigned i = 0; i < IndexRows.size(); ++i) {390if (getNumericKey(Index, IndexRows[i]) != (FirstKeyVal + i)) {391IsContiguous = false;392break;393}394}395}396397if (IsContiguous) {398const GenericField &Field = Index.Fields[0];399std::string FirstRepr = primaryRepresentation(400Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));401std::string LastRepr = primaryRepresentation(402Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));403OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n";404OS << " (" << Field.Name << " > " << LastRepr << "))\n";405OS << " return nullptr;\n";406OS << " auto Table = ArrayRef(" << IndexName << ");\n";407OS << " size_t Idx = " << Index.Fields[0].Name << " - " << FirstRepr408<< ";\n";409OS << " return ";410if (IsPrimary)411OS << "&Table[Idx]";412else413OS << "&" << Table.Name << "[Table[Idx]._index]";414OS << ";\n";415OS << "}\n";416return;417}418419if (Index.EarlyOut) {420const GenericField &Field = Index.Fields[0];421std::string FirstRepr = primaryRepresentation(422Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));423std::string LastRepr = primaryRepresentation(424Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));425OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n";426OS << " (" << Field.Name << " > " << LastRepr << "))\n";427OS << " return nullptr;\n\n";428}429430OS << " struct KeyType {\n";431for (const auto &Field : Index.Fields) {432OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)433<< " " << Field.Name << ";\n";434}435OS << " };\n";436OS << " KeyType Key = {";437ListSeparator LS;438for (const auto &Field : Index.Fields) {439OS << LS << Field.Name;440if (isa<StringRecTy>(Field.RecType)) {441OS << ".upper()";442if (IsPrimary)443PrintFatalError(Index.Loc,444Twine("In table '") + Table.Name +445"', use a secondary lookup method for "446"case-insensitive comparison of field '" +447Field.Name + "'");448}449}450OS << "};\n";451452OS << " struct Comp {\n";453OS << " bool operator()(const " << IndexTypeName454<< " &LHS, const KeyType &RHS) const {\n";455456auto emitComparator = [&]() {457for (const auto &Field : Index.Fields) {458if (isa<StringRecTy>(Field.RecType)) {459OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name460<< ").compare(RHS." << Field.Name << ");\n";461OS << " if (Cmp" << Field.Name << " < 0) return true;\n";462OS << " if (Cmp" << Field.Name << " > 0) return false;\n";463} else if (Field.Enum) {464// Explicitly cast to unsigned, because the signedness of enums is465// compiler-dependent.466OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS."467<< Field.Name << ")\n";468OS << " return true;\n";469OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS."470<< Field.Name << ")\n";471OS << " return false;\n";472} else {473OS << " if (LHS." << Field.Name << " < RHS." << Field.Name474<< ")\n";475OS << " return true;\n";476OS << " if (LHS." << Field.Name << " > RHS." << Field.Name477<< ")\n";478OS << " return false;\n";479}480}481OS << " return false;\n";482OS << " }\n";483};484emitComparator();485bool ShouldReturnRange = Index.ReturnRange;486if (ShouldReturnRange) {487OS << " bool operator()(const KeyType &LHS, const " << IndexTypeName488<< " &RHS) const {\n";489emitComparator();490}491492OS << " };\n";493OS << " auto Table = ArrayRef(" << IndexName << ");\n";494if (ShouldReturnRange)495OS << " auto It = std::equal_range(Table.begin(), Table.end(), Key, ";496else497OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key, ";498OS << "Comp());\n";499500if (!ShouldReturnRange) {501OS << " if (Idx == Table.end()";502for (const auto &Field : Index.Fields)503OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name;504}505506if (ShouldReturnRange)507OS << " return llvm::make_range(It.first, It.second);\n";508else if (IsPrimary) {509OS << ")\n return nullptr;\n\n";510OS << " return &*Idx;\n";511} else {512OS << ")\n return nullptr;\n\n";513OS << " return &" << Table.Name << "[Idx->_index];\n";514}515516OS << "}\n";517}518519void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,520const SearchIndex &Index,521raw_ostream &OS) {522if (Index.ReturnRange)523OS << "llvm::iterator_range<const " << Table.CppTypeName << " *> ";524else525OS << "const " << Table.CppTypeName << " *";526OS << Index.Name << "(";527ListSeparator LS;528for (const auto &Field : Index.Fields)529OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "530<< Field.Name;531OS << ")";532}533534void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,535raw_ostream &OS) {536emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS);537538// Emit the declarations for the functions that will perform lookup.539if (Table.PrimaryKey) {540emitLookupDeclaration(Table, *Table.PrimaryKey, OS);541OS << ";\n";542}543for (const auto &Index : Table.Indices) {544emitLookupDeclaration(Table, *Index, OS);545OS << ";\n";546}547548OS << "#endif\n\n";549550emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);551552// The primary data table contains all the fields defined for this map.553OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";554for (unsigned i = 0; i < Table.Entries.size(); ++i) {555Record *Entry = Table.Entries[i];556OS << " { ";557558ListSeparator LS;559for (const auto &Field : Table.Fields)560OS << LS561<< primaryRepresentation(Table.Locs[0], Field,562Entry->getValueInit(Field.Name));563564OS << " }, // " << i << "\n";565}566OS << " };\n";567568// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary569// search can be performed by "Thing".570if (Table.PrimaryKey)571emitLookupFunction(Table, *Table.PrimaryKey, /*IsPrimary=*/true, OS);572for (const auto &Index : Table.Indices)573emitLookupFunction(Table, *Index, /*IsPrimary=*/false, OS);574575OS << "#endif\n\n";576}577578bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {579if (auto Type = dyn_cast<StringInit>(TypeOf)) {580if (Type->getValue() == "code") {581Field.IsCode = true;582return true;583} else {584if (Record *TypeRec = Records.getDef(Type->getValue())) {585if (TypeRec->isSubClassOf("GenericEnum")) {586Field.Enum = EnumMap[TypeRec];587Field.RecType = RecordRecTy::get(Field.Enum->Class);588return true;589}590}591}592}593594return false;595}596597std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(598GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,599const std::vector<StringRef> &Key, bool EarlyOut, bool ReturnRange) {600auto Index = std::make_unique<SearchIndex>();601Index->Name = std::string(Name);602Index->Loc = KeyRecVal->getLoc();603Index->EarlyOut = EarlyOut;604Index->ReturnRange = ReturnRange;605606for (const auto &FieldName : Key) {607const GenericField *Field = Table.getFieldByName(FieldName);608if (!Field)609PrintFatalError(610KeyRecVal,611Twine("In table '") + Table.Name +612"', 'PrimaryKey' or 'Key' refers to nonexistent field '" +613FieldName + "'");614615Index->Fields.push_back(*Field);616}617618if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {619PrintFatalError(620KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +621"supported for a first key field of type string");622}623624return Index;625}626627void SearchableTableEmitter::collectEnumEntries(628GenericEnum &Enum, StringRef NameField, StringRef ValueField,629const std::vector<Record *> &Items) {630for (auto *EntryRec : Items) {631StringRef Name;632if (NameField.empty())633Name = EntryRec->getName();634else635Name = EntryRec->getValueAsString(NameField);636637int64_t Value = 0;638if (!ValueField.empty())639Value = getInt(EntryRec, ValueField);640641Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));642Enum.EntryMap.insert(std::pair(EntryRec, Enum.Entries.back().get()));643}644645if (ValueField.empty()) {646llvm::stable_sort(Enum.Entries,647[](const std::unique_ptr<GenericEnum::Entry> &LHS,648const std::unique_ptr<GenericEnum::Entry> &RHS) {649return LHS->first < RHS->first;650});651652for (size_t i = 0; i < Enum.Entries.size(); ++i)653Enum.Entries[i]->second = i;654}655}656657void SearchableTableEmitter::collectTableEntries(658GenericTable &Table, const std::vector<Record *> &Items) {659if (Items.empty())660PrintFatalError(Table.Locs,661Twine("Table '") + Table.Name + "' has no entries");662663for (auto *EntryRec : Items) {664for (auto &Field : Table.Fields) {665auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));666if (!TI || !TI->isComplete()) {667PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +668"' for table '" + Table.Name +669"' is missing field '" + Field.Name +670"'");671}672if (!Field.RecType) {673Field.RecType = TI->getType();674} else {675RecTy *Ty = resolveTypes(Field.RecType, TI->getType());676if (!Ty)677PrintFatalError(EntryRec->getValue(Field.Name),678Twine("Field '") + Field.Name + "' of table '" +679Table.Name + "' entry has incompatible type: " +680TI->getType()->getAsString() + " vs. " +681Field.RecType->getAsString());682Field.RecType = Ty;683}684}685686Table.Entries.push_back(EntryRec); // Add record to table's record list.687}688689Record *IntrinsicClass = Records.getClass("Intrinsic");690Record *InstructionClass = Records.getClass("Instruction");691for (auto &Field : Table.Fields) {692if (!Field.RecType)693PrintFatalError(Twine("Cannot determine type of field '") + Field.Name +694"' in table '" + Table.Name + "'. Maybe it is not used?");695696if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) {697if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass))698Field.IsIntrinsic = true;699else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass))700Field.IsInstruction = true;701}702}703704SearchIndex Idx;705std::copy(Table.Fields.begin(), Table.Fields.end(),706std::back_inserter(Idx.Fields));707llvm::sort(Table.Entries, [&](Record *LHS, Record *RHS) {708return compareBy(LHS, RHS, Idx);709});710}711712void SearchableTableEmitter::run(raw_ostream &OS) {713// Emit tables in a deterministic order to avoid needless rebuilds.714SmallVector<std::unique_ptr<GenericTable>, 4> Tables;715DenseMap<Record *, GenericTable *> TableMap;716if (!Records.getAllDerivedDefinitionsIfDefined("Instruction").empty())717Target = std::make_unique<CodeGenTarget>(Records);718719// Collect all definitions first.720for (auto *EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {721StringRef NameField;722if (!EnumRec->isValueUnset("NameField"))723NameField = EnumRec->getValueAsString("NameField");724725StringRef ValueField;726if (!EnumRec->isValueUnset("ValueField"))727ValueField = EnumRec->getValueAsString("ValueField");728729auto Enum = std::make_unique<GenericEnum>();730Enum->Name = std::string(EnumRec->getName());731Enum->PreprocessorGuard = std::string(EnumRec->getName());732733StringRef FilterClass = EnumRec->getValueAsString("FilterClass");734Enum->Class = Records.getClass(FilterClass);735if (!Enum->Class)736PrintFatalError(EnumRec->getValue("FilterClass"),737Twine("Enum FilterClass '") + FilterClass +738"' does not exist");739740collectEnumEntries(*Enum, NameField, ValueField,741Records.getAllDerivedDefinitions(FilterClass));742EnumMap.insert(std::pair(EnumRec, Enum.get()));743Enums.emplace_back(std::move(Enum));744}745746for (auto *TableRec : Records.getAllDerivedDefinitions("GenericTable")) {747auto Table = std::make_unique<GenericTable>();748Table->Name = std::string(TableRec->getName());749Table->Locs = TableRec->getLoc();750Table->PreprocessorGuard = std::string(TableRec->getName());751Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName"));752753std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");754for (const auto &FieldName : Fields) {755Table->Fields.emplace_back(FieldName); // Construct a GenericField.756757if (auto TypeOfRecordVal =758TableRec->getValue(("TypeOf_" + FieldName).str())) {759if (!parseFieldType(Table->Fields.back(),760TypeOfRecordVal->getValue())) {761PrintError(TypeOfRecordVal,762Twine("Table '") + Table->Name + "' has invalid 'TypeOf_" +763FieldName +764"': " + TypeOfRecordVal->getValue()->getAsString());765PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "766"GenericEnum record, or \"code\"");767}768}769}770771StringRef FilterClass = TableRec->getValueAsString("FilterClass");772if (!Records.getClass(FilterClass))773PrintFatalError(TableRec->getValue("FilterClass"),774Twine("Table FilterClass '") + FilterClass +775"' does not exist");776777RecordVal *FilterClassFieldVal = TableRec->getValue("FilterClassField");778std::vector<Record *> Definitions =779Records.getAllDerivedDefinitions(FilterClass);780if (auto *FilterClassFieldInit =781dyn_cast<StringInit>(FilterClassFieldVal->getValue())) {782StringRef FilterClassField = FilterClassFieldInit->getValue();783llvm::erase_if(Definitions, [&](const Record *R) {784const RecordVal *Filter = R->getValue(FilterClassField);785if (auto *BitV = dyn_cast<BitInit>(Filter->getValue()))786return !BitV->getValue();787788PrintFatalError(Filter, Twine("FilterClassField '") + FilterClass +789"' should be a bit value");790return true;791});792}793collectTableEntries(*Table, Definitions);794795if (!TableRec->isValueUnset("PrimaryKey")) {796Table->PrimaryKey =797parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),798TableRec->getValueAsString("PrimaryKeyName"),799TableRec->getValueAsListOfStrings("PrimaryKey"),800TableRec->getValueAsBit("PrimaryKeyEarlyOut"),801TableRec->getValueAsBit("PrimaryKeyReturnRange"));802803llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {804return compareBy(LHS, RHS, *Table->PrimaryKey);805});806}807808TableMap.insert(std::pair(TableRec, Table.get()));809Tables.emplace_back(std::move(Table));810}811812for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) {813Record *TableRec = IndexRec->getValueAsDef("Table");814auto It = TableMap.find(TableRec);815if (It == TableMap.end())816PrintFatalError(IndexRec->getValue("Table"),817Twine("SearchIndex '") + IndexRec->getName() +818"' refers to nonexistent table '" +819TableRec->getName());820821GenericTable &Table = *It->second;822Table.Indices.push_back(parseSearchIndex(823Table, IndexRec->getValue("Key"), IndexRec->getName(),824IndexRec->getValueAsListOfStrings("Key"),825IndexRec->getValueAsBit("EarlyOut"), /*ReturnRange*/ false));826}827828// Translate legacy tables.829Record *SearchableTable = Records.getClass("SearchableTable");830for (auto &NameRec : Records.getClasses()) {831Record *Class = NameRec.second.get();832if (Class->getSuperClasses().size() != 1 ||833!Class->isSubClassOf(SearchableTable))834continue;835836StringRef TableName = Class->getName();837std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);838if (!Class->isValueUnset("EnumNameField")) {839StringRef NameField = Class->getValueAsString("EnumNameField");840StringRef ValueField;841if (!Class->isValueUnset("EnumValueField"))842ValueField = Class->getValueAsString("EnumValueField");843844auto Enum = std::make_unique<GenericEnum>();845Enum->Name = (Twine(Class->getName()) + "Values").str();846Enum->PreprocessorGuard = Class->getName().upper();847Enum->Class = Class;848849collectEnumEntries(*Enum, NameField, ValueField, Items);850851Enums.emplace_back(std::move(Enum));852}853854auto Table = std::make_unique<GenericTable>();855Table->Name = (Twine(Class->getName()) + "sList").str();856Table->Locs = Class->getLoc();857Table->PreprocessorGuard = Class->getName().upper();858Table->CppTypeName = std::string(Class->getName());859860for (const RecordVal &Field : Class->getValues()) {861std::string FieldName = std::string(Field.getName());862863// Skip uninteresting fields: either special to us, or injected864// template parameters (if they contain a ':').865if (FieldName.find(':') != std::string::npos ||866FieldName == "SearchableFields" || FieldName == "EnumNameField" ||867FieldName == "EnumValueField")868continue;869870Table->Fields.emplace_back(FieldName);871}872873collectTableEntries(*Table, Items);874875for (const auto &Field :876Class->getValueAsListOfStrings("SearchableFields")) {877std::string Name =878(Twine("lookup") + Table->CppTypeName + "By" + Field).str();879Table->Indices.push_back(880parseSearchIndex(*Table, Class->getValue(Field), Name, {Field},881/*EarlyOut*/ false, /*ReturnRange*/ false));882}883884Tables.emplace_back(std::move(Table));885}886887// Emit everything.888for (const auto &Enum : Enums)889emitGenericEnum(*Enum, OS);890891for (const auto &Table : Tables)892emitGenericTable(*Table, OS);893894// Put all #undefs last, to allow multiple sections guarded by the same895// define.896for (const auto &Guard : PreprocessorGuards)897OS << "#undef " << Guard << "\n";898}899900static TableGen::Emitter::OptClass<SearchableTableEmitter>901X("gen-searchable-tables", "Generate generic binary-searchable table");902903904