[llvm] [llvm][GlobalOpt] Preserve COMDATs for Dead GVs (PR #222720)
Miguel A. Arroyo via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 22:14:52 PDT 2026
https://github.com/mayanez updated https://github.com/llvm/llvm-project/pull/222720
>From 4afacaf4a3afc72107087b742e40948913594518 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <Miguel.Arroyo at rockstargames.com>
Date: Wed, 2 Sep 2026 14:22:54 -0700
Subject: [PATCH 1/3] [llvm][GlobalOpt] Preserve COMDATs for Dead GVs
---
llvm/lib/Transforms/IPO/GlobalOpt.cpp | 8 +++-
.../GlobalOpt/deadfunction-comdat.ll | 38 +++++++++++++++++++
2 files changed, 44 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Transforms/GlobalOpt/deadfunction-comdat.ll
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index 9892c6796517c..767d53cf25942 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1331,9 +1331,13 @@ deleteIfDead(GlobalValue &GV,
if (!GV.isDiscardableIfUnused() && !GV.isDeclaration())
return false;
- if (const Comdat *C = GV.getComdat())
- if (!GV.hasLocalLinkage() && NotDiscardableComdats.count(C))
+ if (auto *C = GV.getComdat()) {
+ auto IsComdatLeaderWithUses =
+ C->getName() == GV.getName() && C->getUsers().size() > 1;
+ if (IsComdatLeaderWithUses ||
+ (!GV.hasInternalLinkage() && NotDiscardableComdats.count(C)))
return false;
+ }
bool Dead;
if (auto *F = dyn_cast<Function>(&GV))
diff --git a/llvm/test/Transforms/GlobalOpt/deadfunction-comdat.ll b/llvm/test/Transforms/GlobalOpt/deadfunction-comdat.ll
new file mode 100644
index 0000000000000..feac9e2e2f501
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/deadfunction-comdat.ll
@@ -0,0 +1,38 @@
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$foo = comdat any
+$trulydead = comdat any
+
+; CHECK: @foo
+define internal void @foo() comdat {
+ ret void
+}
+
+; CHECK: @bar
+define internal void @bar() #0 comdat($foo) {
+ ret void
+}
+
+define void @zed() {
+ call void @bar()
+ ret void
+}
+
+; CHECK-NOT: @trulydead
+define internal void @trulydead() comdat {
+ ret void
+}
+
+; CHECK-NOT: @trulydead2
+define internal void @trulydead2() comdat($trulydead) {
+ ret void
+}
+
+define i32 @main() {
+ ret i32 0
+}
+
+attributes #0 = { noinline }
\ No newline at end of file
>From def519e8e144687986e1686505175937bd21e158 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <Miguel.Arroyo at rockstargames.com>
Date: Thu, 10 Sep 2026 17:42:16 -0700
Subject: [PATCH 2/3] Handle COMDAT Alias
---
llvm/lib/Transforms/IPO/GlobalOpt.cpp | 3 ++-
.../Transforms/GlobalOpt/deadglobal-comdat.ll | 22 +++++++++++++++++++
2 files changed, 24 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/Transforms/GlobalOpt/deadglobal-comdat.ll
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index 767d53cf25942..6f8d60ab8e251 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1333,7 +1333,8 @@ deleteIfDead(GlobalValue &GV,
if (auto *C = GV.getComdat()) {
auto IsComdatLeaderWithUses =
- C->getName() == GV.getName() && C->getUsers().size() > 1;
+ GV.getParent()->getComdatSymbolTable().contains(GV.getName()) &&
+ C->getUsers().size() > 1;
if (IsComdatLeaderWithUses ||
(!GV.hasInternalLinkage() && NotDiscardableComdats.count(C)))
return false;
diff --git a/llvm/test/Transforms/GlobalOpt/deadglobal-comdat.ll b/llvm/test/Transforms/GlobalOpt/deadglobal-comdat.ll
new file mode 100644
index 0000000000000..e1f99975a057e
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/deadglobal-comdat.ll
@@ -0,0 +1,22 @@
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; CHECK: $x
+$x = comdat any
+
+; CHECK-NOT: $trulydeadg
+$trulydeadg = comdat any
+
+; CHECK: @g
+ at g = internal global i32 0, comdat($x)
+; CHECK: @g2
+ at g2 = global i32 0, comdat($x)
+; CHECK: @x
+ at x = internal alias i32, ptr @g
+
+; CHECK-NOT: @trulydeadg
+ at trulydeadg = internal alias i32, ptr @deadg
+; CHECK-NOT: @deadg
+ at deadg = internal global i32 0, comdat($trulydeadg)
\ No newline at end of file
>From d0b8c40d85396035093fed817751754dfd9e7643 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <Miguel.Arroyo at rockstargames.com>
Date: Tue, 29 Sep 2026 22:12:53 -0700
Subject: [PATCH 3/3] Add Global Value isComdatLeader()
---
llvm/include/llvm/IR/GlobalValue.h | 1 +
llvm/lib/IR/Globals.cpp | 6 ++++++
llvm/lib/Transforms/IPO/GlobalOpt.cpp | 3 +--
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h
index 79e45ef51367c..177f7d1ce6a94 100644
--- a/llvm/include/llvm/IR/GlobalValue.h
+++ b/llvm/include/llvm/IR/GlobalValue.h
@@ -250,6 +250,7 @@ class GlobalValue : public Constant {
return const_cast<Comdat *>(
static_cast<const GlobalValue *>(this)->getComdat());
}
+ bool isComdatLeader() const;
VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); }
bool hasDefaultVisibility() const { return Visibility == DefaultVisibility; }
diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp
index 3428f662e9120..c8ccff9f90080 100644
--- a/llvm/lib/IR/Globals.cpp
+++ b/llvm/lib/IR/Globals.cpp
@@ -284,6 +284,12 @@ const Comdat *GlobalValue::getComdat() const {
return cast<GlobalObject>(this)->getComdat();
}
+bool GlobalValue::isComdatLeader() const {
+ if (hasComdat())
+ return getParent()->getComdatSymbolTable().contains(getName());
+ return false;
+}
+
void GlobalObject::setComdat(Comdat *C) {
if (ObjComdat)
ObjComdat->removeUser(this);
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index e458a67e84cf5..0fe6655275462 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1324,8 +1324,7 @@ deleteIfDead(GlobalValue &GV,
if (auto *C = GV.getComdat()) {
auto IsComdatLeaderWithUses =
- GV.getParent()->getComdatSymbolTable().contains(GV.getName()) &&
- C->getUsers().size() > 1;
+ GV.isComdatLeader() && C->getUsers().size() > 1;
if (IsComdatLeaderWithUses ||
(!GV.hasInternalLinkage() && NotDiscardableComdats.count(C)))
return false;
More information about the llvm-commits
mailing list