[llvm] [NFCI[TableGen] Minor improvements to `Intrinsic::getAttributes` (PR #152761)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 8 13:26:18 PDT 2025


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

>From 4ac6a9321a3eda64e6c0b88851ce2cd5dde44c7e Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Fri, 8 Aug 2025 07:49:29 -0700
Subject: [PATCH] [NFCI[TableGen] Minor improvements to
 `Intrinsic::getAttributes`

---
 .../utils/TableGen/Basic/IntrinsicEmitter.cpp | 108 +++++++++---------
 1 file changed, 51 insertions(+), 57 deletions(-)

diff --git a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp
index 293e64e97cc33..04707084a4166 100644
--- a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp
@@ -455,15 +455,9 @@ struct FnAttributeComparator {
 
 struct AttributeComparator {
   bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
-    // Order all intrinsics with no functiona attributes before all intrinsics
-    // with function attributes.
-    bool HasFnAttrLHS = hasFnAttributes(*L);
-    bool HasFnAttrRHS = hasFnAttributes(*R);
-
-    // Order by argument attributes if function `hasFnAttributes` is equal.
-    // This is reliable because each side is already sorted internally.
-    return std::tie(HasFnAttrLHS, L->ArgumentAttributes) <
-           std::tie(HasFnAttrRHS, R->ArgumentAttributes);
+    // This comparator is used to unique just the argument attributes of an
+    // intrinsic without considering any function attributes.
+    return L->ArgumentAttributes < R->ArgumentAttributes;
   }
 };
 } // End anonymous namespace
@@ -659,7 +653,7 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
   //
   //   getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo));
   //
-  // Create a table that records, for each argument attributes, the set of
+  // Create a table that records, for each argument attributes, the list of
   // <ArgNo, ArgAttrID> pairs that are needed to construct its argument
   // attributes. These tables for all intrinsics will be concatenated into one
   // large table and then for each intrinsic, we remember the Staring index and
@@ -667,79 +661,77 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
   // non-empty attributes), so that we can build the attribute list for an
   // intrinsic without using a switch-case.
 
-  // Find the max number of attributes to create the local array and create
-  // a concatenated list of <ArgNo, AttrID> pairs.
-  struct ArgNoAttrIDPair {
-    uint16_t ArgNo, ArgAttrID;
-    ArgNoAttrIDPair(uint16_t ArgNo, uint16_t ArgAttrID)
-        : ArgNo(ArgNo), ArgAttrID(ArgAttrID) {}
-  };
+  using ArgNoAttrIDPair = std::pair<uint16_t, uint16_t>;
 
-  // For each unique ID in UniqAttributes, reacord the starting index in the
-  // flattened ArgNoAttrIDPair table, and the number of non-empty arg
-  // attributes.
-  struct ArgAttributesInfo {
-    uint16_t StartIndex;
-    uint16_t NumAttrs;
-    ArgAttributesInfo(uint16_t StartIndex, uint16_t NumAttrs)
-        : StartIndex(StartIndex), NumAttrs(NumAttrs) {}
-  };
-  SmallVector<ArgNoAttrIDPair> ArgAttrIdTable;
-  SmallVector<ArgAttributesInfo> ArgAttributesInfoTable(UniqAttributes.size(),
-                                                        {0, 0});
+  // Emit the table of concatenated <ArgNo, AttrId> using SequenceToOffsetTable
+  // so that entries can be reused if possible. Individual sequences in this
+  // table do not have any terminator.
+  using ArgAttrIDSubTable = SmallVector<ArgNoAttrIDPair>;
+  SequenceToOffsetTable<ArgAttrIDSubTable> ArgAttrIdSequenceTable(std::nullopt);
+  SmallVector<ArgAttrIDSubTable> ArgAttrIdSubTables(
+      UniqAttributes.size()); // Indexed by UniqueID.
 
+  // Find the max number of attributes to create the local array.
   unsigned MaxNumAttrs = 0;
   for (const auto [IntPtr, UniqueID] : UniqAttributes) {
     const CodeGenIntrinsic &Int = *IntPtr;
-    unsigned NumAttrs = 0;
-    unsigned StartIndex = ArgAttrIdTable.size();
+    ArgAttrIDSubTable SubTable;
 
     for (const auto &[ArgNo, Attrs] : enumerate(Int.ArgumentAttributes)) {
       if (Attrs.empty())
         continue;
 
       uint16_t ArgAttrID = UniqArgAttributes.find(Attrs)->second;
-      ArgAttrIdTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
-      ++NumAttrs;
+      SubTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
     }
-
-    // Record the start index and size of the list for this unique ID.
-    if (NumAttrs)
-      ArgAttributesInfoTable[UniqueID] =
-          ArgAttributesInfo(StartIndex, NumAttrs);
-
-    NumAttrs += hasFnAttributes(Int);
+    ArgAttrIdSubTables[UniqueID] = SubTable;
+    if (!SubTable.empty())
+      ArgAttrIdSequenceTable.add(SubTable);
+    unsigned NumAttrs = SubTable.size() + hasFnAttributes(Int);
     MaxNumAttrs = std::max(MaxNumAttrs, NumAttrs);
   }
 
-  if (ArgAttrIdTable.size() >= std::numeric_limits<uint16_t>::max())
+  ArgAttrIdSequenceTable.layout();
+
+  if (ArgAttrIdSequenceTable.size() >= std::numeric_limits<uint16_t>::max())
     PrintFatalError("Size of ArgAttrIdTable exceeds supported limit");
 
-  // Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttrIdTableIndex
-  OS << R"(
-namespace {
-struct ArgNoAttrIDPair {
+  // Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttributesInfoTable.
+  OS << formatv(R"(
+namespace {{
+struct ArgNoAttrIDPair {{
   uint16_t ArgNo, ArgAttrID;
 };
 } // namespace
 
-static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {
-)";
-  for (const auto &[ArgNo, ArgAttrID] : ArgAttrIdTable)
-    OS << formatv("  {{{}, {}},\n", ArgNo, ArgAttrID);
-  OS << R"(}; // ArgAttrIdTable
+// Number of entries: {}
+static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {{
+)",
+                ArgAttrIdSequenceTable.size());
 
-namespace {
-struct ArgAttributesInfo {
+  ArgAttrIdSequenceTable.emit(OS, [](raw_ostream &OS, ArgNoAttrIDPair Elem) {
+    OS << formatv("{{{}, {}}", Elem.first, Elem.second);
+  });
+
+  OS << formatv(R"(}; // ArgAttrIdTable
+
+namespace {{
+struct ArgAttributesInfo {{
   uint16_t StartIndex;
   uint16_t NumAttrs;
 };
 } // namespace
- 
-static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {
-)";
-  for (const auto &[StartIndex, NumAttrs] : ArgAttributesInfoTable)
+
+// Number of entries: {}
+static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {{
+)",
+                ArgAttrIdSubTables.size());
+
+  for (const auto &SubTable : ArgAttrIdSubTables) {
+    unsigned NumAttrs = SubTable.size();
+    unsigned StartIndex = NumAttrs ? ArgAttrIdSequenceTable.get(SubTable) : 0;
     OS << formatv("  {{{}, {}},\n", StartIndex, NumAttrs);
+  }
   OS << "}; // ArgAttributesInfoTable\n";
 
   // Now emit the Intrinsic::getAttributes function. This will first map
@@ -756,7 +748,9 @@ AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
   uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
   uint8_t FnAttrID = PackedID >> 8;
   uint8_t ArgAttrID = PackedID & 0xFF;
-  std::pair<unsigned, AttributeSet> AS[{}];
+  using PairTy = std::pair<unsigned, AttributeSet>;
+  alignas(PairTy) char ASStorage[sizeof(PairTy) * {}];
+  PairTy *AS = reinterpret_cast<PairTy *>(ASStorage);
 
   // Construct an ArrayRef for easier range checking.
   ArrayRef<ArgAttributesInfo> ArgAttributesInfoTableAR(ArgAttributesInfoTable);



More information about the llvm-commits mailing list