From fde55a9c9bf147241249ae478760ae69dd1925ed Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Thu, 18 Feb 2021 17:23:02 -0800 Subject: [PATCH] [LTO] Fix cloning of llvm*.used when splitting module Refines the fix in 3c4c205060c9398da705eb71b63ddd8a04999de9 to only put globals whose defs were cloned into the split regular LTO module on the cloned llvm*.used globals. This avoids an issue where one of the attached values was a local that was promoted in the original module after the module was cloned. We only need to have the values defined in the new module on those globals. Fixes PR49251. Differential Revision: https://reviews.llvm.org/D97013 --- .../Transforms/IPO/ThinLTOBitcodeWriter.cpp | 33 ++++++++++++++++--- llvm/lib/Transforms/Utils/ModuleUtils.cpp | 12 ++++--- .../ThinLTOBitcodeWriter/split-used.ll | 30 +++++++++++++++++ 3 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 llvm/test/Transforms/ThinLTOBitcodeWriter/split-used.ll 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"}