[llvm] [NFC][TableGen] Remove small heap allocations in SearchableTableEmitter (PR #147845)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 9 15:46:38 PDT 2025


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/147845

>From 10980e6092d46d689bf8b966ace04d426abbe66d Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 9 Jul 2025 07:24:53 -0700
Subject: [PATCH] [NFC][TableGen] Remove small heap allocations in
 `SearchableTableEmitter`

Change `GenericEnum` to not heap allocate its entries. Instead stash
them directly in the `Entries` vector. Change `EntryMap` to hold an
index as opposed to a pointer to the entry (the original reason why
they were unique_ptr).
---
 .../utils/TableGen/SearchableTableEmitter.cpp | 71 +++++++++++--------
 1 file changed, 42 insertions(+), 29 deletions(-)

diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index 38fc1ee5e4020..89015c66283a0 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -44,13 +44,27 @@ static int64_t getInt(const Record *R, StringRef Field) {
 
 namespace {
 struct GenericEnum {
-  using Entry = std::pair<StringRef, int64_t>;
+  struct Entry {
+    StringRef Name;
+    int64_t Value;
+    const Record *Def;
+    Entry(StringRef N, int64_t V, const Record *D)
+        : Name(N), Value(V), Def(D) {}
+  };
 
   std::string Name;
   const Record *Class = nullptr;
   std::string PreprocessorGuard;
-  std::vector<std::unique_ptr<Entry>> Entries;
-  DenseMap<const Record *, Entry *> EntryMap;
+  std::vector<Entry> Entries;
+  // Map from a Record to an index into the `Entries` vector.
+  DenseMap<const Record *, uint32_t> EntryMap;
+
+  const Entry *getEntry(const Record *Def) const {
+    auto II = EntryMap.find(Def);
+    if (II == EntryMap.end())
+      return nullptr;
+    return &Entries[II->second];
+  }
 };
 
 struct GenericField {
@@ -129,11 +143,12 @@ class SearchableTableEmitter {
     else if (Field.IsInstruction)
       return I->getAsString();
     else if (Field.Enum) {
-      auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
+      const GenericEnum::Entry *Entry =
+          Field.Enum->getEntry(cast<DefInit>(I)->getDef());
       if (!Entry)
         PrintFatalError(Loc,
                         Twine("Entry for field '") + Field.Name + "' is null");
-      return Entry->first.str();
+      return Entry->Name.str();
     }
     PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
                              "'; expected: bit, bits, string, or code");
@@ -221,7 +236,7 @@ int64_t SearchableTableEmitter::getNumericKey(const SearchIndex &Index,
   }
   if (Field.Enum) {
     const Record *EnumEntry = Rec->getValueAsDef(Field.Name);
-    return Field.Enum->EntryMap[EnumEntry]->second;
+    return Field.Enum->getEntry(EnumEntry)->Value;
   }
   assert(isa<BitsRecTy>(Field.RecType) && "unexpected field type");
 
@@ -272,8 +287,8 @@ bool SearchableTableEmitter::compareBy(const Record *LHS, const Record *RHS,
     } else if (Field.Enum) {
       auto LHSr = cast<DefInit>(LHSI)->getDef();
       auto RHSr = cast<DefInit>(RHSI)->getDef();
-      int64_t LHSv = Field.Enum->EntryMap[LHSr]->second;
-      int64_t RHSv = Field.Enum->EntryMap[RHSr]->second;
+      int64_t LHSv = Field.Enum->getEntry(LHSr)->Value;
+      int64_t RHSv = Field.Enum->getEntry(RHSr)->Value;
       if (LHSv < RHSv)
         return true;
       if (LHSv > RHSv)
@@ -308,8 +323,8 @@ void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
   emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS);
 
   OS << "enum " << Enum.Name << " {\n";
-  for (const auto &Entry : Enum.Entries)
-    OS << "  " << Entry->first << " = " << Entry->second << ",\n";
+  for (const auto &[Name, Value, _] : Enum.Entries)
+    OS << "  " << Name << " = " << Value << ",\n";
   OS << "};\n";
 
   OS << "#endif\n\n";
@@ -625,31 +640,29 @@ std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
 void SearchableTableEmitter::collectEnumEntries(
     GenericEnum &Enum, StringRef NameField, StringRef ValueField,
     ArrayRef<const Record *> Items) {
+  Enum.Entries.reserve(Items.size());
   for (const Record *EntryRec : Items) {
-    StringRef Name;
-    if (NameField.empty())
-      Name = EntryRec->getName();
-    else
-      Name = EntryRec->getValueAsString(NameField);
-
-    int64_t Value = 0;
-    if (!ValueField.empty())
-      Value = getInt(EntryRec, ValueField);
-
-    Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));
-    Enum.EntryMap.try_emplace(EntryRec, Enum.Entries.back().get());
+    StringRef Name = NameField.empty() ? EntryRec->getName()
+                                       : EntryRec->getValueAsString(NameField);
+    int64_t Value = ValueField.empty() ? 0 : getInt(EntryRec, ValueField);
+    Enum.Entries.emplace_back(Name, Value, EntryRec);
   }
 
+  // If no values are provided for enums, assign values in the order of sorted
+  // enum names.
   if (ValueField.empty()) {
-    llvm::stable_sort(Enum.Entries,
-                      [](const std::unique_ptr<GenericEnum::Entry> &LHS,
-                         const std::unique_ptr<GenericEnum::Entry> &RHS) {
-                        return LHS->first < RHS->first;
-                      });
+    llvm::stable_sort(Enum.Entries, [](const GenericEnum::Entry &LHS,
+                                       const GenericEnum::Entry &RHS) {
+      return LHS.Name < RHS.Name;
+    });
 
-    for (size_t i = 0; i < Enum.Entries.size(); ++i)
-      Enum.Entries[i]->second = i;
+    for (auto [Idx, Entry] : enumerate(Enum.Entries))
+      Entry.Value = Idx;
   }
+
+  // Populate the entry map after the `Entries` vector is finalized.
+  for (auto [Idx, Entry] : enumerate(Enum.Entries))
+    Enum.EntryMap.try_emplace(Entry.Def, Idx);
 }
 
 void SearchableTableEmitter::collectTableEntries(



More information about the llvm-commits mailing list