diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp index bb9de5346577..2ab9dcd09910 100644 --- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -195,6 +195,29 @@ void forEachVirtualFunction(Constant *C, function_ref Fn) { forEachVirtualFunction(cast(Op), Fn); } +// Clone any @llvm[.compiler].used over to the new module and append +// values whose defs were cloned into that module. +static void cloneUsedGlobalVariables(const Module &SrcM, Module &DestM, + bool CompilerUsed) { + SmallPtrSet Used; + SmallPtrSet NewUsed; + // First collect those in the llvm[.compiler].used set. + collectUsedGlobalVariables(SrcM, Used, CompilerUsed); + // Next build a set of the equivalent values defined in DestM. + for (auto *V : Used) { + auto *GV = DestM.getNamedValue(V->getName()); + if (GV && !GV->isDeclaration()) + NewUsed.insert(GV); + } + // Finally, add them to a llvm[.compiler].used variable in DestM. + if (CompilerUsed) + appendToCompilerUsed( + DestM, std::vector(NewUsed.begin(), NewUsed.end())); + else + appendToUsed(DestM, + std::vector(NewUsed.begin(), NewUsed.end())); +} + // If it's possible to split M into regular and thin LTO parts, do so and write // a multi-module bitcode file with the two parts to OS. Otherwise, write only a // regular LTO bitcode file to OS. @@ -275,11 +298,6 @@ void splitAndWriteThinLTOBitcode( ValueToValueMapTy VMap; std::unique_ptr MergedM( CloneModule(M, VMap, [&](const GlobalValue *GV) -> bool { - // Clone any llvm.*used globals to ensure the included values are - // not deleted. - if (GV->getName() == "llvm.used" || - GV->getName() == "llvm.compiler.used") - return true; if (const auto *C = GV->getComdat()) if (MergedMComdats.count(C)) return true; @@ -292,6 +310,11 @@ void splitAndWriteThinLTOBitcode( StripDebugInfo(*MergedM); MergedM->setModuleInlineAsm(""); + // Clone any llvm.*used globals to ensure the included values are + // not deleted. + cloneUsedGlobalVariables(M, *MergedM, /*CompilerUsed*/ false); + cloneUsedGlobalVariables(M, *MergedM, /*CompilerUsed*/ true); + for (Function &F : *MergedM) if (!F.isDeclaration()) { // Reset the linkage of all functions eligible for virtual constant diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp index ef9f18a2289e..f7bd8f0d500f 100644 --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -76,11 +76,13 @@ static void appendToUsedList(Module &M, StringRef Name, ArrayRef SmallPtrSet InitAsSet; SmallVector Init; if (GV) { - auto *CA = cast(GV->getInitializer()); - for (auto &Op : CA->operands()) { - Constant *C = cast_or_null(Op); - if (InitAsSet.insert(C).second) - Init.push_back(C); + if (GV->hasInitializer()) { + auto *CA = cast(GV->getInitializer()); + for (auto &Op : CA->operands()) { + Constant *C = cast_or_null(Op); + if (InitAsSet.insert(C).second) + Init.push_back(C); + } } GV->eraseFromParent(); } diff --git a/llvm/test/Transforms/ThinLTOBitcodeWriter/split-used.ll b/llvm/test/Transforms/ThinLTOBitcodeWriter/split-used.ll new file mode 100644 index 000000000000..77a4c7c782fb --- /dev/null +++ b/llvm/test/Transforms/ThinLTOBitcodeWriter/split-used.ll @@ -0,0 +1,30 @@ +; Test to ensure that @llvm[.compiler].used is cloned to the split module for +; any globals whose defs were cloned to that module. + +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s +; RUN: llvm-modextract -b -n 0 -o %t0.bc %t +; RUN: llvm-modextract -b -n 1 -o %t1.bc %t +; RUN: llvm-dis -o - %t0.bc | FileCheck --check-prefix=M0 %s +; RUN: llvm-dis -o - %t1.bc | FileCheck --check-prefix=M1 %s + +; M0: @g1 = external global i8 +; M0: @g2 = external global i8 +; M0: @g3 = global i8 42 +; M0: @g4 = global i8 42 +; M1: @g1 = global i8 42, !type !0 +; M1: @g2 = global i8 42, !type !0 +; M1-NOT: @g +@g1 = global i8 42, !type !0 +@g2 = global i8 42, !type !0 +@g3 = global i8 42 +@g4 = global i8 42 + +; M0: @llvm.used = appending global [2 x i8*] [i8* @g1, i8* @g3] +; M0: @llvm.compiler.used = appending global [2 x i8*] [i8* @g2, i8* @g4] +; M1: @llvm.used = appending global [1 x i8*] [i8* @g1] +; M1: @llvm.compiler.used = appending global [1 x i8*] [i8* @g2] +@llvm.used = appending global [2 x i8*] [ i8* @g1, i8* @g3] +@llvm.compiler.used = appending global [2 x i8*] [ i8* @g2, i8* @g4] + +; M1: !0 = !{i32 0, !"typeid"} +!0 = !{i32 0, !"typeid"}