[llvm] [SelectionDAG] Unique VT lists in a DenseSet instead of a FoldingSet (PR #219364)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 00:15:37 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/219364
>From 7a2855bd535acadb08934c1f47294fb37d0d1808 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 26 Aug 2026 23:26:01 -0700
Subject: [PATCH 1/2] [SelectionDAG] Unique VT lists in a DenseSet instead of a
FoldingSet
Every getVTList call serializes the list's raw bits into a
FoldingSetNodeID and hashes it with xxh3, and every SDVTListNode carries
an interned copy of that profile. The list itself is the key.
Key VTLists on the ArrayRef the returned SDVTList already points at, and
let the two-, three- and four-type overloads share the ArrayRef one.
Aided by Opus 5
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 51 ++++--------
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 77 +++----------------
2 files changed, 26 insertions(+), 102 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 5bda87a317d73..f8331143ece60 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -99,41 +99,6 @@ using SSAContext = GenericSSAContext<Function>;
template <typename T> class GenericUniformityInfo;
using UniformityInfo = GenericUniformityInfo<SSAContext>;
-class SDVTListNode : public FoldingSetNode {
- friend struct FoldingSetTrait<SDVTListNode>;
-
- /// A reference to an Interned FoldingSetNodeID for this node.
- /// The Allocator in SelectionDAG holds the data.
- /// SDVTList contains all types which are frequently accessed in SelectionDAG.
- /// The size of this list is not expected to be big so it won't introduce
- /// a memory penalty.
- FoldingSetNodeIDRef FastID;
- const EVT *VTs;
- unsigned int NumVTs;
-
-public:
- SDVTListNode(const FoldingSetNodeIDRef ID, const EVT *VT, unsigned int Num)
- : FastID(ID), VTs(VT), NumVTs(Num) {}
-
- SDVTList getSDVTList() {
- SDVTList result = {VTs, NumVTs};
- return result;
- }
-};
-
-/// Specialize FoldingSetTrait for SDVTListNode
-/// to avoid computing temp FoldingSetNodeID.
-template<> struct FoldingSetTrait<SDVTListNode> : DefaultFoldingSetTrait<SDVTListNode> {
- static void Profile(const SDVTListNode &X, FoldingSetNodeID& ID) {
- ID = X.FastID;
- }
-
- static bool Equals(const SDVTListNode &X, const FoldingSetNodeID &ID,
- unsigned IDHash, FoldingSetNodeID &TempID) {
- return ID == X.FastID;
- }
-};
-
template <> struct ilist_alloc_traits<SDNode> {
static void deleteNode(SDNode *) {
llvm_unreachable("ilist_traits<SDNode> shouldn't see a deleteNode call!");
@@ -247,7 +212,21 @@ class SelectionDAG {
std::set<EVT, EVT::compareRawBits> EVTs;
/// List of non-single value types.
- FoldingSet<SDVTListNode> VTListMap;
+ /// Uniquing of VT lists. Each key aliases the EVT array that the returned
+ /// SDVTList points at, allocated from \p Allocator.
+ struct VTListInfo {
+ static unsigned getHashValue(ArrayRef<EVT> VTs) {
+ unsigned H = VTs.size();
+ for (EVT VT : VTs)
+ H = detail::combineHashValue(
+ H, DenseMapInfo<intptr_t>::getHashValue(VT.getRawBits()));
+ return H;
+ }
+ static bool isEqual(ArrayRef<EVT> LHS, ArrayRef<EVT> RHS) {
+ return LHS == RHS;
+ }
+ };
+ DenseSet<ArrayRef<EVT>, VTListInfo> VTLists;
/// Pool allocation for misc. objects that are created once per SelectionDAG.
BumpPtrAllocator Allocator;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 7d7026a2a3e3b..07d7636e6cb3b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -12266,85 +12266,30 @@ SDVTList SelectionDAG::getVTList(EVT VT) {
}
SDVTList SelectionDAG::getVTList(EVT VT1, EVT VT2) {
- FoldingSetNodeID ID;
- ID.AddInteger(2U);
- ID.AddInteger(VT1.getRawBits());
- ID.AddInteger(VT2.getRawBits());
-
- void *IP = nullptr;
- SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP);
- if (!Result) {
- EVT *Array = Allocator.Allocate<EVT>(2);
- Array[0] = VT1;
- Array[1] = VT2;
- Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, 2);
- VTListMap.InsertNode(Result, IP);
- }
- return Result->getSDVTList();
+ EVT VTs[] = {VT1, VT2};
+ return getVTList(VTs);
}
SDVTList SelectionDAG::getVTList(EVT VT1, EVT VT2, EVT VT3) {
- FoldingSetNodeID ID;
- ID.AddInteger(3U);
- ID.AddInteger(VT1.getRawBits());
- ID.AddInteger(VT2.getRawBits());
- ID.AddInteger(VT3.getRawBits());
-
- void *IP = nullptr;
- SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP);
- if (!Result) {
- EVT *Array = Allocator.Allocate<EVT>(3);
- Array[0] = VT1;
- Array[1] = VT2;
- Array[2] = VT3;
- Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, 3);
- VTListMap.InsertNode(Result, IP);
- }
- return Result->getSDVTList();
+ EVT VTs[] = {VT1, VT2, VT3};
+ return getVTList(VTs);
}
SDVTList SelectionDAG::getVTList(EVT VT1, EVT VT2, EVT VT3, EVT VT4) {
- FoldingSetNodeID ID;
- ID.AddInteger(4U);
- ID.AddInteger(VT1.getRawBits());
- ID.AddInteger(VT2.getRawBits());
- ID.AddInteger(VT3.getRawBits());
- ID.AddInteger(VT4.getRawBits());
-
- void *IP = nullptr;
- SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP);
- if (!Result) {
- EVT *Array = Allocator.Allocate<EVT>(4);
- Array[0] = VT1;
- Array[1] = VT2;
- Array[2] = VT3;
- Array[3] = VT4;
- Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, 4);
- VTListMap.InsertNode(Result, IP);
- }
- return Result->getSDVTList();
+ EVT VTs[] = {VT1, VT2, VT3, VT4};
+ return getVTList(VTs);
}
SDVTList SelectionDAG::getVTList(ArrayRef<EVT> VTs) {
- unsigned NumVTs = VTs.size();
- FoldingSetNodeID ID;
- ID.AddInteger(NumVTs);
- for (unsigned index = 0; index < NumVTs; index++) {
- ID.AddInteger(VTs[index].getRawBits());
- }
-
- void *IP = nullptr;
- SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP);
- if (!Result) {
- EVT *Array = Allocator.Allocate<EVT>(NumVTs);
+ auto It = VTLists.find(VTs);
+ if (It == VTLists.end()) {
+ EVT *Array = Allocator.Allocate<EVT>(VTs.size());
llvm::copy(VTs, Array);
- Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, NumVTs);
- VTListMap.InsertNode(Result, IP);
+ It = VTLists.insert(ArrayRef(Array, VTs.size())).first;
}
- return Result->getSDVTList();
+ return makeVTList(It->data(), It->size());
}
-
/// UpdateNodeOperands - *Mutate* the specified node in-place to have the
/// specified operands. If the resultant node already exists in the DAG,
/// this does not modify the specified node, instead it returns the node that
>From 06a06a3c98f8e532624945110886b3a442fd6f8d Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 28 Aug 2026 00:15:27 -0700
Subject: [PATCH 2/2] Update llvm/include/llvm/CodeGen/SelectionDAG.h
Co-authored-by: Kazu Hirata <kazu at google.com>
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index f8331143ece60..c0649b6c75c7c 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -211,7 +211,6 @@ class SelectionDAG {
/// Extended EVTs used for single value VTLists.
std::set<EVT, EVT::compareRawBits> EVTs;
- /// List of non-single value types.
/// Uniquing of VT lists. Each key aliases the EVT array that the returned
/// SDVTList points at, allocated from \p Allocator.
struct VTListInfo {
More information about the llvm-commits
mailing list