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 Values); + +/// Adds global values to the llvm.compiler.used list. +LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef 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 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 Values); - -/// Adds global values to the llvm.compiler.used list. -LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef 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 ShouldRemove); - /// Filter out potentially dead comdat functions where other entries keep the /// entire comdat group alive. /// diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 8ff3aa9817571..fc6bcaf598fc9 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 #include #include @@ -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 &CmdArgs) { - // Save llvm.compiler.used and remove it. - SmallVector UsedArray; - SmallVector 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 ModuleData; Triple T(M.getTargetTriple()); + SmallVector NewGlobals; if (EmbedBitcode) { if (Buf.getBufferSize() == 0 || @@ -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. @@ -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"); } 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 Aliases; findBaseObject(getResolver(), Aliases, Op); } + +static void collectUsedGlobals(GlobalVariable *GV, + SmallSetVector &Init) { + if (!GV || !GV->hasInitializer()) + return; + + auto *CA = cast(GV->getInitializer()); + for (Use &Op : CA->operands()) + Init.insert(cast(Op)); +} + +static void appendToUsedList(Module &M, StringRef Name, + ArrayRef Values) { + GlobalVariable *GV = M.getGlobalVariable(Name); + + SmallSetVector 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 Values) { + appendToUsedList(M, "llvm.used", Values); +} + +void llvm::appendToCompilerUsed(Module &M, ArrayRef Values) { + appendToUsedList(M, "llvm.compiler.used", Values); +} + +static void removeFromUsedList(Module &M, StringRef Name, + function_ref ShouldRemove) { + GlobalVariable *GV = M.getNamedGlobal(Name); + if (!GV) + return; + + SmallSetVector Init; + collectUsedGlobals(GV, Init); + + Type *ArrayEltTy = cast(GV->getValueType())->getElementType(); + + SmallVector 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 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 596849ecab742..81ddcf06c49d2 100644 --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -123,82 +123,6 @@ void llvm::transformGlobalDtors(Module &M, const GlobalCtorTransformFn &Fn) { transformGlobalArray("llvm.global_dtors", M, Fn); } -static void collectUsedGlobals(GlobalVariable *GV, - SmallSetVector &Init) { - if (!GV || !GV->hasInitializer()) - return; - - auto *CA = cast(GV->getInitializer()); - for (Use &Op : CA->operands()) - Init.insert(cast(Op)); -} - -static void appendToUsedList(Module &M, StringRef Name, ArrayRef Values) { - GlobalVariable *GV = M.getGlobalVariable(Name); - - SmallSetVector 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 Values) { - appendToUsedList(M, "llvm.used", Values); -} - -void llvm::appendToCompilerUsed(Module &M, ArrayRef Values) { - appendToUsedList(M, "llvm.compiler.used", Values); -} - -static void removeFromUsedList(Module &M, StringRef Name, - function_ref ShouldRemove) { - GlobalVariable *GV = M.getNamedGlobal(Name); - if (!GV) - return; - - SmallSetVector Init; - collectUsedGlobals(GV, Init); - - Type *ArrayEltTy = cast(GV->getValueType())->getElementType(); - - SmallVector 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 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 { 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 parseIR(LLVMContext &C, StringRef IR) { + SMDiagnostic Err; + std::unique_ptr 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(List->getValueType()); + return T->getNumElements(); +} + +TEST(UsedGlobal, AppendToUsedList1) { + LLVMContext C; + + std::unique_ptr M = parseIR( + C, R"(@x = addrspace(4) global [2 x i32] zeroinitializer, align 4)"); + SmallVector 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 M = + parseIR(C, R"(@x = global [2 x i32] zeroinitializer, align 4)"); + SmallVector 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 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 d4094c5307060..f1c984717096f 100644 --- a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp +++ b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp @@ -33,42 +33,6 @@ static int getListSize(Module &M, StringRef Name) { return T->getNumElements(); } -TEST(ModuleUtils, AppendToUsedList1) { - LLVMContext C; - - std::unique_ptr M = parseIR( - C, R"(@x = addrspace(4) global [2 x i32] zeroinitializer, align 4)"); - SmallVector 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 M = - parseIR(C, R"(@x = global [2 x i32] zeroinitializer, align 4)"); - SmallVector 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")); -} - using AppendFnType = decltype(&appendToGlobalCtors); using TransformFnType = decltype(&transformGlobalCtors); using ParamType = std::tuple;