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