[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
Fri Oct 10 01:14:18 PDT 2025


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

>From c9f9939c06d21a396268eb5b6b0744e4b9ce5ec8 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/5] 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 276346d4043d7dce22333610611c053cd207cf7a 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/5] [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 9cb36675ccb80889f87bf025639565d6030103d3 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/5] [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 7ed140d392fca..f7afa393f3e00 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>
@@ -5850,25 +5851,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 ||
@@ -5887,23 +5888,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.
@@ -5913,30 +5913,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 22f1c7f6b679dddeeccb5669df87da784f564180 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/5] [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 f7afa393f3e00..a6519ad7f29ac 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -5848,6 +5848,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) {
@@ -5858,19 +5864,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(),
@@ -5898,6 +5891,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);
@@ -5919,6 +5913,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 7b445e0ca3391af3053e94bc9fbc34ceb9bff5fd 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/5] [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");



More information about the llvm-commits mailing list