[llvm] [LLVM] Maintain element type of @llvm.compiler.used/@llvm.used if it already exists (PR #162660)

Juan Manuel Martinez CaamaƱo via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 16 02:08:59 PDT 2025


https://github.com/jmmartinez updated https://github.com/llvm/llvm-project/pull/162660

>From 51dda4dab6f7e62b41fc9136a5a61dccb63461f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Thu, 9 Oct 2025 14:57:56 +0200
Subject: [PATCH 1/8] Pre-Commit test: [LLVM] Maintain element type of
 @llvm.compiler.used/@llvm.used if it already exists

This new test fails with:

    /home/juamarti/llvm/_llvm/llvm/lib/IR/Constants.cpp:1327:
    static Constant *llvm::ConstantArray::getImpl(ArrayType *, ArrayRef<Constant *>):
    Assertion `C->getType() == Ty->getElementType()
      && "Wrong type in array element initializer"'
      failed.
---
 .../Transforms/Utils/ModuleUtilsTest.cpp        | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
index d4094c5307060..0cc408af43bc5 100644
--- a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
@@ -69,6 +69,23 @@ TEST(ModuleUtils, AppendToUsedList2) {
   EXPECT_EQ(1, getListSize(*M, "llvm.used"));
 }
 
+TEST(ModuleUtils, AppendToUsedList3) {
+  LLVMContext C;
+
+  std::unique_ptr<Module> M = parseIR(C, R"(
+          @x = addrspace(1) global [2 x i32] zeroinitializer, align 4
+          @y = addrspace(2) global [2 x i32] zeroinitializer, align 4
+          @llvm.compiler.used = appending global [1 x ptr addrspace (3)] [ptr addrspace(3) addrspacecast (ptr addrspace (1) @x to ptr addrspace(3))]
+      )");
+  GlobalVariable *X = M->getNamedGlobal("x");
+  GlobalVariable *Y = M->getNamedGlobal("y");
+  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
+  appendToCompilerUsed(*M, X);
+  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
+  appendToCompilerUsed(*M, Y);
+  EXPECT_EQ(2, getListSize(*M, "llvm.compiler.used"));
+}
+
 using AppendFnType = decltype(&appendToGlobalCtors);
 using TransformFnType = decltype(&transformGlobalCtors);
 using ParamType = std::tuple<StringRef, AppendFnType, TransformFnType>;

>From 5fc418cdd7ef4fb37b873cab36a9aa77ad3b7552 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Thu, 9 Oct 2025 14:34:32 +0200
Subject: [PATCH 2/8] [LLVM] Maintain element type of
 @llvm.compiler.used/@llvm.used if it already exists

At the moment, the pointer type stored in the
llvm.compiler.used/llvm.used is not well fixed.

The frontend uses a pointer to the default address space (which may not
be 0; for example, it is 4 for SPIRV).

This patch makes `appendToUsed/appendToCompilerUsed` match the behaviour
in BitcodeWriter.cpp: if the variable already exists, preserve its
element type, otherwise use `ptr addrspace (0)`.

This fixes the following error in the newly added test:

  UtilsTests: /home/juamarti/llvm/_llvm/llvm/lib/IR/Constants.cpp:1327:
    static Constant *llvm::ConstantArray::getImpl(ArrayType *, ArrayRef<Constant *>):
    Assertion `C->getType() == Ty->getElementType() && "Wrong type in array element initializer"' failed.
---
 llvm/lib/Transforms/Utils/ModuleUtils.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index 596849ecab742..d1acb0ff1ad6b 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -138,10 +138,11 @@ static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *>
 
   SmallSetVector<Constant *, 16> Init;
   collectUsedGlobals(GV, Init);
+  Type *ArrayEltTy = GV ? GV->getValueType()->getArrayElementType()
+                        : PointerType::getUnqual(M.getContext());
   if (GV)
     GV->eraseFromParent();
 
-  Type *ArrayEltTy = llvm::PointerType::getUnqual(M.getContext());
   for (auto *V : Values)
     Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy));
 

