1*0b57cec5SDimitry Andric //===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This tablegen backend emits a generic array initialized by specified fields, 10*0b57cec5SDimitry Andric // together with companion index tables and lookup functions (binary search, 11*0b57cec5SDimitry Andric // currently). 12*0b57cec5SDimitry Andric // 13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/Format.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 19*0b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 20*0b57cec5SDimitry Andric #include "llvm/TableGen/Error.h" 21*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 22*0b57cec5SDimitry Andric #include "CodeGenIntrinsics.h" 23*0b57cec5SDimitry Andric #include <algorithm> 24*0b57cec5SDimitry Andric #include <set> 25*0b57cec5SDimitry Andric #include <string> 26*0b57cec5SDimitry Andric #include <vector> 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric using namespace llvm; 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric #define DEBUG_TYPE "searchable-table-emitter" 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric namespace { 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric struct GenericTable; 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric int getAsInt(Init *B) { 37*0b57cec5SDimitry Andric return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue(); 38*0b57cec5SDimitry Andric } 39*0b57cec5SDimitry Andric int getInt(Record *R, StringRef Field) { 40*0b57cec5SDimitry Andric return getAsInt(R->getValueInit(Field)); 41*0b57cec5SDimitry Andric } 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric struct GenericEnum { 44*0b57cec5SDimitry Andric using Entry = std::pair<StringRef, int64_t>; 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric std::string Name; 47*0b57cec5SDimitry Andric Record *Class; 48*0b57cec5SDimitry Andric std::string PreprocessorGuard; 49*0b57cec5SDimitry Andric std::vector<std::unique_ptr<Entry>> Entries; 50*0b57cec5SDimitry Andric DenseMap<Record *, Entry *> EntryMap; 51*0b57cec5SDimitry Andric }; 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric struct GenericField { 54*0b57cec5SDimitry Andric std::string Name; 55*0b57cec5SDimitry Andric RecTy *RecType = nullptr; 56*0b57cec5SDimitry Andric bool IsIntrinsic = false; 57*0b57cec5SDimitry Andric bool IsInstruction = false; 58*0b57cec5SDimitry Andric GenericEnum *Enum = nullptr; 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric GenericField(StringRef Name) : Name(Name) {} 61*0b57cec5SDimitry Andric }; 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric struct SearchIndex { 64*0b57cec5SDimitry Andric std::string Name; 65*0b57cec5SDimitry Andric SmallVector<GenericField, 1> Fields; 66*0b57cec5SDimitry Andric bool EarlyOut; 67*0b57cec5SDimitry Andric }; 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric struct GenericTable { 70*0b57cec5SDimitry Andric std::string Name; 71*0b57cec5SDimitry Andric std::string PreprocessorGuard; 72*0b57cec5SDimitry Andric std::string CppTypeName; 73*0b57cec5SDimitry Andric SmallVector<GenericField, 2> Fields; 74*0b57cec5SDimitry Andric std::vector<Record *> Entries; 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric std::unique_ptr<SearchIndex> PrimaryKey; 77*0b57cec5SDimitry Andric SmallVector<std::unique_ptr<SearchIndex>, 2> Indices; 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric const GenericField *getFieldByName(StringRef Name) const { 80*0b57cec5SDimitry Andric for (const auto &Field : Fields) { 81*0b57cec5SDimitry Andric if (Name == Field.Name) 82*0b57cec5SDimitry Andric return &Field; 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric return nullptr; 85*0b57cec5SDimitry Andric } 86*0b57cec5SDimitry Andric }; 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric class SearchableTableEmitter { 89*0b57cec5SDimitry Andric RecordKeeper &Records; 90*0b57cec5SDimitry Andric DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics; 91*0b57cec5SDimitry Andric std::vector<std::unique_ptr<GenericEnum>> Enums; 92*0b57cec5SDimitry Andric DenseMap<Record *, GenericEnum *> EnumMap; 93*0b57cec5SDimitry Andric std::set<std::string> PreprocessorGuards; 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric public: 96*0b57cec5SDimitry Andric SearchableTableEmitter(RecordKeeper &R) : Records(R) {} 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric void run(raw_ostream &OS); 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric private: 101*0b57cec5SDimitry Andric typedef std::pair<Init *, int> SearchTableEntry; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric enum TypeContext { 104*0b57cec5SDimitry Andric TypeInStaticStruct, 105*0b57cec5SDimitry Andric TypeInTempStruct, 106*0b57cec5SDimitry Andric TypeInArgument, 107*0b57cec5SDimitry Andric }; 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric std::string primaryRepresentation(const GenericField &Field, Init *I) { 110*0b57cec5SDimitry Andric if (StringInit *SI = dyn_cast<StringInit>(I)) 111*0b57cec5SDimitry Andric return SI->getAsString(); 112*0b57cec5SDimitry Andric else if (BitsInit *BI = dyn_cast<BitsInit>(I)) 113*0b57cec5SDimitry Andric return "0x" + utohexstr(getAsInt(BI)); 114*0b57cec5SDimitry Andric else if (BitInit *BI = dyn_cast<BitInit>(I)) 115*0b57cec5SDimitry Andric return BI->getValue() ? "true" : "false"; 116*0b57cec5SDimitry Andric else if (CodeInit *CI = dyn_cast<CodeInit>(I)) 117*0b57cec5SDimitry Andric return CI->getValue(); 118*0b57cec5SDimitry Andric else if (Field.IsIntrinsic) 119*0b57cec5SDimitry Andric return "Intrinsic::" + getIntrinsic(I).EnumName; 120*0b57cec5SDimitry Andric else if (Field.IsInstruction) 121*0b57cec5SDimitry Andric return I->getAsString(); 122*0b57cec5SDimitry Andric else if (Field.Enum) 123*0b57cec5SDimitry Andric return Field.Enum->EntryMap[cast<DefInit>(I)->getDef()]->first; 124*0b57cec5SDimitry Andric PrintFatalError(Twine("invalid field type for field '") + Field.Name + 125*0b57cec5SDimitry Andric "', expected: string, bits, bit or code"); 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric bool isIntrinsic(Init *I) { 129*0b57cec5SDimitry Andric if (DefInit *DI = dyn_cast<DefInit>(I)) 130*0b57cec5SDimitry Andric return DI->getDef()->isSubClassOf("Intrinsic"); 131*0b57cec5SDimitry Andric return false; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric CodeGenIntrinsic &getIntrinsic(Init *I) { 135*0b57cec5SDimitry Andric std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I]; 136*0b57cec5SDimitry Andric if (!Intr) 137*0b57cec5SDimitry Andric Intr = make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef()); 138*0b57cec5SDimitry Andric return *Intr; 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index); 142*0b57cec5SDimitry Andric 143*0b57cec5SDimitry Andric bool isIntegral(Init *I) { 144*0b57cec5SDimitry Andric return isa<BitsInit>(I) || isa<CodeInit>(I) || isIntrinsic(I); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) { 148*0b57cec5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) { 149*0b57cec5SDimitry Andric if (Ctx == TypeInStaticStruct) 150*0b57cec5SDimitry Andric return "const char *"; 151*0b57cec5SDimitry Andric if (Ctx == TypeInTempStruct) 152*0b57cec5SDimitry Andric return "std::string"; 153*0b57cec5SDimitry Andric return "StringRef"; 154*0b57cec5SDimitry Andric } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) { 155*0b57cec5SDimitry Andric unsigned NumBits = BI->getNumBits(); 156*0b57cec5SDimitry Andric if (NumBits <= 8) 157*0b57cec5SDimitry Andric return "uint8_t"; 158*0b57cec5SDimitry Andric if (NumBits <= 16) 159*0b57cec5SDimitry Andric return "uint16_t"; 160*0b57cec5SDimitry Andric if (NumBits <= 32) 161*0b57cec5SDimitry Andric return "uint32_t"; 162*0b57cec5SDimitry Andric if (NumBits <= 64) 163*0b57cec5SDimitry Andric return "uint64_t"; 164*0b57cec5SDimitry Andric PrintFatalError(Twine("bitfield '") + Field.Name + 165*0b57cec5SDimitry Andric "' too large to search"); 166*0b57cec5SDimitry Andric } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) 167*0b57cec5SDimitry Andric return "unsigned"; 168*0b57cec5SDimitry Andric PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" + 169*0b57cec5SDimitry Andric Field.RecType->getAsString() + "' to search by"); 170*0b57cec5SDimitry Andric } 171*0b57cec5SDimitry Andric 172*0b57cec5SDimitry Andric void emitGenericTable(const GenericTable &Table, raw_ostream &OS); 173*0b57cec5SDimitry Andric void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS); 174*0b57cec5SDimitry Andric void emitLookupDeclaration(const GenericTable &Table, 175*0b57cec5SDimitry Andric const SearchIndex &Index, raw_ostream &OS); 176*0b57cec5SDimitry Andric void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index, 177*0b57cec5SDimitry Andric bool IsPrimary, raw_ostream &OS); 178*0b57cec5SDimitry Andric void emitIfdef(StringRef Guard, raw_ostream &OS); 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric bool parseFieldType(GenericField &Field, Init *II); 181*0b57cec5SDimitry Andric std::unique_ptr<SearchIndex> 182*0b57cec5SDimitry Andric parseSearchIndex(GenericTable &Table, StringRef Name, 183*0b57cec5SDimitry Andric const std::vector<StringRef> &Key, bool EarlyOut); 184*0b57cec5SDimitry Andric void collectEnumEntries(GenericEnum &Enum, StringRef NameField, 185*0b57cec5SDimitry Andric StringRef ValueField, 186*0b57cec5SDimitry Andric const std::vector<Record *> &Items); 187*0b57cec5SDimitry Andric void collectTableEntries(GenericTable &Table, 188*0b57cec5SDimitry Andric const std::vector<Record *> &Items); 189*0b57cec5SDimitry Andric }; 190*0b57cec5SDimitry Andric 191*0b57cec5SDimitry Andric } // End anonymous namespace. 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric // For search indices that consists of a single field whose numeric value is 194*0b57cec5SDimitry Andric // known, return that numeric value. 195*0b57cec5SDimitry Andric static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) { 196*0b57cec5SDimitry Andric assert(Index.Fields.size() == 1); 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric if (Index.Fields[0].Enum) { 199*0b57cec5SDimitry Andric Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name); 200*0b57cec5SDimitry Andric return Index.Fields[0].Enum->EntryMap[EnumEntry]->second; 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric return getInt(Rec, Index.Fields[0].Name); 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric /// Less-than style comparison between \p LHS and \p RHS according to the 207*0b57cec5SDimitry Andric /// key of \p Index. 208*0b57cec5SDimitry Andric bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS, 209*0b57cec5SDimitry Andric const SearchIndex &Index) { 210*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 211*0b57cec5SDimitry Andric Init *LHSI = LHS->getValueInit(Field.Name); 212*0b57cec5SDimitry Andric Init *RHSI = RHS->getValueInit(Field.Name); 213*0b57cec5SDimitry Andric 214*0b57cec5SDimitry Andric if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) { 215*0b57cec5SDimitry Andric int64_t LHSi = getAsInt(LHSI); 216*0b57cec5SDimitry Andric int64_t RHSi = getAsInt(RHSI); 217*0b57cec5SDimitry Andric if (LHSi < RHSi) 218*0b57cec5SDimitry Andric return true; 219*0b57cec5SDimitry Andric if (LHSi > RHSi) 220*0b57cec5SDimitry Andric return false; 221*0b57cec5SDimitry Andric } else if (Field.IsIntrinsic) { 222*0b57cec5SDimitry Andric CodeGenIntrinsic &LHSi = getIntrinsic(LHSI); 223*0b57cec5SDimitry Andric CodeGenIntrinsic &RHSi = getIntrinsic(RHSI); 224*0b57cec5SDimitry Andric if (std::tie(LHSi.TargetPrefix, LHSi.Name) < 225*0b57cec5SDimitry Andric std::tie(RHSi.TargetPrefix, RHSi.Name)) 226*0b57cec5SDimitry Andric return true; 227*0b57cec5SDimitry Andric if (std::tie(LHSi.TargetPrefix, LHSi.Name) > 228*0b57cec5SDimitry Andric std::tie(RHSi.TargetPrefix, RHSi.Name)) 229*0b57cec5SDimitry Andric return false; 230*0b57cec5SDimitry Andric } else if (Field.IsInstruction) { 231*0b57cec5SDimitry Andric // This does not correctly compare the predefined instructions! 232*0b57cec5SDimitry Andric Record *LHSr = cast<DefInit>(LHSI)->getDef(); 233*0b57cec5SDimitry Andric Record *RHSr = cast<DefInit>(RHSI)->getDef(); 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric bool LHSpseudo = LHSr->getValueAsBit("isPseudo"); 236*0b57cec5SDimitry Andric bool RHSpseudo = RHSr->getValueAsBit("isPseudo"); 237*0b57cec5SDimitry Andric if (LHSpseudo && !RHSpseudo) 238*0b57cec5SDimitry Andric return true; 239*0b57cec5SDimitry Andric if (!LHSpseudo && RHSpseudo) 240*0b57cec5SDimitry Andric return false; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric int comp = LHSr->getName().compare(RHSr->getName()); 243*0b57cec5SDimitry Andric if (comp < 0) 244*0b57cec5SDimitry Andric return true; 245*0b57cec5SDimitry Andric if (comp > 0) 246*0b57cec5SDimitry Andric return false; 247*0b57cec5SDimitry Andric } else if (Field.Enum) { 248*0b57cec5SDimitry Andric auto LHSr = cast<DefInit>(LHSI)->getDef(); 249*0b57cec5SDimitry Andric auto RHSr = cast<DefInit>(RHSI)->getDef(); 250*0b57cec5SDimitry Andric int64_t LHSv = Field.Enum->EntryMap[LHSr]->second; 251*0b57cec5SDimitry Andric int64_t RHSv = Field.Enum->EntryMap[RHSr]->second; 252*0b57cec5SDimitry Andric if (LHSv < RHSv) 253*0b57cec5SDimitry Andric return true; 254*0b57cec5SDimitry Andric if (LHSv > RHSv) 255*0b57cec5SDimitry Andric return false; 256*0b57cec5SDimitry Andric } else { 257*0b57cec5SDimitry Andric std::string LHSs = primaryRepresentation(Field, LHSI); 258*0b57cec5SDimitry Andric std::string RHSs = primaryRepresentation(Field, RHSI); 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) { 261*0b57cec5SDimitry Andric LHSs = StringRef(LHSs).upper(); 262*0b57cec5SDimitry Andric RHSs = StringRef(RHSs).upper(); 263*0b57cec5SDimitry Andric } 264*0b57cec5SDimitry Andric 265*0b57cec5SDimitry Andric int comp = LHSs.compare(RHSs); 266*0b57cec5SDimitry Andric if (comp < 0) 267*0b57cec5SDimitry Andric return true; 268*0b57cec5SDimitry Andric if (comp > 0) 269*0b57cec5SDimitry Andric return false; 270*0b57cec5SDimitry Andric } 271*0b57cec5SDimitry Andric } 272*0b57cec5SDimitry Andric return false; 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) { 276*0b57cec5SDimitry Andric OS << "#ifdef " << Guard << "\n"; 277*0b57cec5SDimitry Andric PreprocessorGuards.insert(Guard); 278*0b57cec5SDimitry Andric } 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric /// Emit a generic enum. 281*0b57cec5SDimitry Andric void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum, 282*0b57cec5SDimitry Andric raw_ostream &OS) { 283*0b57cec5SDimitry Andric emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS); 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric OS << "enum " << Enum.Name << " {\n"; 286*0b57cec5SDimitry Andric for (const auto &Entry : Enum.Entries) 287*0b57cec5SDimitry Andric OS << " " << Entry->first << " = " << Entry->second << ",\n"; 288*0b57cec5SDimitry Andric OS << "};\n"; 289*0b57cec5SDimitry Andric 290*0b57cec5SDimitry Andric OS << "#endif\n\n"; 291*0b57cec5SDimitry Andric } 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, 294*0b57cec5SDimitry Andric const SearchIndex &Index, 295*0b57cec5SDimitry Andric bool IsPrimary, 296*0b57cec5SDimitry Andric raw_ostream &OS) { 297*0b57cec5SDimitry Andric OS << "\n"; 298*0b57cec5SDimitry Andric emitLookupDeclaration(Table, Index, OS); 299*0b57cec5SDimitry Andric OS << " {\n"; 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric std::vector<Record *> IndexRowsStorage; 302*0b57cec5SDimitry Andric ArrayRef<Record *> IndexRows; 303*0b57cec5SDimitry Andric StringRef IndexTypeName; 304*0b57cec5SDimitry Andric StringRef IndexName; 305*0b57cec5SDimitry Andric 306*0b57cec5SDimitry Andric if (IsPrimary) { 307*0b57cec5SDimitry Andric IndexTypeName = Table.CppTypeName; 308*0b57cec5SDimitry Andric IndexName = Table.Name; 309*0b57cec5SDimitry Andric IndexRows = Table.Entries; 310*0b57cec5SDimitry Andric } else { 311*0b57cec5SDimitry Andric OS << " struct IndexType {\n"; 312*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 313*0b57cec5SDimitry Andric OS << " " << searchableFieldType(Field, TypeInStaticStruct) << " " 314*0b57cec5SDimitry Andric << Field.Name << ";\n"; 315*0b57cec5SDimitry Andric } 316*0b57cec5SDimitry Andric OS << " unsigned _index;\n"; 317*0b57cec5SDimitry Andric OS << " };\n"; 318*0b57cec5SDimitry Andric 319*0b57cec5SDimitry Andric OS << " static const struct IndexType Index[] = {\n"; 320*0b57cec5SDimitry Andric 321*0b57cec5SDimitry Andric std::vector<std::pair<Record *, unsigned>> Entries; 322*0b57cec5SDimitry Andric Entries.reserve(Table.Entries.size()); 323*0b57cec5SDimitry Andric for (unsigned i = 0; i < Table.Entries.size(); ++i) 324*0b57cec5SDimitry Andric Entries.emplace_back(Table.Entries[i], i); 325*0b57cec5SDimitry Andric 326*0b57cec5SDimitry Andric std::stable_sort(Entries.begin(), Entries.end(), 327*0b57cec5SDimitry Andric [&](const std::pair<Record *, unsigned> &LHS, 328*0b57cec5SDimitry Andric const std::pair<Record *, unsigned> &RHS) { 329*0b57cec5SDimitry Andric return compareBy(LHS.first, RHS.first, Index); 330*0b57cec5SDimitry Andric }); 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric IndexRowsStorage.reserve(Entries.size()); 333*0b57cec5SDimitry Andric for (const auto &Entry : Entries) { 334*0b57cec5SDimitry Andric IndexRowsStorage.push_back(Entry.first); 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric OS << " { "; 337*0b57cec5SDimitry Andric bool NeedComma = false; 338*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 339*0b57cec5SDimitry Andric if (NeedComma) 340*0b57cec5SDimitry Andric OS << ", "; 341*0b57cec5SDimitry Andric NeedComma = true; 342*0b57cec5SDimitry Andric 343*0b57cec5SDimitry Andric std::string Repr = 344*0b57cec5SDimitry Andric primaryRepresentation(Field, Entry.first->getValueInit(Field.Name)); 345*0b57cec5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) 346*0b57cec5SDimitry Andric Repr = StringRef(Repr).upper(); 347*0b57cec5SDimitry Andric OS << Repr; 348*0b57cec5SDimitry Andric } 349*0b57cec5SDimitry Andric OS << ", " << Entry.second << " },\n"; 350*0b57cec5SDimitry Andric } 351*0b57cec5SDimitry Andric 352*0b57cec5SDimitry Andric OS << " };\n\n"; 353*0b57cec5SDimitry Andric 354*0b57cec5SDimitry Andric IndexTypeName = "IndexType"; 355*0b57cec5SDimitry Andric IndexName = "Index"; 356*0b57cec5SDimitry Andric IndexRows = IndexRowsStorage; 357*0b57cec5SDimitry Andric } 358*0b57cec5SDimitry Andric 359*0b57cec5SDimitry Andric bool IsContiguous = false; 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric if (Index.Fields.size() == 1 && 362*0b57cec5SDimitry Andric (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) { 363*0b57cec5SDimitry Andric IsContiguous = true; 364*0b57cec5SDimitry Andric for (unsigned i = 0; i < IndexRows.size(); ++i) { 365*0b57cec5SDimitry Andric if (getNumericKey(Index, IndexRows[i]) != i) { 366*0b57cec5SDimitry Andric IsContiguous = false; 367*0b57cec5SDimitry Andric break; 368*0b57cec5SDimitry Andric } 369*0b57cec5SDimitry Andric } 370*0b57cec5SDimitry Andric } 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric if (IsContiguous) { 373*0b57cec5SDimitry Andric OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; 374*0b57cec5SDimitry Andric OS << " size_t Idx = " << Index.Fields[0].Name << ";\n"; 375*0b57cec5SDimitry Andric OS << " return Idx >= Table.size() ? nullptr : "; 376*0b57cec5SDimitry Andric if (IsPrimary) 377*0b57cec5SDimitry Andric OS << "&Table[Idx]"; 378*0b57cec5SDimitry Andric else 379*0b57cec5SDimitry Andric OS << "&" << Table.Name << "[Table[Idx]._index]"; 380*0b57cec5SDimitry Andric OS << ";\n"; 381*0b57cec5SDimitry Andric OS << "}\n"; 382*0b57cec5SDimitry Andric return; 383*0b57cec5SDimitry Andric } 384*0b57cec5SDimitry Andric 385*0b57cec5SDimitry Andric if (Index.EarlyOut) { 386*0b57cec5SDimitry Andric const GenericField &Field = Index.Fields[0]; 387*0b57cec5SDimitry Andric std::string FirstRepr = 388*0b57cec5SDimitry Andric primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name)); 389*0b57cec5SDimitry Andric std::string LastRepr = primaryRepresentation( 390*0b57cec5SDimitry Andric Field, IndexRows.back()->getValueInit(Field.Name)); 391*0b57cec5SDimitry Andric OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n"; 392*0b57cec5SDimitry Andric OS << " (" << Field.Name << " > " << LastRepr << "))\n"; 393*0b57cec5SDimitry Andric OS << " return nullptr;\n\n"; 394*0b57cec5SDimitry Andric } 395*0b57cec5SDimitry Andric 396*0b57cec5SDimitry Andric OS << " struct KeyType {\n"; 397*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 398*0b57cec5SDimitry Andric OS << " " << searchableFieldType(Field, TypeInTempStruct) << " " 399*0b57cec5SDimitry Andric << Field.Name << ";\n"; 400*0b57cec5SDimitry Andric } 401*0b57cec5SDimitry Andric OS << " };\n"; 402*0b57cec5SDimitry Andric OS << " KeyType Key = { "; 403*0b57cec5SDimitry Andric bool NeedComma = false; 404*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 405*0b57cec5SDimitry Andric if (NeedComma) 406*0b57cec5SDimitry Andric OS << ", "; 407*0b57cec5SDimitry Andric NeedComma = true; 408*0b57cec5SDimitry Andric 409*0b57cec5SDimitry Andric OS << Field.Name; 410*0b57cec5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) { 411*0b57cec5SDimitry Andric OS << ".upper()"; 412*0b57cec5SDimitry Andric if (IsPrimary) 413*0b57cec5SDimitry Andric PrintFatalError(Twine("Use a secondary index for case-insensitive " 414*0b57cec5SDimitry Andric "comparison of field '") + 415*0b57cec5SDimitry Andric Field.Name + "' in table '" + Table.Name + "'"); 416*0b57cec5SDimitry Andric } 417*0b57cec5SDimitry Andric } 418*0b57cec5SDimitry Andric OS << " };\n"; 419*0b57cec5SDimitry Andric 420*0b57cec5SDimitry Andric OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; 421*0b57cec5SDimitry Andric OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n"; 422*0b57cec5SDimitry Andric OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n"; 423*0b57cec5SDimitry Andric 424*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 425*0b57cec5SDimitry Andric if (isa<StringRecTy>(Field.RecType)) { 426*0b57cec5SDimitry Andric OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name 427*0b57cec5SDimitry Andric << ").compare(RHS." << Field.Name << ");\n"; 428*0b57cec5SDimitry Andric OS << " if (Cmp" << Field.Name << " < 0) return true;\n"; 429*0b57cec5SDimitry Andric OS << " if (Cmp" << Field.Name << " > 0) return false;\n"; 430*0b57cec5SDimitry Andric } else if (Field.Enum) { 431*0b57cec5SDimitry Andric // Explicitly cast to unsigned, because the signedness of enums is 432*0b57cec5SDimitry Andric // compiler-dependent. 433*0b57cec5SDimitry Andric OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS." 434*0b57cec5SDimitry Andric << Field.Name << ")\n"; 435*0b57cec5SDimitry Andric OS << " return true;\n"; 436*0b57cec5SDimitry Andric OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS." 437*0b57cec5SDimitry Andric << Field.Name << ")\n"; 438*0b57cec5SDimitry Andric OS << " return false;\n"; 439*0b57cec5SDimitry Andric } else { 440*0b57cec5SDimitry Andric OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n"; 441*0b57cec5SDimitry Andric OS << " return true;\n"; 442*0b57cec5SDimitry Andric OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n"; 443*0b57cec5SDimitry Andric OS << " return false;\n"; 444*0b57cec5SDimitry Andric } 445*0b57cec5SDimitry Andric } 446*0b57cec5SDimitry Andric 447*0b57cec5SDimitry Andric OS << " return false;\n"; 448*0b57cec5SDimitry Andric OS << " });\n\n"; 449*0b57cec5SDimitry Andric 450*0b57cec5SDimitry Andric OS << " if (Idx == Table.end()"; 451*0b57cec5SDimitry Andric 452*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) 453*0b57cec5SDimitry Andric OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name; 454*0b57cec5SDimitry Andric OS << ")\n return nullptr;\n"; 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric if (IsPrimary) 457*0b57cec5SDimitry Andric OS << " return &*Idx;\n"; 458*0b57cec5SDimitry Andric else 459*0b57cec5SDimitry Andric OS << " return &" << Table.Name << "[Idx->_index];\n"; 460*0b57cec5SDimitry Andric 461*0b57cec5SDimitry Andric OS << "}\n"; 462*0b57cec5SDimitry Andric } 463*0b57cec5SDimitry Andric 464*0b57cec5SDimitry Andric void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table, 465*0b57cec5SDimitry Andric const SearchIndex &Index, 466*0b57cec5SDimitry Andric raw_ostream &OS) { 467*0b57cec5SDimitry Andric OS << "const " << Table.CppTypeName << " *" << Index.Name << "("; 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric bool NeedComma = false; 470*0b57cec5SDimitry Andric for (const auto &Field : Index.Fields) { 471*0b57cec5SDimitry Andric if (NeedComma) 472*0b57cec5SDimitry Andric OS << ", "; 473*0b57cec5SDimitry Andric NeedComma = true; 474*0b57cec5SDimitry Andric 475*0b57cec5SDimitry Andric OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name; 476*0b57cec5SDimitry Andric } 477*0b57cec5SDimitry Andric OS << ")"; 478*0b57cec5SDimitry Andric } 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric void SearchableTableEmitter::emitGenericTable(const GenericTable &Table, 481*0b57cec5SDimitry Andric raw_ostream &OS) { 482*0b57cec5SDimitry Andric emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS); 483*0b57cec5SDimitry Andric 484*0b57cec5SDimitry Andric // Emit the declarations for the functions that will perform lookup. 485*0b57cec5SDimitry Andric if (Table.PrimaryKey) { 486*0b57cec5SDimitry Andric emitLookupDeclaration(Table, *Table.PrimaryKey, OS); 487*0b57cec5SDimitry Andric OS << ";\n"; 488*0b57cec5SDimitry Andric } 489*0b57cec5SDimitry Andric for (const auto &Index : Table.Indices) { 490*0b57cec5SDimitry Andric emitLookupDeclaration(Table, *Index, OS); 491*0b57cec5SDimitry Andric OS << ";\n"; 492*0b57cec5SDimitry Andric } 493*0b57cec5SDimitry Andric 494*0b57cec5SDimitry Andric OS << "#endif\n\n"; 495*0b57cec5SDimitry Andric 496*0b57cec5SDimitry Andric emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS); 497*0b57cec5SDimitry Andric 498*0b57cec5SDimitry Andric // The primary data table contains all the fields defined for this map. 499*0b57cec5SDimitry Andric OS << "const " << Table.CppTypeName << " " << Table.Name << "[] = {\n"; 500*0b57cec5SDimitry Andric for (unsigned i = 0; i < Table.Entries.size(); ++i) { 501*0b57cec5SDimitry Andric Record *Entry = Table.Entries[i]; 502*0b57cec5SDimitry Andric OS << " { "; 503*0b57cec5SDimitry Andric 504*0b57cec5SDimitry Andric bool NeedComma = false; 505*0b57cec5SDimitry Andric for (const auto &Field : Table.Fields) { 506*0b57cec5SDimitry Andric if (NeedComma) 507*0b57cec5SDimitry Andric OS << ", "; 508*0b57cec5SDimitry Andric NeedComma = true; 509*0b57cec5SDimitry Andric 510*0b57cec5SDimitry Andric OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name)); 511*0b57cec5SDimitry Andric } 512*0b57cec5SDimitry Andric 513*0b57cec5SDimitry Andric OS << " }, // " << i << "\n"; 514*0b57cec5SDimitry Andric } 515*0b57cec5SDimitry Andric OS << " };\n"; 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary 518*0b57cec5SDimitry Andric // search can be performed by "Thing". 519*0b57cec5SDimitry Andric if (Table.PrimaryKey) 520*0b57cec5SDimitry Andric emitLookupFunction(Table, *Table.PrimaryKey, true, OS); 521*0b57cec5SDimitry Andric for (const auto &Index : Table.Indices) 522*0b57cec5SDimitry Andric emitLookupFunction(Table, *Index, false, OS); 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric OS << "#endif\n\n"; 525*0b57cec5SDimitry Andric } 526*0b57cec5SDimitry Andric 527*0b57cec5SDimitry Andric bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) { 528*0b57cec5SDimitry Andric if (auto DI = dyn_cast<DefInit>(II)) { 529*0b57cec5SDimitry Andric Record *TypeRec = DI->getDef(); 530*0b57cec5SDimitry Andric if (TypeRec->isSubClassOf("GenericEnum")) { 531*0b57cec5SDimitry Andric Field.Enum = EnumMap[TypeRec]; 532*0b57cec5SDimitry Andric Field.RecType = RecordRecTy::get(Field.Enum->Class); 533*0b57cec5SDimitry Andric return true; 534*0b57cec5SDimitry Andric } 535*0b57cec5SDimitry Andric } 536*0b57cec5SDimitry Andric 537*0b57cec5SDimitry Andric return false; 538*0b57cec5SDimitry Andric } 539*0b57cec5SDimitry Andric 540*0b57cec5SDimitry Andric std::unique_ptr<SearchIndex> 541*0b57cec5SDimitry Andric SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name, 542*0b57cec5SDimitry Andric const std::vector<StringRef> &Key, 543*0b57cec5SDimitry Andric bool EarlyOut) { 544*0b57cec5SDimitry Andric auto Index = llvm::make_unique<SearchIndex>(); 545*0b57cec5SDimitry Andric Index->Name = Name; 546*0b57cec5SDimitry Andric Index->EarlyOut = EarlyOut; 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric for (const auto &FieldName : Key) { 549*0b57cec5SDimitry Andric const GenericField *Field = Table.getFieldByName(FieldName); 550*0b57cec5SDimitry Andric if (!Field) 551*0b57cec5SDimitry Andric PrintFatalError(Twine("Search index '") + Name + 552*0b57cec5SDimitry Andric "' refers to non-existing field '" + FieldName + 553*0b57cec5SDimitry Andric "' in table '" + Table.Name + "'"); 554*0b57cec5SDimitry Andric Index->Fields.push_back(*Field); 555*0b57cec5SDimitry Andric } 556*0b57cec5SDimitry Andric 557*0b57cec5SDimitry Andric if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) { 558*0b57cec5SDimitry Andric PrintFatalError( 559*0b57cec5SDimitry Andric "Early-out is not supported for string types (in search index '" + 560*0b57cec5SDimitry Andric Twine(Name) + "'"); 561*0b57cec5SDimitry Andric } 562*0b57cec5SDimitry Andric 563*0b57cec5SDimitry Andric return Index; 564*0b57cec5SDimitry Andric } 565*0b57cec5SDimitry Andric 566*0b57cec5SDimitry Andric void SearchableTableEmitter::collectEnumEntries( 567*0b57cec5SDimitry Andric GenericEnum &Enum, StringRef NameField, StringRef ValueField, 568*0b57cec5SDimitry Andric const std::vector<Record *> &Items) { 569*0b57cec5SDimitry Andric for (auto EntryRec : Items) { 570*0b57cec5SDimitry Andric StringRef Name; 571*0b57cec5SDimitry Andric if (NameField.empty()) 572*0b57cec5SDimitry Andric Name = EntryRec->getName(); 573*0b57cec5SDimitry Andric else 574*0b57cec5SDimitry Andric Name = EntryRec->getValueAsString(NameField); 575*0b57cec5SDimitry Andric 576*0b57cec5SDimitry Andric int64_t Value = 0; 577*0b57cec5SDimitry Andric if (!ValueField.empty()) 578*0b57cec5SDimitry Andric Value = getInt(EntryRec, ValueField); 579*0b57cec5SDimitry Andric 580*0b57cec5SDimitry Andric Enum.Entries.push_back(llvm::make_unique<GenericEnum::Entry>(Name, Value)); 581*0b57cec5SDimitry Andric Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get())); 582*0b57cec5SDimitry Andric } 583*0b57cec5SDimitry Andric 584*0b57cec5SDimitry Andric if (ValueField.empty()) { 585*0b57cec5SDimitry Andric std::stable_sort(Enum.Entries.begin(), Enum.Entries.end(), 586*0b57cec5SDimitry Andric [](const std::unique_ptr<GenericEnum::Entry> &LHS, 587*0b57cec5SDimitry Andric const std::unique_ptr<GenericEnum::Entry> &RHS) { 588*0b57cec5SDimitry Andric return LHS->first < RHS->first; 589*0b57cec5SDimitry Andric }); 590*0b57cec5SDimitry Andric 591*0b57cec5SDimitry Andric for (size_t i = 0; i < Enum.Entries.size(); ++i) 592*0b57cec5SDimitry Andric Enum.Entries[i]->second = i; 593*0b57cec5SDimitry Andric } 594*0b57cec5SDimitry Andric } 595*0b57cec5SDimitry Andric 596*0b57cec5SDimitry Andric void SearchableTableEmitter::collectTableEntries( 597*0b57cec5SDimitry Andric GenericTable &Table, const std::vector<Record *> &Items) { 598*0b57cec5SDimitry Andric for (auto EntryRec : Items) { 599*0b57cec5SDimitry Andric for (auto &Field : Table.Fields) { 600*0b57cec5SDimitry Andric auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name)); 601*0b57cec5SDimitry Andric if (!TI) { 602*0b57cec5SDimitry Andric PrintFatalError(EntryRec->getLoc(), 603*0b57cec5SDimitry Andric Twine("Record '") + EntryRec->getName() + 604*0b57cec5SDimitry Andric "' in table '" + Table.Name + 605*0b57cec5SDimitry Andric "' is missing field '" + Field.Name + "'"); 606*0b57cec5SDimitry Andric } 607*0b57cec5SDimitry Andric if (!Field.RecType) { 608*0b57cec5SDimitry Andric Field.RecType = TI->getType(); 609*0b57cec5SDimitry Andric } else { 610*0b57cec5SDimitry Andric RecTy *Ty = resolveTypes(Field.RecType, TI->getType()); 611*0b57cec5SDimitry Andric if (!Ty) 612*0b57cec5SDimitry Andric PrintFatalError(Twine("Field '") + Field.Name + "' of table '" + 613*0b57cec5SDimitry Andric Table.Name + "' has incompatible type: " + 614*0b57cec5SDimitry Andric Field.RecType->getAsString() + " vs. " + 615*0b57cec5SDimitry Andric TI->getType()->getAsString()); 616*0b57cec5SDimitry Andric Field.RecType = Ty; 617*0b57cec5SDimitry Andric } 618*0b57cec5SDimitry Andric } 619*0b57cec5SDimitry Andric 620*0b57cec5SDimitry Andric Table.Entries.push_back(EntryRec); 621*0b57cec5SDimitry Andric } 622*0b57cec5SDimitry Andric 623*0b57cec5SDimitry Andric Record *IntrinsicClass = Records.getClass("Intrinsic"); 624*0b57cec5SDimitry Andric Record *InstructionClass = Records.getClass("Instruction"); 625*0b57cec5SDimitry Andric for (auto &Field : Table.Fields) { 626*0b57cec5SDimitry Andric if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) { 627*0b57cec5SDimitry Andric if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass)) 628*0b57cec5SDimitry Andric Field.IsIntrinsic = true; 629*0b57cec5SDimitry Andric else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass)) 630*0b57cec5SDimitry Andric Field.IsInstruction = true; 631*0b57cec5SDimitry Andric } 632*0b57cec5SDimitry Andric } 633*0b57cec5SDimitry Andric } 634*0b57cec5SDimitry Andric 635*0b57cec5SDimitry Andric void SearchableTableEmitter::run(raw_ostream &OS) { 636*0b57cec5SDimitry Andric // Emit tables in a deterministic order to avoid needless rebuilds. 637*0b57cec5SDimitry Andric SmallVector<std::unique_ptr<GenericTable>, 4> Tables; 638*0b57cec5SDimitry Andric DenseMap<Record *, GenericTable *> TableMap; 639*0b57cec5SDimitry Andric 640*0b57cec5SDimitry Andric // Collect all definitions first. 641*0b57cec5SDimitry Andric for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) { 642*0b57cec5SDimitry Andric StringRef NameField; 643*0b57cec5SDimitry Andric if (!EnumRec->isValueUnset("NameField")) 644*0b57cec5SDimitry Andric NameField = EnumRec->getValueAsString("NameField"); 645*0b57cec5SDimitry Andric 646*0b57cec5SDimitry Andric StringRef ValueField; 647*0b57cec5SDimitry Andric if (!EnumRec->isValueUnset("ValueField")) 648*0b57cec5SDimitry Andric ValueField = EnumRec->getValueAsString("ValueField"); 649*0b57cec5SDimitry Andric 650*0b57cec5SDimitry Andric auto Enum = llvm::make_unique<GenericEnum>(); 651*0b57cec5SDimitry Andric Enum->Name = EnumRec->getName(); 652*0b57cec5SDimitry Andric Enum->PreprocessorGuard = EnumRec->getName(); 653*0b57cec5SDimitry Andric 654*0b57cec5SDimitry Andric StringRef FilterClass = EnumRec->getValueAsString("FilterClass"); 655*0b57cec5SDimitry Andric Enum->Class = Records.getClass(FilterClass); 656*0b57cec5SDimitry Andric if (!Enum->Class) 657*0b57cec5SDimitry Andric PrintFatalError(EnumRec->getLoc(), Twine("Enum FilterClass '") + 658*0b57cec5SDimitry Andric FilterClass + "' does not exist"); 659*0b57cec5SDimitry Andric 660*0b57cec5SDimitry Andric collectEnumEntries(*Enum, NameField, ValueField, 661*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions(FilterClass)); 662*0b57cec5SDimitry Andric EnumMap.insert(std::make_pair(EnumRec, Enum.get())); 663*0b57cec5SDimitry Andric Enums.emplace_back(std::move(Enum)); 664*0b57cec5SDimitry Andric } 665*0b57cec5SDimitry Andric 666*0b57cec5SDimitry Andric for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) { 667*0b57cec5SDimitry Andric auto Table = llvm::make_unique<GenericTable>(); 668*0b57cec5SDimitry Andric Table->Name = TableRec->getName(); 669*0b57cec5SDimitry Andric Table->PreprocessorGuard = TableRec->getName(); 670*0b57cec5SDimitry Andric Table->CppTypeName = TableRec->getValueAsString("CppTypeName"); 671*0b57cec5SDimitry Andric 672*0b57cec5SDimitry Andric std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields"); 673*0b57cec5SDimitry Andric for (const auto &FieldName : Fields) { 674*0b57cec5SDimitry Andric Table->Fields.emplace_back(FieldName); 675*0b57cec5SDimitry Andric 676*0b57cec5SDimitry Andric if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) { 677*0b57cec5SDimitry Andric if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) { 678*0b57cec5SDimitry Andric PrintFatalError(TableRec->getLoc(), 679*0b57cec5SDimitry Andric Twine("Table '") + Table->Name + 680*0b57cec5SDimitry Andric "' has bad 'TypeOf_" + FieldName + 681*0b57cec5SDimitry Andric "': " + TypeOfVal->getValue()->getAsString()); 682*0b57cec5SDimitry Andric } 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric } 685*0b57cec5SDimitry Andric 686*0b57cec5SDimitry Andric collectTableEntries(*Table, Records.getAllDerivedDefinitions( 687*0b57cec5SDimitry Andric TableRec->getValueAsString("FilterClass"))); 688*0b57cec5SDimitry Andric 689*0b57cec5SDimitry Andric if (!TableRec->isValueUnset("PrimaryKey")) { 690*0b57cec5SDimitry Andric Table->PrimaryKey = 691*0b57cec5SDimitry Andric parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"), 692*0b57cec5SDimitry Andric TableRec->getValueAsListOfStrings("PrimaryKey"), 693*0b57cec5SDimitry Andric TableRec->getValueAsBit("PrimaryKeyEarlyOut")); 694*0b57cec5SDimitry Andric 695*0b57cec5SDimitry Andric std::stable_sort(Table->Entries.begin(), Table->Entries.end(), 696*0b57cec5SDimitry Andric [&](Record *LHS, Record *RHS) { 697*0b57cec5SDimitry Andric return compareBy(LHS, RHS, *Table->PrimaryKey); 698*0b57cec5SDimitry Andric }); 699*0b57cec5SDimitry Andric } 700*0b57cec5SDimitry Andric 701*0b57cec5SDimitry Andric TableMap.insert(std::make_pair(TableRec, Table.get())); 702*0b57cec5SDimitry Andric Tables.emplace_back(std::move(Table)); 703*0b57cec5SDimitry Andric } 704*0b57cec5SDimitry Andric 705*0b57cec5SDimitry Andric for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) { 706*0b57cec5SDimitry Andric Record *TableRec = IndexRec->getValueAsDef("Table"); 707*0b57cec5SDimitry Andric auto It = TableMap.find(TableRec); 708*0b57cec5SDimitry Andric if (It == TableMap.end()) 709*0b57cec5SDimitry Andric PrintFatalError(IndexRec->getLoc(), 710*0b57cec5SDimitry Andric Twine("SearchIndex '") + IndexRec->getName() + 711*0b57cec5SDimitry Andric "' refers to non-existing table '" + 712*0b57cec5SDimitry Andric TableRec->getName()); 713*0b57cec5SDimitry Andric 714*0b57cec5SDimitry Andric GenericTable &Table = *It->second; 715*0b57cec5SDimitry Andric Table.Indices.push_back(parseSearchIndex( 716*0b57cec5SDimitry Andric Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"), 717*0b57cec5SDimitry Andric IndexRec->getValueAsBit("EarlyOut"))); 718*0b57cec5SDimitry Andric } 719*0b57cec5SDimitry Andric 720*0b57cec5SDimitry Andric // Translate legacy tables. 721*0b57cec5SDimitry Andric Record *SearchableTable = Records.getClass("SearchableTable"); 722*0b57cec5SDimitry Andric for (auto &NameRec : Records.getClasses()) { 723*0b57cec5SDimitry Andric Record *Class = NameRec.second.get(); 724*0b57cec5SDimitry Andric if (Class->getSuperClasses().size() != 1 || 725*0b57cec5SDimitry Andric !Class->isSubClassOf(SearchableTable)) 726*0b57cec5SDimitry Andric continue; 727*0b57cec5SDimitry Andric 728*0b57cec5SDimitry Andric StringRef TableName = Class->getName(); 729*0b57cec5SDimitry Andric std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName); 730*0b57cec5SDimitry Andric if (!Class->isValueUnset("EnumNameField")) { 731*0b57cec5SDimitry Andric StringRef NameField = Class->getValueAsString("EnumNameField"); 732*0b57cec5SDimitry Andric StringRef ValueField; 733*0b57cec5SDimitry Andric if (!Class->isValueUnset("EnumValueField")) 734*0b57cec5SDimitry Andric ValueField = Class->getValueAsString("EnumValueField"); 735*0b57cec5SDimitry Andric 736*0b57cec5SDimitry Andric auto Enum = llvm::make_unique<GenericEnum>(); 737*0b57cec5SDimitry Andric Enum->Name = (Twine(Class->getName()) + "Values").str(); 738*0b57cec5SDimitry Andric Enum->PreprocessorGuard = Class->getName().upper(); 739*0b57cec5SDimitry Andric Enum->Class = Class; 740*0b57cec5SDimitry Andric 741*0b57cec5SDimitry Andric collectEnumEntries(*Enum, NameField, ValueField, Items); 742*0b57cec5SDimitry Andric 743*0b57cec5SDimitry Andric Enums.emplace_back(std::move(Enum)); 744*0b57cec5SDimitry Andric } 745*0b57cec5SDimitry Andric 746*0b57cec5SDimitry Andric auto Table = llvm::make_unique<GenericTable>(); 747*0b57cec5SDimitry Andric Table->Name = (Twine(Class->getName()) + "sList").str(); 748*0b57cec5SDimitry Andric Table->PreprocessorGuard = Class->getName().upper(); 749*0b57cec5SDimitry Andric Table->CppTypeName = Class->getName(); 750*0b57cec5SDimitry Andric 751*0b57cec5SDimitry Andric for (const RecordVal &Field : Class->getValues()) { 752*0b57cec5SDimitry Andric std::string FieldName = Field.getName(); 753*0b57cec5SDimitry Andric 754*0b57cec5SDimitry Andric // Skip uninteresting fields: either special to us, or injected 755*0b57cec5SDimitry Andric // template parameters (if they contain a ':'). 756*0b57cec5SDimitry Andric if (FieldName.find(':') != std::string::npos || 757*0b57cec5SDimitry Andric FieldName == "SearchableFields" || FieldName == "EnumNameField" || 758*0b57cec5SDimitry Andric FieldName == "EnumValueField") 759*0b57cec5SDimitry Andric continue; 760*0b57cec5SDimitry Andric 761*0b57cec5SDimitry Andric Table->Fields.emplace_back(FieldName); 762*0b57cec5SDimitry Andric } 763*0b57cec5SDimitry Andric 764*0b57cec5SDimitry Andric collectTableEntries(*Table, Items); 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric for (const auto &Field : 767*0b57cec5SDimitry Andric Class->getValueAsListOfStrings("SearchableFields")) { 768*0b57cec5SDimitry Andric std::string Name = 769*0b57cec5SDimitry Andric (Twine("lookup") + Table->CppTypeName + "By" + Field).str(); 770*0b57cec5SDimitry Andric Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false)); 771*0b57cec5SDimitry Andric } 772*0b57cec5SDimitry Andric 773*0b57cec5SDimitry Andric Tables.emplace_back(std::move(Table)); 774*0b57cec5SDimitry Andric } 775*0b57cec5SDimitry Andric 776*0b57cec5SDimitry Andric // Emit everything. 777*0b57cec5SDimitry Andric for (const auto &Enum : Enums) 778*0b57cec5SDimitry Andric emitGenericEnum(*Enum, OS); 779*0b57cec5SDimitry Andric 780*0b57cec5SDimitry Andric for (const auto &Table : Tables) 781*0b57cec5SDimitry Andric emitGenericTable(*Table, OS); 782*0b57cec5SDimitry Andric 783*0b57cec5SDimitry Andric // Put all #undefs last, to allow multiple sections guarded by the same 784*0b57cec5SDimitry Andric // define. 785*0b57cec5SDimitry Andric for (const auto &Guard : PreprocessorGuards) 786*0b57cec5SDimitry Andric OS << "#undef " << Guard << "\n"; 787*0b57cec5SDimitry Andric } 788*0b57cec5SDimitry Andric 789*0b57cec5SDimitry Andric namespace llvm { 790*0b57cec5SDimitry Andric 791*0b57cec5SDimitry Andric void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) { 792*0b57cec5SDimitry Andric SearchableTableEmitter(RK).run(OS); 793*0b57cec5SDimitry Andric } 794*0b57cec5SDimitry Andric 795*0b57cec5SDimitry Andric } // End llvm namespace. 796