Skip to content
12 changes: 12 additions & 0 deletions llvm/include/llvm/IR/GlobalValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 0 additions & 12 deletions llvm/include/llvm/Transforms/Utils/ModuleUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
63 changes: 23 additions & 40 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bitcode cannot depend on Transforms

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would moving these 3 functions to llvm/IR/UsedGlobals.h (or something like that) work for you ?

  • llvm::appendToUsed
  • llvm::appendToCompilerUsed
  • llvm::removeFromUsedLists

I'd really like to eventually use this elsewhere (in Clang's CodeGenModule and in the BitcodeWriter to avoid these kind of invariant violations in the future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably even to llvm/include/llvm/IR/GlobalValue.h, since at the end of the day these are manipulating GlobalValue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to match Shilei's suggestion.

Copy link
Contributor Author

@jmmartinez jmmartinez Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arf, I forgot to move the unittests -> Done

#include <algorithm>
#include <cassert>
#include <cstddef>
Expand Down Expand Up @@ -5861,28 +5862,19 @@ 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) {
// 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;

if (EmbedBitcode) {
if (Buf.getBufferSize() == 0 ||
Expand All @@ -5901,23 +5893,23 @@ 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)) {
removeFromUsedLists(M, globalInUsedHasName("llvm.embedded.module"));
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.
Expand All @@ -5927,30 +5919,21 @@ 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)) {
removeFromUsedLists(M, globalInUsedHasName("llvm.cmdline"));
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");
}
1 change: 0 additions & 1 deletion llvm/lib/CodeGen/JMCInstrumenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
78 changes: 78 additions & 0 deletions llvm/lib/IR/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
1 change: 0 additions & 1 deletion llvm/lib/Target/AMDGPU/AMDGPUCtorDtorLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Target/NVPTX/NVPTXCtorDtorLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
76 changes: 0 additions & 76 deletions llvm/lib/Transforms/Utils/ModuleUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,82 +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);
if (GV)
GV->eraseFromParent();

Type *ArrayEltTy = llvm::PointerType::getUnqual(M.getContext());
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;
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_llvm_unittest(IRTests
TypesTest.cpp
UseTest.cpp
UserTest.cpp
UsedGlobalTest.cpp
ValueHandleTest.cpp
ValueMapTest.cpp
ValueTest.cpp
Expand Down
Loading