Author: Matt Arsenault
Date: 2026-10-15T10:32:39+02:00
New Revision: 80017ba18d8c8866713586fa19245f0878b4f8a2

URL: 
https://github.com/llvm/llvm-project/commit/80017ba18d8c8866713586fa19245f0878b4f8a2
DIFF: 
https://github.com/llvm/llvm-project/commit/80017ba18d8c8866713586fa19245f0878b4f8a2.diff

LOG: TableGen: Store classes and defs in a StringMap (#231573)

Classes and defs were kept in a std::map ordered by name, which makes
every lookup a series of string comparisons over names that often share
long prefixes. Store them in a StringMap instead, and have getClasses()
and getDefs() return a list sorted by name, built when first needed
after records are added.

Gigainstructions executed by llvm-tblgen --null-backend

```
             before   after
  AMDGPU.td   18.17   16.98   -6.6%
  X86.td       6.15    5.84   -5.1%
  AArch64.td   3.32    3.00   -9.7%
  RISCV.td     8.26    7.44   -9.9%
```

Including the backends, all tablegen runs in a build of all targets and
clang execute 3.1% fewer instructions in total, and none are slower.
Peak memory parsing AMDGPU.td drops from 835 MB to 830 MB.

Co-authored-by: Claude Opus 5.5 <[email protected]>

Added: 
    

Modified: 
    clang/utils/TableGen/ClangDataCollectorsEmitter.cpp
    llvm/docs/TableGen/BackGuide.md
    llvm/include/llvm/TableGen/Record.h
    llvm/lib/TableGen/DetailedRecordsBackend.cpp
    llvm/lib/TableGen/JSONBackend.cpp
    llvm/lib/TableGen/Record.cpp
    llvm/utils/TableGen/CTagsEmitter.cpp
    llvm/utils/TableGen/SearchableTableEmitter.cpp
    mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp
    mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp
    mlir/tools/mlir-tblgen/OpGenHelpers.cpp

Removed: 
    


################################################################################
diff  --git a/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp 
b/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp
index 50e90691c555bf..226857673d49b6 100644
--- a/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp
+++ b/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp
@@ -17,9 +17,8 @@
 using namespace llvm;
 
 void clang::EmitClangDataCollectors(const RecordKeeper &RK, raw_ostream &OS) {
-  const auto &Defs = RK.getClasses();
-  for (const auto &Entry : Defs) {
-    Record &R = *Entry.second;
+  for (const Record *Class : RK.getClasses()) {
+    const Record &R = *Class;
     OS << "DEF_ADD_DATA(" << R.getName() << ", {\n";
     auto Code = R.getValue("Code")->getValue();
     OS << Code->getAsUnquotedString() << "}\n)";

diff  --git a/llvm/docs/TableGen/BackGuide.md b/llvm/docs/TableGen/BackGuide.md
index bc1ce3c82c5834..a1abf291423eac 100644
--- a/llvm/docs/TableGen/BackGuide.md
+++ b/llvm/docs/TableGen/BackGuide.md
@@ -434,29 +434,24 @@ conventions used in the skeleton file.
 The `RecordKeeper` class provides two functions for getting the
 `Record` instances for classes defined in the TableGen files.
 
-- `getClasses()` returns a `RecordMap` reference for all the classes.
+- `getClasses()` returns all the class records, sorted by name.
 - `getClass(`*name*`)` returns a `Record` reference for the named
   class.
 
 If you need to iterate over all the class records:
 
 ```text
-for (auto ClassPair : Records.getClasses()) {
-  Record *ClassRec = ClassPair.second.get();
+for (const Record *ClassRec : Records.getClasses()) {
   ...
 }
 ```
 
-`ClassPair.second` gets the class's `unique_ptr`, and then `.get()` gets the
-class `Record` itself.
-
 ## Getting Records
 
 The `RecordKeeper` class provides four functions for getting the
 `Record` instances for concrete records defined in the TableGen files.
 
-- `getDefs()` returns a `RecordMap` reference for all the concrete
-  records.
+- `getDefs()` returns all the concrete records, sorted by name.
 - `getDef(`*name*`)` returns a `Record` reference for the named
   concrete record.
 - `getAllDerivedDefinitions(`*classname*`)` returns a vector of

diff  --git a/llvm/include/llvm/TableGen/Record.h 
b/llvm/include/llvm/TableGen/Record.h
index d3e1b6ccbf5c96..3823d8dd4d91e9 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -23,6 +23,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -2043,7 +2044,7 @@ class Record {
 raw_ostream &operator<<(raw_ostream &OS, const Record &R);
 
 class RecordKeeper {
-  using RecordMap = std::map<std::string, std::unique_ptr<Record>, 
std::less<>>;
+  using RecordMap = StringMap<std::unique_ptr<Record>>;
   using GlobalMap = std::map<std::string, const Init *, std::less<>>;
 
 public:
@@ -2056,25 +2057,25 @@ class RecordKeeper {
   /// Get the main TableGen input file's name.
   StringRef getInputFilename() const { return InputFilename; }
 
-  /// Get the map of classes.
-  const RecordMap &getClasses() const { return Classes; }
+  /// Get all classes, sorted by name.
+  ArrayRef<const Record *> getClasses() const;
 
-  /// Get the map of records (defs).
-  const RecordMap &getDefs() const { return Defs; }
+  /// Get all records (defs), sorted by name.
+  ArrayRef<const Record *> getDefs() const;
 
   /// Get the map of global variables.
   const GlobalMap &getGlobals() const { return ExtraGlobals; }
 
   /// Get the class with the specified name.
   const Record *getClass(StringRef Name) const {
-    auto I = Classes.find(Name);
-    return I == Classes.end() ? nullptr : I->second.get();
+    auto It = Classes.find(Name);
+    return It == Classes.end() ? nullptr : It->second.get();
   }
 
   /// Get the concrete record with the specified name.
   const Record *getDef(StringRef Name) const {
-    auto I = Defs.find(Name);
-    return I == Defs.end() ? nullptr : I->second.get();
+    auto It = Defs.find(Name);
+    return It == Defs.end() ? nullptr : It->second.get();
   }
 
   /// Get the \p Init value of the specified global variable.
@@ -2090,14 +2091,13 @@ class RecordKeeper {
   }
 
   void addClass(std::unique_ptr<Record> R) {
-    bool Ins =
-        Classes.try_emplace(std::string(R->getName()), std::move(R)).second;
+    bool Ins = Classes.try_emplace(R->getName(), std::move(R)).second;
     (void)Ins;
     assert(Ins && "Class already exists");
   }
 
   void addDef(std::unique_ptr<Record> R) {
-    bool Ins = Defs.try_emplace(std::string(R->getName()), 
std::move(R)).second;
+    bool Ins = Defs.try_emplace(R->getName(), std::move(R)).second;
     (void)Ins;
     assert(Ins && "Record already exists");
     // Clear cache
@@ -2145,6 +2145,8 @@ class RecordKeeper {
 
   std::string InputFilename;
   RecordMap Classes, Defs;
+  // Classes and Defs sorted by name, built on demand.
+  mutable std::vector<const Record *> SortedClasses, SortedDefs;
   mutable std::map<std::string, std::vector<const Record *>> Cache;
   GlobalMap ExtraGlobals;
 

diff  --git a/llvm/lib/TableGen/DetailedRecordsBackend.cpp 
b/llvm/lib/TableGen/DetailedRecordsBackend.cpp
index b1152bf680c69a..fc79df45631fa7 100644
--- a/llvm/lib/TableGen/DetailedRecordsBackend.cpp
+++ b/llvm/lib/TableGen/DetailedRecordsBackend.cpp
@@ -81,10 +81,10 @@ void DetailedRecordsEmitter::printVariables(raw_ostream 
&OS) {
 
 // Print classes, including the template arguments, superclasses, and fields.
 void DetailedRecordsEmitter::printClasses(raw_ostream &OS) {
-  const auto &ClassList = Records.getClasses();
+  ArrayRef<const Record *> ClassList = Records.getClasses();
   printSectionHeading("Classes", ClassList.size(), OS);
 
-  for (const auto &[Name, Class] : ClassList) {
+  for (const Record *Class : ClassList) {
     OS << formatv("\n{0}  |{1}|\n", Class->getNameInitAsString(),
                   
SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front()));
     printTemplateArgs(*Class, OS);
@@ -95,10 +95,10 @@ void DetailedRecordsEmitter::printClasses(raw_ostream &OS) {
 
 // Print the records, including the defm sequences, supercasses, and fields.
 void DetailedRecordsEmitter::printRecords(raw_ostream &OS) {
-  const auto &RecordList = Records.getDefs();
+  ArrayRef<const Record *> RecordList = Records.getDefs();
   printSectionHeading("Records", RecordList.size(), OS);
 
-  for (const auto &[DefName, Rec] : RecordList) {
+  for (const Record *Rec : RecordList) {
     std::string Name = Rec->getNameInitAsString();
     OS << formatv("\n{0}  |{1}|\n", Name.empty() ? "\"\"" : Name,
                   SrcMgr.getFormattedLocationNoOffset(Rec->getLoc().front()));

diff  --git a/llvm/lib/TableGen/JSONBackend.cpp 
b/llvm/lib/TableGen/JSONBackend.cpp
index 80c1d7fd1dc4dc..d9f93a38963274 100644
--- a/llvm/lib/TableGen/JSONBackend.cpp
+++ b/llvm/lib/TableGen/JSONBackend.cpp
@@ -127,11 +127,11 @@ void JSONEmitter::run(raw_ostream &OS) {
   // over the classes, invoking std::map::operator[] to default-
   // construct the array for each one.
   std::map<std::string, json::Array> InstanceLists;
-  for (const auto &[ClassName, ClassRec] : Records.getClasses())
+  for (const Record *ClassRec : Records.getClasses())
     InstanceLists.emplace(ClassRec->getNameInitAsString(), json::Array());
 
   // Main iteration over the defs.
-  for (const auto &[DefName, Def] : Records.getDefs()) {
+  for (const Record *Def : Records.getDefs()) {
     const std::string Name = Def->getNameInitAsString();
 
     json::Object Obj;

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index f456222b5ea788..b9870b8510a974 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -3165,11 +3165,11 @@ LLVM_DUMP_METHOD void RecordKeeper::dump() const { 
errs() << *this; }
 
 raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) {
   OS << "------------- Classes -----------------\n";
-  for (const auto &[_, C] : RK.getClasses())
+  for (const Record *C : RK.getClasses())
     OS << "class " << *C;
 
   OS << "------------- Defs -----------------\n";
-  for (const auto &[_, D] : RK.getDefs())
+  for (const Record *D : RK.getDefs())
     OS << "def " << *D;
   return OS;
 }
@@ -3190,10 +3190,35 @@ RecordKeeper::getAllDerivedDefinitions(StringRef 
ClassName) const {
   return Iter->second;
 }
 
+// Return the records in Map sorted by name. Records are never removed, so
+// Sorted is out of date if its size 
diff ers.
+static ArrayRef<const Record *>
+getSortedRecords(const StringMap<std::unique_ptr<Record>> &Map,
+                 std::vector<const Record *> &Sorted) {
+  if (Sorted.size() != Map.size()) {
+    Sorted.clear();
+    Sorted.reserve(Map.size());
+    for (const auto &Entry : Map)
+      Sorted.push_back(Entry.second.get());
+    llvm::sort(Sorted, [](const Record *LHS, const Record *RHS) {
+      return LHS->getName() < RHS->getName();
+    });
+  }
+  return Sorted;
+}
+
+ArrayRef<const Record *> RecordKeeper::getClasses() const {
+  return getSortedRecords(Classes, SortedClasses);
+}
+
+ArrayRef<const Record *> RecordKeeper::getDefs() const {
+  return getSortedRecords(Defs, SortedDefs);
+}
+
 std::vector<const Record *>
 RecordKeeper::getAllDerivedDefinitions(ArrayRef<StringRef> ClassNames) const {
   SmallVector<const Record *, 2> ClassRecs;
-  std::vector<const Record *> Defs;
+  std::vector<const Record *> Derived;
 
   assert(ClassNames.size() > 0 && "At least one class must be passed.");
   for (StringRef ClassName : ClassNames) {
@@ -3203,14 +3228,15 @@ 
RecordKeeper::getAllDerivedDefinitions(ArrayRef<StringRef> ClassNames) const {
     ClassRecs.push_back(Class);
   }
 
-  for (const auto &OneDef : getDefs()) {
-    if (all_of(ClassRecs, [&OneDef](const Record *Class) {
-          return OneDef.second->isSubClassOf(Class);
-        }))
-      Defs.push_back(OneDef.second.get());
+  // The iteration order of Defs doesn't matter since the result is sorted.
+  for (const auto &OneDef : Defs) {
+    const Record *Def = OneDef.second.get();
+    if (all_of(ClassRecs,
+               [Def](const Record *Class) { return Def->isSubClassOf(Class); 
}))
+      Derived.push_back(Def);
   }
-  llvm::sort(Defs, LessRecord());
-  return Defs;
+  llvm::sort(Derived, LessRecord());
+  return Derived;
 }
 
 ArrayRef<const Record *>

diff  --git a/llvm/utils/TableGen/CTagsEmitter.cpp 
b/llvm/utils/TableGen/CTagsEmitter.cpp
index 413d8f5dbcff07..b29eac9cf92fe3 100644
--- a/llvm/utils/TableGen/CTagsEmitter.cpp
+++ b/llvm/utils/TableGen/CTagsEmitter.cpp
@@ -69,18 +69,18 @@ SMLoc CTagsEmitter::locate(const Record *R) {
 }
 
 void CTagsEmitter::run(raw_ostream &OS) {
-  const auto &Classes = Records.getClasses();
-  const auto &Defs = Records.getDefs();
+  ArrayRef<const Record *> Classes = Records.getClasses();
+  ArrayRef<const Record *> Defs = Records.getDefs();
   std::vector<Tag> Tags;
   // Collect tags.
   Tags.reserve(Classes.size() + Defs.size());
-  for (const auto &C : Classes) {
-    Tags.push_back(Tag(C.first, locate(C.second.get())));
-    for (SMLoc FwdLoc : C.second->getForwardDeclarationLocs())
-      Tags.push_back(Tag(C.first, FwdLoc));
+  for (const Record *C : Classes) {
+    Tags.push_back(Tag(C->getName(), locate(C)));
+    for (SMLoc FwdLoc : C->getForwardDeclarationLocs())
+      Tags.push_back(Tag(C->getName(), FwdLoc));
   }
-  for (const auto &D : Defs)
-    Tags.push_back(Tag(D.first, locate(D.second.get())));
+  for (const Record *D : Defs)
+    Tags.push_back(Tag(D->getName(), locate(D)));
   // Emit tags.
   llvm::sort(Tags);
   OS << "!_TAG_FILE_FORMAT\t1\t/original ctags format/\n";

diff  --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp 
b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index 65aa86e33fba32..c43471b32911de 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -1008,8 +1008,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
 
   // Translate legacy tables.
   const Record *SearchableTable = Records.getClass("SearchableTable");
-  for (auto &NameRec : Records.getClasses()) {
-    const Record *Class = NameRec.second.get();
+  for (const Record *Class : Records.getClasses()) {
     if (Class->getDirectSuperClasses().size() != 1 ||
         !Class->isSubClassOf(SearchableTable))
       continue;

diff  --git a/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp 
b/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp
index 64e86f2a62073b..807a3ef5926d64 100644
--- a/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp
+++ b/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp
@@ -82,7 +82,7 @@ static bool findUse(const Init *field, const Init 
*deprecatedInit,
 }
 
 // Returns if there is a use of `deprecatedInit` in `record`.
-static bool findUse(Record &record, const Init *deprecatedInit,
+static bool findUse(const Record &record, const Init *deprecatedInit,
                     llvm::DenseMap<const Init *, bool> &known) {
   return llvm::any_of(record.getValues(), [&](const RecordVal &val) {
     return findUse(val.getValue(), deprecatedInit, known);
@@ -94,21 +94,21 @@ static void warnOfDeprecatedUses(const RecordKeeper 
&records) {
   // finds all uses of deprecated def. Deprecated defs are not expected to be
   // either numerous or long lived.
   bool deprecatedDefsFounds = false;
-  for (auto &it : records.getDefs()) {
-    const RecordVal *r = it.second->getValue("odsDeprecated");
+  for (const Record *it : records.getDefs()) {
+    const RecordVal *r = it->getValue("odsDeprecated");
     if (!r || !r->getValue())
       continue;
 
     llvm::DenseMap<const Init *, bool> hasUse;
     if (auto *si = dyn_cast<StringInit>(r->getValue())) {
-      for (auto &jt : records.getDefs()) {
+      for (const Record *jt : records.getDefs()) {
         // Skip anonymous defs.
-        if (jt.second->isAnonymous())
+        if (jt->isAnonymous())
           continue;
 
-        if (findUse(*jt.second, it.second->getDefInit(), hasUse)) {
-          PrintWarning(jt.second->getLoc(),
-                       "Using deprecated def `" + it.first + "`");
+        if (findUse(*jt, it->getDefInit(), hasUse)) {
+          PrintWarning(jt->getLoc(),
+                       "Using deprecated def `" + it->getName() + "`");
           PrintNote(si->getAsUnquotedString());
           deprecatedDefsFounds = true;
         }

diff  --git a/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp 
b/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp
index 8e67da90763d89..2dae2448fda306 100644
--- a/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp
+++ b/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp
@@ -282,11 +282,9 @@ void TableGenIndex::initialize(const RecordKeeper 
&records) {
     if (!isDef)
       sym->references.push_back(refLoc);
   };
-  auto classes =
-      llvm::make_pointee_range(llvm::make_second_range(records.getClasses()));
-  auto defs =
-      llvm::make_pointee_range(llvm::make_second_range(records.getDefs()));
-  for (const Record &def : llvm::concat<Record>(classes, defs)) {
+  auto classes = llvm::make_pointee_range(records.getClasses());
+  auto defs = llvm::make_pointee_range(records.getDefs());
+  for (const Record &def : llvm::concat<const Record>(classes, defs)) {
     auto *sym = getOrInsertDef(&def);
     insertRef(sym, sym->defLoc, /*isDef=*/true);
 

diff  --git a/mlir/tools/mlir-tblgen/OpGenHelpers.cpp 
b/mlir/tools/mlir-tblgen/OpGenHelpers.cpp
index 44dbacf19fffd4..afc8272bc2a630 100644
--- a/mlir/tools/mlir-tblgen/OpGenHelpers.cpp
+++ b/mlir/tools/mlir-tblgen/OpGenHelpers.cpp
@@ -52,18 +52,16 @@ mlir::tblgen::getRequestedOpDefinitions(const RecordKeeper 
&records) {
 
   Regex includeRegex(opIncFilter), excludeRegex(opExcFilter);
   std::vector<const Record *> defs;
-  for (const auto &def : records.getDefs()) {
-    if (!def.second->isSubClassOf(classDef))
+  for (const Record *def : records.getDefs()) {
+    if (!def->isSubClassOf(classDef))
       continue;
     // Include if no include filter or include filter matches.
-    if (!opIncFilter.empty() &&
-        !includeRegex.match(getOperationName(*def.second)))
+    if (!opIncFilter.empty() && !includeRegex.match(getOperationName(*def)))
       continue;
     // Unless there is an exclude filter and it matches.
-    if (!opExcFilter.empty() &&
-        excludeRegex.match(getOperationName(*def.second)))
+    if (!opExcFilter.empty() && excludeRegex.match(getOperationName(*def)))
       continue;
-    defs.push_back(def.second.get());
+    defs.push_back(def);
   }
 
   return defs;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to