>From 94711ebce860a86c3b1c60736732c81360924dd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Thu, 9 Oct 2025 14:34:24 +0200
Subject: [PATCH 3/8] [NFC][BitcodeWriter] Use appendToCompilerUsed instead of
 custom implementation

---
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 70 ++++++++++-------------
 llvm/lib/Bitcode/Writer/CMakeLists.txt    |  1 +
 2 files changed, 31 insertions(+), 40 deletions(-)

diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 8ff3aa9817571..af66e13641126 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -75,6 +75,7 @@
 #include "llvm/Support/SHA1.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Triple.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
@@ -5864,25 +5865,25 @@ static const char *getSectionNameForCommandline(const Triple &T) {
 void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
                                 bool EmbedBitcode, bool EmbedCmdline,
                                 const std::vector<uint8_t> &CmdArgs) {
-  // Save llvm.compiler.used and remove it.
-  SmallVector<Constant *, 2> UsedArray;
-  SmallVector<GlobalValue *, 4> UsedGlobals;
-  GlobalVariable *Used = collectUsedGlobalVariables(M, UsedGlobals, true);
-  Type *UsedElementType = Used ? Used->getValueType()->getArrayElementType()
-                               : PointerType::getUnqual(M.getContext());
-  for (auto *GV : UsedGlobals) {
-    if (GV->getName() != "llvm.embedded.module" &&
-        GV->getName() != "llvm.cmdline")
-      UsedArray.push_back(
-          ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
-  }
-  if (Used)
-    Used->eraseFromParent();
 
   // Embed the bitcode for the llvm module.
   std::string Data;
   ArrayRef<uint8_t> ModuleData;
   Triple T(M.getTargetTriple());
+  SmallVector<GlobalValue *, 2> NewGlobals;
+
+  auto IsCmdOrBitcode = [&](Constant *C) {
+    GlobalVariable *GV = dyn_cast<GlobalVariable>(C);
+    StringRef Name = GV ? GV->getName() : "";
+    if (EmbedBitcode && Name == "llvm.embedded.module")
+      return true;
+    if (EmbedCmdline && Name == "llvm.cmdline")
+      return true;
+    return false;
+  };
+
+  if (EmbedBitcode || EmbedCmdline)
+    removeFromUsedLists(M, IsCmdOrBitcode);
 
   if (EmbedBitcode) {
     if (Buf.getBufferSize() == 0 ||
@@ -5901,23 +5902,22 @@ void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
   }
   llvm::Constant *ModuleConstant =
       llvm::ConstantDataArray::get(M.getContext(), ModuleData);
-  llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+  llvm::GlobalVariable *EmbeddedModule = new llvm::GlobalVariable(
       M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage,
       ModuleConstant);
-  GV->setSection(getSectionNameForBitcode(T));
+  EmbeddedModule->setSection(getSectionNameForBitcode(T));
   // Set alignment to 1 to prevent padding between two contributions from input
   // sections after linking.
-  GV->setAlignment(Align(1));
-  UsedArray.push_back(
-      ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
+  EmbeddedModule->setAlignment(Align(1));
+  NewGlobals.push_back(EmbeddedModule);
   if (llvm::GlobalVariable *Old =
           M.getGlobalVariable("llvm.embedded.module", true)) {
     assert(Old->hasZeroLiveUses() &&
            "llvm.embedded.module can only be used once in llvm.compiler.used");
-    GV->takeName(Old);
+    EmbeddedModule->takeName(Old);
     Old->eraseFromParent();
   } else {
-    GV->setName("llvm.embedded.module");
+    EmbeddedModule->setName("llvm.embedded.module");
   }
 
   // Skip if only bitcode needs to be embedded.
@@ -5927,30 +5927,20 @@ void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
                               CmdArgs.size());
     llvm::Constant *CmdConstant =
         llvm::ConstantDataArray::get(M.getContext(), CmdData);
-    GV = new llvm::GlobalVariable(M, CmdConstant->getType(), true,
-                                  llvm::GlobalValue::PrivateLinkage,
-                                  CmdConstant);
-    GV->setSection(getSectionNameForCommandline(T));
-    GV->setAlignment(Align(1));
-    UsedArray.push_back(
-        ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
+    GlobalVariable *CmdLine = new llvm::GlobalVariable(
+        M, CmdConstant->getType(), true, llvm::GlobalValue::PrivateLinkage,
+        CmdConstant);
+    CmdLine->setSection(getSectionNameForCommandline(T));
+    CmdLine->setAlignment(Align(1));
     if (llvm::GlobalVariable *Old = M.getGlobalVariable("llvm.cmdline", true)) {
       assert(Old->hasZeroLiveUses() &&
              "llvm.cmdline can only be used once in llvm.compiler.used");
-      GV->takeName(Old);
+      CmdLine->takeName(Old);
       Old->eraseFromParent();
     } else {
-      GV->setName("llvm.cmdline");
+      CmdLine->setName("llvm.cmdline");
     }
+    NewGlobals.push_back(CmdLine);
+    appendToCompilerUsed(M, NewGlobals);
   }
-
-  if (UsedArray.empty())
-    return;
-
-  // Recreate llvm.compiler.used.
-  ArrayType *ATy = ArrayType::get(UsedElementType, UsedArray.size());
-  auto *NewUsed = new GlobalVariable(
-      M, ATy, false, llvm::GlobalValue::AppendingLinkage,
-      llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used");
-  NewUsed->setSection("llvm.metadata");
 }
diff --git a/llvm/lib/Bitcode/Writer/CMakeLists.txt b/llvm/lib/Bitcode/Writer/CMakeLists.txt
index 2c508ca9fae95..5bbb872a90341 100644
--- a/llvm/lib/Bitcode/Writer/CMakeLists.txt
+++ b/llvm/lib/Bitcode/Writer/CMakeLists.txt
@@ -15,4 +15,5 @@ add_llvm_component_library(LLVMBitWriter
   ProfileData
   Support
   TargetParser
+  TransformUtils
   )

>From 69ede1be9eff2d31a32b67feda26919d8f64e4bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Fri, 10 Oct 2025 09:52:55 +0200
Subject: [PATCH 4/8] [Review] Remove lambda from embedBitcodeInModule

---
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index af66e13641126..d42cce76d4487 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -5862,6 +5862,12 @@ static const char *getSectionNameForCommandline(const Triple &T) {
   llvm_unreachable("Unimplemented ObjectFormatType");
 }
 
+static auto globalInUsedHasName(StringRef Name) {
+  return [Name](Constant* C) {
+    return C->getName() == Name;
+  };
+}
+
 void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
                                 bool EmbedBitcode, bool EmbedCmdline,
                                 const std::vector<uint8_t> &CmdArgs) {
@@ -5872,19 +5878,6 @@ void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
   Triple T(M.getTargetTriple());
   SmallVector<GlobalValue *, 2> NewGlobals;
 
-  auto IsCmdOrBitcode = [&](Constant *C) {
-    GlobalVariable *GV = dyn_cast<GlobalVariable>(C);
-    StringRef Name = GV ? GV->getName() : "";
-    if (EmbedBitcode && Name == "llvm.embedded.module")
-      return true;
-    if (EmbedCmdline && Name == "llvm.cmdline")
-      return true;
-    return false;
-  };
-
-  if (EmbedBitcode || EmbedCmdline)
-    removeFromUsedLists(M, IsCmdOrBitcode);
-
   if (EmbedBitcode) {
     if (Buf.getBufferSize() == 0 ||
         !isBitcode((const unsigned char *)Buf.getBufferStart(),
@@ -5912,6 +5905,7 @@ void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
   NewGlobals.push_back(EmbeddedModule);
   if (llvm::GlobalVariable *Old =
           M.getGlobalVariable("llvm.embedded.module", true)) {
+    removeFromUsedLists(M, globalInUsedHasName("llvm.embedded.module"));
     assert(Old->hasZeroLiveUses() &&
            "llvm.embedded.module can only be used once in llvm.compiler.used");
     EmbeddedModule->takeName(Old);
@@ -5933,6 +5927,7 @@ void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,
     CmdLine->setSection(getSectionNameForCommandline(T));
     CmdLine->setAlignment(Align(1));
     if (llvm::GlobalVariable *Old = M.getGlobalVariable("llvm.cmdline", true)) {
+      removeFromUsedLists(M, globalInUsedHasName("llvm.cmdline"));
       assert(Old->hasZeroLiveUses() &&
              "llvm.cmdline can only be used once in llvm.compiler.used");
       CmdLine->takeName(Old);

>From a5e4c7311144b4d760415633be92f0b43adb8648 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Fri, 10 Oct 2025 09:54:55 +0200
Subject: [PATCH 5/8] [Review] 'addrspace (n)' -> 'addrspace(n)'

---
 llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
index 0cc408af43bc5..cbdb4dcbc9a6f 100644
--- a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
@@ -75,7 +75,7 @@ TEST(ModuleUtils, AppendToUsedList3) {
   std::unique_ptr<Module> M = parseIR(C, R"(
           @x = addrspace(1) global [2 x i32] zeroinitializer, align 4
           @y = addrspace(2) global [2 x i32] zeroinitializer, align 4
-          @llvm.compiler.used = appending global [1 x ptr addrspace (3)] [ptr addrspace(3) addrspacecast (ptr addrspace (1) @x to ptr addrspace(3))]
+          @llvm.compiler.used = appending global [1 x ptr addrspace(3)] [ptr addrspace(3) addrspacecast (ptr addrspace(1) @x to ptr addrspace(3))]
       )");
   GlobalVariable *X = M->getNamedGlobal("x");
   GlobalVariable *Y = M->getNamedGlobal("y");

>From a368f1cd7840a657c3b8944d4199f5fe173308ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Fri, 10 Oct 2025 10:40:58 +0200
Subject: [PATCH 6/8] [Review] Forgot again to run clang-format

---
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index d42cce76d4487..fc6bcaf598fc9 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -5863,9 +5863,7 @@ static const char *getSectionNameForCommandline(const Triple &T) {
 }
 
 static auto globalInUsedHasName(StringRef Name) {
-  return [Name](Constant* C) {
-    return C->getName() == Name;
-  };
+  return [Name](Constant *C) { return C->getName() == Name; };
 }
 
 void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf,

>From e686175ece054671ea9fcc124ab725cd05b7d7ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Thu, 16 Oct 2025 09:51:00 +0200
Subject: [PATCH 7/8] [Review] Move llvm.used/llvm.compiler.used helpers from
 ModuleUtils to GlobalValue; and remove dependency between BitcodeWriter &
 TransformUtils

---
 llvm/include/llvm/IR/GlobalValue.h            | 12 +++
 .../llvm/Transforms/Utils/ModuleUtils.h       | 12 ---
 llvm/lib/Bitcode/Writer/CMakeLists.txt        |  1 -
 llvm/lib/CodeGen/JMCInstrumenter.cpp          |  1 -
 llvm/lib/IR/Globals.cpp                       | 78 +++++++++++++++++++
 .../Target/AMDGPU/AMDGPUCtorDtorLowering.cpp  |  1 -
 .../Target/NVPTX/NVPTXCtorDtorLowering.cpp    |  1 -
 llvm/lib/Transforms/Utils/ModuleUtils.cpp     | 77 ------------------
 .../Utils/SampleProfileLoaderBaseUtil.cpp     |  1 -
 9 files changed, 90 insertions(+), 94 deletions(-)

diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h
index 83e695cdd27d9..8f6726bd99335 100644
--- a/llvm/include/llvm/IR/GlobalValue.h
+++ b/llvm/include/llvm/IR/GlobalValue.h
@@ -684,6 +684,18 @@ class GlobalValue : public Constant {
   LLVM_ABI bool canBeOmittedFromSymbolTable() const;
 };
 
+/// Adds global values to the llvm.used list.
+LLVM_ABI void appendToUsed(Module &M, ArrayRef<GlobalValue *> Values);
+
+/// Adds global values to the llvm.compiler.used list.
+LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values);
+
+/// Removes global values from the llvm.used and llvm.compiler.used arrays. \p
+/// ShouldRemove should return true for any initializer field that should not be
+/// included in the replacement global.
+LLVM_ABI void removeFromUsedLists(Module &M,
+                                  function_ref<bool(Constant *)> ShouldRemove);
+
 } // end namespace llvm
 
 #endif // LLVM_IR_GLOBALVALUE_H
diff --git a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h
index 4036c4e947c75..98bb4579f3a6c 100644
--- a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h
@@ -96,18 +96,6 @@ getOrCreateSanitizerCtorAndInitFunctions(
 /// the list of public globals in the module.
 LLVM_ABI bool nameUnamedGlobals(Module &M);
 
-/// Adds global values to the llvm.used list.
-LLVM_ABI void appendToUsed(Module &M, ArrayRef<GlobalValue *> Values);
-
-/// Adds global values to the llvm.compiler.used list.
-LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values);
-
-/// Removes global values from the llvm.used and llvm.compiler.used arrays. \p
-/// ShouldRemove should return true for any initializer field that should not be
-/// included in the replacement global.
-LLVM_ABI void removeFromUsedLists(Module &M,
-                                  function_ref<bool(Constant *)> ShouldRemove);
-
 /// Filter out potentially dead comdat functions where other entries keep the
 /// entire comdat group alive.
 ///
diff --git a/llvm/lib/Bitcode/Writer/CMakeLists.txt b/llvm/lib/Bitcode/Writer/CMakeLists.txt
index 5bbb872a90341..2c508ca9fae95 100644
--- a/llvm/lib/Bitcode/Writer/CMakeLists.txt
+++ b/llvm/lib/Bitcode/Writer/CMakeLists.txt
@@ -15,5 +15,4 @@ add_llvm_component_library(LLVMBitWriter
   ProfileData
   Support
   TargetParser
-  TransformUtils
   )
diff --git a/llvm/lib/CodeGen/JMCInstrumenter.cpp b/llvm/lib/CodeGen/JMCInstrumenter.cpp
index e2aaebedf5a4f..b1c05294ac4b5 100644
--- a/llvm/lib/CodeGen/JMCInstrumenter.cpp
+++ b/llvm/lib/CodeGen/JMCInstrumenter.cpp
@@ -36,7 +36,6 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/DJB.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace llvm;
 
diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp
index c3a472b0cc66d..609c463d95d40 100644
--- a/llvm/lib/IR/Globals.cpp
+++ b/llvm/lib/IR/Globals.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "LLVMContextImpl.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
@@ -671,3 +672,80 @@ void GlobalIFunc::applyAlongResolverPath(
   DenseSet<const GlobalAlias *> Aliases;
   findBaseObject(getResolver(), Aliases, Op);
 }
+
+static void collectUsedGlobals(GlobalVariable *GV,
+                               SmallSetVector<Constant *, 16> &Init) {
+  if (!GV || !GV->hasInitializer())
+    return;
+
+  auto *CA = cast<ConstantArray>(GV->getInitializer());
+  for (Use &Op : CA->operands())
+    Init.insert(cast<Constant>(Op));
+}
+
+static void appendToUsedList(Module &M, StringRef Name,
+                             ArrayRef<GlobalValue *> Values) {
+  GlobalVariable *GV = M.getGlobalVariable(Name);
+
+  SmallSetVector<Constant *, 16> Init;
+  collectUsedGlobals(GV, Init);
+  Type *ArrayEltTy = GV ? GV->getValueType()->getArrayElementType()
+                        : PointerType::getUnqual(M.getContext());
+  if (GV)
+    GV->eraseFromParent();
+
+  for (auto *V : Values)
+    Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy));
+
+  if (Init.empty())
+    return;
+
+  ArrayType *ATy = ArrayType::get(ArrayEltTy, Init.size());
+  GV = new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
+                          ConstantArray::get(ATy, Init.getArrayRef()), Name);
+  GV->setSection("llvm.metadata");
+}
+
+void llvm::appendToUsed(Module &M, ArrayRef<GlobalValue *> Values) {
+  appendToUsedList(M, "llvm.used", Values);
+}
+
+void llvm::appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values) {
+  appendToUsedList(M, "llvm.compiler.used", Values);
+}
+
+static void removeFromUsedList(Module &M, StringRef Name,
+                               function_ref<bool(Constant *)> ShouldRemove) {
+  GlobalVariable *GV = M.getNamedGlobal(Name);
+  if (!GV)
+    return;
+
+  SmallSetVector<Constant *, 16> Init;
+  collectUsedGlobals(GV, Init);
+
+  Type *ArrayEltTy = cast<ArrayType>(GV->getValueType())->getElementType();
+
+  SmallVector<Constant *, 16> NewInit;
+  for (Constant *MaybeRemoved : Init) {
+    if (!ShouldRemove(MaybeRemoved->stripPointerCasts()))
+      NewInit.push_back(MaybeRemoved);
+  }
+
+  if (!NewInit.empty()) {
+    ArrayType *ATy = ArrayType::get(ArrayEltTy, NewInit.size());
+    GlobalVariable *NewGV =
+        new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
+                           ConstantArray::get(ATy, NewInit), "", GV,
+                           GV->getThreadLocalMode(), GV->getAddressSpace());
+    NewGV->setSection(GV->getSection());
+    NewGV->takeName(GV);
+  }
+
+  GV->eraseFromParent();
+}
+
+void llvm::removeFromUsedLists(Module &M,
+                               function_ref<bool(Constant *)> ShouldRemove) {
+  removeFromUsedList(M, "llvm.used", ShouldRemove);
+  removeFromUsedList(M, "llvm.compiler.used", ShouldRemove);
+}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCtorDtorLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCtorDtorLowering.cpp
index a774ad53b5bed..bd1727571f41a 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUCtorDtorLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCtorDtorLowering.cpp
@@ -19,7 +19,6 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Pass.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace llvm;
 
diff --git a/llvm/lib/Target/NVPTX/NVPTXCtorDtorLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXCtorDtorLowering.cpp
index 4e069398d540f..18618ca19beee 100644
--- a/llvm/lib/Target/NVPTX/NVPTXCtorDtorLowering.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXCtorDtorLowering.cpp
@@ -24,7 +24,6 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/MD5.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace llvm;
 
diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index d1acb0ff1ad6b..81ddcf06c49d2 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -123,83 +123,6 @@ void llvm::transformGlobalDtors(Module &M, const GlobalCtorTransformFn &Fn) {
   transformGlobalArray("llvm.global_dtors", M, Fn);
 }
 
-static void collectUsedGlobals(GlobalVariable *GV,
-                               SmallSetVector<Constant *, 16> &Init) {
-  if (!GV || !GV->hasInitializer())
-    return;
-
-  auto *CA = cast<ConstantArray>(GV->getInitializer());
-  for (Use &Op : CA->operands())
-    Init.insert(cast<Constant>(Op));
-}
-
-static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *> Values) {
-  GlobalVariable *GV = M.getGlobalVariable(Name);
-
-  SmallSetVector<Constant *, 16> Init;
-  collectUsedGlobals(GV, Init);
-  Type *ArrayEltTy = GV ? GV->getValueType()->getArrayElementType()
-                        : PointerType::getUnqual(M.getContext());
-  if (GV)
-    GV->eraseFromParent();
-
-  for (auto *V : Values)
-    Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy));
-
-  if (Init.empty())
-    return;
-
-  ArrayType *ATy = ArrayType::get(ArrayEltTy, Init.size());
-  GV = new llvm::GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
-                                ConstantArray::get(ATy, Init.getArrayRef()),
-                                Name);
-  GV->setSection("llvm.metadata");
-}
-
-void llvm::appendToUsed(Module &M, ArrayRef<GlobalValue *> Values) {
-  appendToUsedList(M, "llvm.used", Values);
-}
-
-void llvm::appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values) {
-  appendToUsedList(M, "llvm.compiler.used", Values);
-}
-
-static void removeFromUsedList(Module &M, StringRef Name,
-                               function_ref<bool(Constant *)> ShouldRemove) {
-  GlobalVariable *GV = M.getNamedGlobal(Name);
-  if (!GV)
-    return;
-
-  SmallSetVector<Constant *, 16> Init;
-  collectUsedGlobals(GV, Init);
-
-  Type *ArrayEltTy = cast<ArrayType>(GV->getValueType())->getElementType();
-
-  SmallVector<Constant *, 16> NewInit;
-  for (Constant *MaybeRemoved : Init) {
-    if (!ShouldRemove(MaybeRemoved->stripPointerCasts()))
-      NewInit.push_back(MaybeRemoved);
-  }
-
-  if (!NewInit.empty()) {
-    ArrayType *ATy = ArrayType::get(ArrayEltTy, NewInit.size());
-    GlobalVariable *NewGV =
-        new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
-                           ConstantArray::get(ATy, NewInit), "", GV,
-                           GV->getThreadLocalMode(), GV->getAddressSpace());
-    NewGV->setSection(GV->getSection());
-    NewGV->takeName(GV);
-  }
-
-  GV->eraseFromParent();
-}
-
-void llvm::removeFromUsedLists(Module &M,
-                               function_ref<bool(Constant *)> ShouldRemove) {
-  removeFromUsedList(M, "llvm.used", ShouldRemove);
-  removeFromUsedList(M, "llvm.compiler.used", ShouldRemove);
-}
-
 void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
   if (!M.getModuleFlag("kcfi"))
     return;
