[llvm] [SelectionDAG] Avoid redundant node visits in EnforceNodeIdInvariant (PR #164834)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 23 08:25:08 PDT 2025
https://github.com/mohammadamin382 created https://github.com/llvm/llvm-project/pull/164834
EnforceNodeIdInvariant currently processes nodes with multiple predecessors
multiple times in reconvergent DAGs due to lacking a visited set.
This inefficient O(V*E) complexity is optimized to O(V+E) by introducing
a SmallPtrSet to track visited nodes. This ensures each node is processed
only once, improving compile time for highly connected graphs.
>From a406b292967a0a23ab4fe0caab84446ff8b0d6c6 Mon Sep 17 00:00:00 2001
From: Mohammad <moahmmad.hosseinii at gmail.com>
Date: Thu, 23 Oct 2025 18:35:53 +0330
Subject: [PATCH 1/3] [SelectionDAG] Avoid redundant node visits in
EnforceNodeIdInvariant
Add SmallPtrSet to track visited nodes ensuring each node is checked
exactly once reducing complexity from O(V*E) to O(V+E)
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 6c11c5b815b6b..8fb4586333840 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -1236,13 +1236,15 @@ class ISelUpdater : public SelectionDAG::DAGUpdateListener {
// functions.
void SelectionDAGISel::EnforceNodeIdInvariant(SDNode *Node) {
SmallVector<SDNode *, 4> Nodes;
+ SmallPtrSet<SDNode *, 16> Visited;
Nodes.push_back(Node);
+ Visited.insert(Node);
while (!Nodes.empty()) {
SDNode *N = Nodes.pop_back_val();
for (auto *U : N->users()) {
auto UId = U->getNodeId();
- if (UId > 0) {
+ if (UId > 0 && Visited.insert(U).second) {
InvalidateNodeId(U);
Nodes.push_back(U);
}
>From 980a7a4c1ba7fb37835123ef06f31be0e6346a73 Mon Sep 17 00:00:00 2001
From: Mohammad <moahmmad.hosseinii at gmail.com>
Date: Thu, 23 Oct 2025 18:41:32 +0330
Subject: [PATCH 2/3] Add tests for EnforceNodeIdInvariant in AArch64
---
.../AArch64/test-enforce-nodeid-invariant.ll | 119 ++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/test-enforce-nodeid-invariant.ll
diff --git a/llvm/test/CodeGen/AArch64/test-enforce-nodeid-invariant.ll b/llvm/test/CodeGen/AArch64/test-enforce-nodeid-invariant.ll
new file mode 100644
index 0000000000000..9b70dd9dcd0a7
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/test-enforce-nodeid-invariant.ll
@@ -0,0 +1,119 @@
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s
+
+; Test that EnforceNodeIdInvariant correctly handles nodes
+; users and prevents redundant invalidation visits. This test creates a
+; DAG structure with high fan-in where multiple nodes share common users.
+; should visit each node exactly once.
+
+define i32 @test_diamond_dag(i32 %a, i32 %b) {
+; CHECK-LABEL: test_diamond_dag:
+entry:
+ %add1 = add i32 %a, %b
+ %add2 = add i32 %a, %b
+ %mul1 = mul i32 %add1, %add2
+ %mul2 = mul i32 %add1, %add2
+ %result = add i32 %mul1, %mul2
+ ret i32 %result
+}
+
+define i64 @test_deep_dag(i64 %x) {
+; CHECK-LABEL: test_deep_dag:
+entry:
+ %a = add i64 %x, 1
+ %b = add i64 %x, 2
+ %c = add i64 %a, %b
+ %d = add i64 %a, %b
+ %e = mul i64 %c, %d
+ %f = mul i64 %c, %d
+ %g = add i64 %e, %f
+ ret i64 %g
+}
+
+define i32 @test_wide_dag(i32 %v) {
+; CHECK-LABEL: test_wide_dag:
+entry:
+ %a = add i32 %v, 1
+ %b = add i32 %v, 2
+ %c = add i32 %v, 3
+ %d = add i32 %v, 4
+ %ab = add i32 %a, %b
+ %cd = add i32 %c, %d
+ %ac = add i32 %a, %c
+ %bd = add i32 %b, %d
+ %t1 = mul i32 %ab, %cd
+ %t2 = mul i32 %ac, %bd
+ %result = add i32 %t1, %t2
+ ret i32 %result
+}
+
+define <4 x i32> @test_vector_dag(<4 x i32> %vec1, <4 x i32> %vec2) {
+; CHECK-LABEL: test_vector_dag:
+entry:
+ %add1 = add <4 x i32> %vec1, %vec2
+ %add2 = add <4 x i32> %vec1, %vec2
+ %mul1 = mul <4 x i32> %add1, %add2
+ %mul2 = mul <4 x i32> %add1, %add2
+ %result = add <4 x i32> %mul1, %mul2
+ ret <4 x i32> %result
+}
+
+define i32 @test_chain_with_shared_users(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: test_chain_with_shared_users:
+entry:
+ %a = add i32 %x, %y
+ %b = add i32 %y, %z
+ %c = mul i32 %a, %b
+ %d = mul i32 %a, %b
+ %e = add i32 %c, %d
+ %f = sub i32 %c, %d
+ %g = mul i32 %e, %f
+ ret i32 %g
+}
+
+define i64 @test_complex_sharing(i64 %p1, i64 %p2, i64 %p3) {
+; CHECK-LABEL: test_complex_sharing:
+entry:
+ %n1 = add i64 %p1, %p2
+ %n2 = add i64 %p2, %p3
+ %n3 = add i64 %p1, %p3
+ %u1 = mul i64 %n1, %n2
+ %u2 = mul i64 %n1, %n3
+ %u3 = mul i64 %n2, %n3
+ %s1 = add i64 %u1, %u2
+ %s2 = add i64 %u2, %u3
+ %s3 = add i64 %u1, %u3
+ %f1 = mul i64 %s1, %s2
+ %f2 = mul i64 %s2, %s3
+ %result = add i64 %f1, %f2
+ ret i64 %result
+}
+
+define i32 @test_multiple_paths_to_same_user(i32 %input) {
+; CHECK-LABEL: test_multiple_paths_to_same_user:
+entry:
+ %a = add i32 %input, 1
+ %b = add i32 %input, 2
+ %c = add i32 %input, 3
+ %ab = mul i32 %a, %b
+ %bc = mul i32 %b, %c
+ %ac = mul i32 %a, %c
+ %shared = add i32 %ab, %bc
+ %shared2 = add i32 %ac, %shared
+ ret i32 %shared2
+}
+
+define i64 @test_reconvergent_paths(i64 %val) {
+; CHECK-LABEL: test_reconvergent_paths:
+entry:
+ %l1a = add i64 %val, 10
+ %l1b = add i64 %val, 20
+ %l2a = mul i64 %l1a, 2
+ %l2b = mul i64 %l1b, 3
+ %l2c = mul i64 %l1a, 4
+ %l2d = mul i64 %l1b, 5
+ %l3a = add i64 %l2a, %l2b
+ %l3b = add i64 %l2c, %l2d
+ %merge = mul i64 %l3a, %l3b
+ ret i64 %merge
+}
>From 96cb32c269125721604d84fc1983a5b8c2154609 Mon Sep 17 00:00:00 2001
From: Mohammad <moahmmad.hosseinii at gmail.com>
Date: Thu, 23 Oct 2025 18:42:12 +0330
Subject: [PATCH 3/3] Add tests for EnforceNodeIdInvariant in DAGs
---
.../X86/test-enforce-nodeid-invariant.ll | 119 ++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 llvm/test/CodeGen/X86/test-enforce-nodeid-invariant.ll
diff --git a/llvm/test/CodeGen/X86/test-enforce-nodeid-invariant.ll b/llvm/test/CodeGen/X86/test-enforce-nodeid-invariant.ll
new file mode 100644
index 0000000000000..9b70dd9dcd0a7
--- /dev/null
+++ b/llvm/test/CodeGen/X86/test-enforce-nodeid-invariant.ll
@@ -0,0 +1,119 @@
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s
+
+; Test that EnforceNodeIdInvariant correctly handles nodes
+; users and prevents redundant invalidation visits. This test creates a
+; DAG structure with high fan-in where multiple nodes share common users.
+; should visit each node exactly once.
+
+define i32 @test_diamond_dag(i32 %a, i32 %b) {
+; CHECK-LABEL: test_diamond_dag:
+entry:
+ %add1 = add i32 %a, %b
+ %add2 = add i32 %a, %b
+ %mul1 = mul i32 %add1, %add2
+ %mul2 = mul i32 %add1, %add2
+ %result = add i32 %mul1, %mul2
+ ret i32 %result
+}
+
+define i64 @test_deep_dag(i64 %x) {
+; CHECK-LABEL: test_deep_dag:
+entry:
+ %a = add i64 %x, 1
+ %b = add i64 %x, 2
+ %c = add i64 %a, %b
+ %d = add i64 %a, %b
+ %e = mul i64 %c, %d
+ %f = mul i64 %c, %d
+ %g = add i64 %e, %f
+ ret i64 %g
+}
+
+define i32 @test_wide_dag(i32 %v) {
+; CHECK-LABEL: test_wide_dag:
+entry:
+ %a = add i32 %v, 1
+ %b = add i32 %v, 2
+ %c = add i32 %v, 3
+ %d = add i32 %v, 4
+ %ab = add i32 %a, %b
+ %cd = add i32 %c, %d
+ %ac = add i32 %a, %c
+ %bd = add i32 %b, %d
+ %t1 = mul i32 %ab, %cd
+ %t2 = mul i32 %ac, %bd
+ %result = add i32 %t1, %t2
+ ret i32 %result
+}
+
+define <4 x i32> @test_vector_dag(<4 x i32> %vec1, <4 x i32> %vec2) {
+; CHECK-LABEL: test_vector_dag:
+entry:
+ %add1 = add <4 x i32> %vec1, %vec2
+ %add2 = add <4 x i32> %vec1, %vec2
+ %mul1 = mul <4 x i32> %add1, %add2
+ %mul2 = mul <4 x i32> %add1, %add2
+ %result = add <4 x i32> %mul1, %mul2
+ ret <4 x i32> %result
+}
+
+define i32 @test_chain_with_shared_users(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: test_chain_with_shared_users:
+entry:
+ %a = add i32 %x, %y
+ %b = add i32 %y, %z
+ %c = mul i32 %a, %b
+ %d = mul i32 %a, %b
+ %e = add i32 %c, %d
+ %f = sub i32 %c, %d
+ %g = mul i32 %e, %f
+ ret i32 %g
+}
+
+define i64 @test_complex_sharing(i64 %p1, i64 %p2, i64 %p3) {
+; CHECK-LABEL: test_complex_sharing:
+entry:
+ %n1 = add i64 %p1, %p2
+ %n2 = add i64 %p2, %p3
+ %n3 = add i64 %p1, %p3
+ %u1 = mul i64 %n1, %n2
+ %u2 = mul i64 %n1, %n3
+ %u3 = mul i64 %n2, %n3
+ %s1 = add i64 %u1, %u2
+ %s2 = add i64 %u2, %u3
+ %s3 = add i64 %u1, %u3
+ %f1 = mul i64 %s1, %s2
+ %f2 = mul i64 %s2, %s3
+ %result = add i64 %f1, %f2
+ ret i64 %result
+}
+
+define i32 @test_multiple_paths_to_same_user(i32 %input) {
+; CHECK-LABEL: test_multiple_paths_to_same_user:
+entry:
+ %a = add i32 %input, 1
+ %b = add i32 %input, 2
+ %c = add i32 %input, 3
+ %ab = mul i32 %a, %b
+ %bc = mul i32 %b, %c
+ %ac = mul i32 %a, %c
+ %shared = add i32 %ab, %bc
+ %shared2 = add i32 %ac, %shared
+ ret i32 %shared2
+}
+
+define i64 @test_reconvergent_paths(i64 %val) {
+; CHECK-LABEL: test_reconvergent_paths:
+entry:
+ %l1a = add i64 %val, 10
+ %l1b = add i64 %val, 20
+ %l2a = mul i64 %l1a, 2
+ %l2b = mul i64 %l1b, 3
+ %l2c = mul i64 %l1a, 4
+ %l2d = mul i64 %l1b, 5
+ %l3a = add i64 %l2a, %l2b
+ %l3b = add i64 %l2c, %l2d
+ %merge = mul i64 %l3a, %l3b
+ ret i64 %merge
+}
More information about the llvm-commits
mailing list