[LTO] Fix cloning of llvm*.used when splitting module

Refines the fix in 3c4c205060 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
This commit is contained in:
Teresa Johnson 2021-02-18 17:23:02 -08:00
parent 309b00a42e
commit fde55a9c9b
3 changed files with 65 additions and 10 deletions

View File

@ -195,6 +195,29 @@ void forEachVirtualFunction(Constant *C, function_ref<void(Function *)> Fn) {
forEachVirtualFunction(cast<Constant>(Op), Fn); forEachVirtualFunction(cast<Constant>(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<GlobalValue *, 8> Used;
SmallPtrSet<GlobalValue *, 8> 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<GlobalValue *>(NewUsed.begin(), NewUsed.end()));
else
appendToUsed(DestM,
std::vector<GlobalValue *>(NewUsed.begin(), NewUsed.end()));
}
// If it's possible to split M into regular and thin LTO parts, do so and write // 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 // a multi-module bitcode file with the two parts to OS. Otherwise, write only a
// regular LTO bitcode file to OS. // regular LTO bitcode file to OS.
@ -275,11 +298,6 @@ void splitAndWriteThinLTOBitcode(
ValueToValueMapTy VMap; ValueToValueMapTy VMap;
std::unique_ptr<Module> MergedM( std::unique_ptr<Module> MergedM(
CloneModule(M, VMap, [&](const GlobalValue *GV) -> bool { 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 (const auto *C = GV->getComdat())
if (MergedMComdats.count(C)) if (MergedMComdats.count(C))
return true; return true;
@ -292,6 +310,11 @@ void splitAndWriteThinLTOBitcode(
StripDebugInfo(*MergedM); StripDebugInfo(*MergedM);
MergedM->setModuleInlineAsm(""); 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) for (Function &F : *MergedM)
if (!F.isDeclaration()) { if (!F.isDeclaration()) {
// Reset the linkage of all functions eligible for virtual constant // Reset the linkage of all functions eligible for virtual constant

View File

@ -76,11 +76,13 @@ static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *>
SmallPtrSet<Constant *, 16> InitAsSet; SmallPtrSet<Constant *, 16> InitAsSet;
SmallVector<Constant *, 16> Init; SmallVector<Constant *, 16> Init;
if (GV) { if (GV) {
auto *CA = cast<ConstantArray>(GV->getInitializer()); if (GV->hasInitializer()) {
for (auto &Op : CA->operands()) { auto *CA = cast<ConstantArray>(GV->getInitializer());
Constant *C = cast_or_null<Constant>(Op); for (auto &Op : CA->operands()) {
if (InitAsSet.insert(C).second) Constant *C = cast_or_null<Constant>(Op);
Init.push_back(C); if (InitAsSet.insert(C).second)
Init.push_back(C);
}
} }
GV->eraseFromParent(); GV->eraseFromParent();
} }

View File

@ -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"}