diff --git a/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp b/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp
index f7ae6ad844948..324f6194a2d72 100644
--- a/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp
+++ b/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp
@@ -14,7 +14,6 @@
 #include "llvm/Analysis/ProfileSummaryInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Module.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
 
 namespace llvm {
 

>From e9a62539d180a6a1b1c3de19cba33856eca5fd66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Thu, 16 Oct 2025 11:08:26 +0200
Subject: [PATCH 8/8] [Review] forgot to move the unittests

---
 llvm/unittests/IR/CMakeLists.txt              |  1 +
 llvm/unittests/IR/UsedGlobalTest.cpp          | 82 +++++++++++++++++++
 .../Transforms/Utils/ModuleUtilsTest.cpp      | 53 ------------
 3 files changed, 83 insertions(+), 53 deletions(-)
 create mode 100644 llvm/unittests/IR/UsedGlobalTest.cpp

diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
index d62ce66ef9d34..1e7f0932dd989 100644
--- a/llvm/unittests/IR/CMakeLists.txt
+++ b/llvm/unittests/IR/CMakeLists.txt
@@ -49,6 +49,7 @@ add_llvm_unittest(IRTests
   TypesTest.cpp
   UseTest.cpp
   UserTest.cpp
+  UsedGlobalTest.cpp
   ValueHandleTest.cpp
   ValueMapTest.cpp
   ValueTest.cpp
diff --git a/llvm/unittests/IR/UsedGlobalTest.cpp b/llvm/unittests/IR/UsedGlobalTest.cpp
new file mode 100644
index 0000000000000..23cedc6f774f9
--- /dev/null
+++ b/llvm/unittests/IR/UsedGlobalTest.cpp
@@ -0,0 +1,82 @@
+//===- UsedGlobalTest.cpp - Unit tests for Module utility ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+static std::unique_ptr<Module> parseIR(LLVMContext &C, StringRef IR) {
+  SMDiagnostic Err;
+  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
+  if (!Mod)
+    Err.print("UsedGlobalTest", errs());
+  return Mod;
+}
+
+static int getListSize(Module &M, StringRef Name) {
+  auto *List = M.getGlobalVariable(Name);
+  if (!List)
+    return 0;
+  auto *T = cast<ArrayType>(List->getValueType());
+  return T->getNumElements();
+}
+
+TEST(UsedGlobal, AppendToUsedList1) {
+  LLVMContext C;
+
+  std::unique_ptr<Module> M = parseIR(
+      C, R"(@x = addrspace(4) global [2 x i32] zeroinitializer, align 4)");
+  SmallVector<GlobalValue *, 2> Globals;
+  for (auto &G : M->globals()) {
+    Globals.push_back(&G);
+  }
+  EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
+  appendToCompilerUsed(*M, Globals);
+  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
+
+  EXPECT_EQ(0, getListSize(*M, "llvm.used"));
+  appendToUsed(*M, Globals);
+  EXPECT_EQ(1, getListSize(*M, "llvm.used"));
+}
+
+TEST(UsedGlobal, AppendToUsedList2) {
+  LLVMContext C;
+
+  std::unique_ptr<Module> M =
+      parseIR(C, R"(@x = global [2 x i32] zeroinitializer, align 4)");
+  SmallVector<GlobalValue *, 2> Globals;
+  for (auto &G : M->globals()) {
+    Globals.push_back(&G);
+  }
+  EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
+  appendToCompilerUsed(*M, Globals);
+  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
+
+  EXPECT_EQ(0, getListSize(*M, "llvm.used"));
+  appendToUsed(*M, Globals);
+  EXPECT_EQ(1, getListSize(*M, "llvm.used"));
+}
+
+TEST(UsedGlobal, AppendToUsedList3) {
+  LLVMContext C;
+
+  std::unique_ptr<Module> M = parseIR(C, R"(
+          @x = addrspace(1) global [2 x i32] zeroinitializer, align 4
+          @y = addrspace(2) global [2 x i32] zeroinitializer, align 4
+          @llvm.compiler.used = appending global [1 x ptr addrspace(3)] [ptr addrspace(3) addrspacecast (ptr addrspace(1) @x to ptr addrspace(3))]
+      )");
+  GlobalVariable *X = M->getNamedGlobal("x");
+  GlobalVariable *Y = M->getNamedGlobal("y");
+  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
+  appendToCompilerUsed(*M, X);
+  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
+  appendToCompilerUsed(*M, Y);
+  EXPECT_EQ(2, getListSize(*M, "llvm.compiler.used"));
+}
diff --git a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
index cbdb4dcbc9a6f..f1c984717096f 100644
--- a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp
@@ -33,59 +33,6 @@ static int getListSize(Module &M, StringRef Name) {
   return T->getNumElements();
 }
 
-TEST(ModuleUtils, AppendToUsedList1) {
-  LLVMContext C;
-
-  std::unique_ptr<Module> M = parseIR(
-      C, R"(@x = addrspace(4) global [2 x i32] zeroinitializer, align 4)");
-  SmallVector<GlobalValue *, 2> Globals;
-  for (auto &G : M->globals()) {
-    Globals.push_back(&G);
-  }
-  EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
-  appendToCompilerUsed(*M, Globals);
-  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
-
-  EXPECT_EQ(0, getListSize(*M, "llvm.used"));
-  appendToUsed(*M, Globals);
-  EXPECT_EQ(1, getListSize(*M, "llvm.used"));
-}
-
-TEST(ModuleUtils, AppendToUsedList2) {
-  LLVMContext C;
-
-  std::unique_ptr<Module> M =
-      parseIR(C, R"(@x = global [2 x i32] zeroinitializer, align 4)");
-  SmallVector<GlobalValue *, 2> Globals;
-  for (auto &G : M->globals()) {
-    Globals.push_back(&G);
-  }
-  EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used"));
-  appendToCompilerUsed(*M, Globals);
-  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
-
-  EXPECT_EQ(0, getListSize(*M, "llvm.used"));
-  appendToUsed(*M, Globals);
-  EXPECT_EQ(1, getListSize(*M, "llvm.used"));
-}
-
-TEST(ModuleUtils, AppendToUsedList3) {
-  LLVMContext C;
-
-  std::unique_ptr<Module> M = parseIR(C, R"(
-          @x = addrspace(1) global [2 x i32] zeroinitializer, align 4
-          @y = addrspace(2) global [2 x i32] zeroinitializer, align 4
-          @llvm.compiler.used = appending global [1 x ptr addrspace(3)] [ptr addrspace(3) addrspacecast (ptr addrspace(1) @x to ptr addrspace(3))]
-      )");
-  GlobalVariable *X = M->getNamedGlobal("x");
-  GlobalVariable *Y = M->getNamedGlobal("y");
-  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
-  appendToCompilerUsed(*M, X);
-  EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used"));
-  appendToCompilerUsed(*M, Y);
-  EXPECT_EQ(2, getListSize(*M, "llvm.compiler.used"));
-}
-
 using AppendFnType = decltype(&appendToGlobalCtors);
 using TransformFnType = decltype(&transformGlobalCtors);
 using ParamType = std::tuple<StringRef, AppendFnType, TransformFnType>;



More information about the llvm-commits mailing list