[Mlir-commits] [mlir] 80017ba - TableGen: Store classes and defs in a StringMap (#231573)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Oct 15 01:32:47 PDT 2026
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 <noreply at anthropic.com>
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;
More information about the Mlir-commits
mailing list