[llvm] [GlobalOpt]: Removes metadata when referenced global variable is deleted (PR #169221)

via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 23 07:56:21 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: None (kper)

<details>
<summary>Changes</summary>

When a global variable is deleted, metadata might still point to it. This caused a crash in the linked issue. 
The PR adds a fix where the module's global variables are iterated and the metadata is removed when the referenced global variable is deleted.  

Closes https://github.com/llvm/llvm-project/issues/165242

---
Full diff: https://github.com/llvm/llvm-project/pull/169221.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/IPO/GlobalOpt.cpp (+38-5) 
- (added) llvm/test/Transforms/GlobalOpt/dead_metadata.ll (+11) 


``````````diff
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index c3dede31540d6..d8b220d08d7e5 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1322,8 +1322,38 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
   return true;
 }
 
+// Iterate over all globals in the module and remove any metadata that
+// references to the given GV.
+static void removeMetadataReferencesToGlobal(Module &M, GlobalValue &GV) {
+  for (auto &MGV : M.globals()) {
+    SmallVector<std::pair<unsigned, llvm::MDNode *>, 4> MDs;
+    MGV.getAllMetadata(MDs);
+
+    for (auto &pair : MDs) {
+      auto Node = pair.second;
+
+      for (const llvm::MDOperand &Op : Node->operands()) {
+        llvm::Metadata *MD = Op.get();
+        if (!MD)
+          continue;
+
+        auto *VM = llvm::dyn_cast<llvm::ValueAsMetadata>(MD);
+        if (!VM)
+          continue;
+
+        auto *V = llvm::dyn_cast<GlobalValue>(VM->getValue());
+        if (!V)
+          continue;
+
+        if (V == &GV)
+          MGV.eraseMetadata(pair.first);
+      }
+    }
+  }
+}
+
 static bool
-deleteIfDead(GlobalValue &GV,
+deleteIfDead(Module &M, GlobalValue &GV,
              SmallPtrSetImpl<const Comdat *> &NotDiscardableComdats,
              function_ref<void(Function &)> DeleteFnCallback = nullptr) {
   GV.removeDeadConstantUsers();
@@ -1348,6 +1378,9 @@ deleteIfDead(GlobalValue &GV,
     if (DeleteFnCallback)
       DeleteFnCallback(*F);
   }
+
+  removeMetadataReferencesToGlobal(M, GV);
+
   ReplaceableMetadataImpl::SalvageDebugInfo(GV);
   GV.eraseFromParent();
   ++NumDeleted;
@@ -1950,7 +1983,7 @@ OptimizeFunctions(Module &M,
     if (!F.hasName() && !F.isDeclaration() && !F.hasLocalLinkage())
       F.setLinkage(GlobalValue::InternalLinkage);
 
-    if (deleteIfDead(F, NotDiscardableComdats, DeleteFnCallback)) {
+    if (deleteIfDead(M, F, NotDiscardableComdats, DeleteFnCallback)) {
       Changed = true;
       continue;
     }
@@ -2062,7 +2095,7 @@ OptimizeGlobalVars(Module &M,
           GV.setInitializer(New);
       }
 
-    if (deleteIfDead(GV, NotDiscardableComdats)) {
+    if (deleteIfDead(M, GV, NotDiscardableComdats)) {
       Changed = true;
       continue;
     }
@@ -2278,7 +2311,7 @@ OptimizeGlobalAliases(Module &M,
     if (!J.hasName() && !J.isDeclaration() && !J.hasLocalLinkage())
       J.setLinkage(GlobalValue::InternalLinkage);
 
-    if (deleteIfDead(J, NotDiscardableComdats)) {
+    if (deleteIfDead(M, J, NotDiscardableComdats)) {
       Changed = true;
       continue;
     }
@@ -2478,7 +2511,7 @@ DeleteDeadIFuncs(Module &M,
                  SmallPtrSetImpl<const Comdat *> &NotDiscardableComdats) {
   bool Changed = false;
   for (GlobalIFunc &IF : make_early_inc_range(M.ifuncs()))
-    if (deleteIfDead(IF, NotDiscardableComdats)) {
+    if (deleteIfDead(M, IF, NotDiscardableComdats)) {
       NumIFuncsDeleted++;
       Changed = true;
     }
diff --git a/llvm/test/Transforms/GlobalOpt/dead_metadata.ll b/llvm/test/Transforms/GlobalOpt/dead_metadata.ll
new file mode 100644
index 0000000000000..bbf9a51d3f57d
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/dead_metadata.ll
@@ -0,0 +1,11 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=globalopt < %s | FileCheck %s
+
+ at a = global i32 0, !associated !0
+ at b = external global i32, !associated !1
+
+!0 = !{ptr @b}
+!1 = !{ptr @a}
+
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: @a = local_unnamed_addr global i32
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/169221


More information about the llvm-commits mailing list