Skip to content

Commit b1554fe

Browse files
authored
[Linker] Do not keep a private member of a non-prevailing comdat group (llvm#69143)
`IRMover` links in referenced private global values unconditionally, see `IRLinker::shouldLink()`. If they are part of a non-prevailing comdat, this leads to duplication of the values. Full and Thin LTO avoid duplication by changing the linkage of members of non-prevailing comdat groups to `available_externally`, which was implemented in https://reviews.llvm.org/D34803 and https://reviews.llvm.org/D135427. This patch does the same for `Linker`, but limits the effect only to private members without aliases to minimize interference. Motivation example: ``` > cat foo.h inline int foo(int a) { return a + 1; } > cat bar.cpp #include "foo.h" int bar(int a) { return foo(a + 1); } > cat main.cpp #include "foo.h" int bar(int a); int main(int argc, const char* argv[]) { return bar(argc) + foo(argc); } > clang++ -c -flto -fprofile-instr-generate main.cpp -o main.o > clang++ -c -flto -fprofile-instr-generate bar.cpp -o bar.o > clang++ -fuse-ld=lld -fprofile-instr-generate main.o bar.o -o test1 > ./test1 > llvm-profdata merge --text default.profraw -o - _Z3fooi # Counter Values: 2 > llvm-link main.o bar.o -o combined.o > clang++ -fuse-ld=lld -fprofile-instr-generate combined.o -o test2 > ./test2 > llvm-profdata merge --text default.profraw -o - _Z3fooi # Counter Values: 4 ```
1 parent 497b2eb commit b1554fe

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

llvm/lib/Linker/LinkModules.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ void ModuleLinker::dropReplacedComdat(
462462
bool ModuleLinker::run() {
463463
Module &DstM = Mover.getModule();
464464
DenseSet<const Comdat *> ReplacedDstComdats;
465+
DenseSet<const Comdat *> NonPrevailingComdats;
465466

466467
for (const auto &SMEC : SrcM->getComdatSymbolTable()) {
467468
const Comdat &C = SMEC.getValue();
@@ -473,6 +474,9 @@ bool ModuleLinker::run() {
473474
return true;
474475
ComdatsChosen[&C] = std::make_pair(SK, From);
475476

477+
if (From == LinkFrom::Dst)
478+
NonPrevailingComdats.insert(&C);
479+
476480
if (From != LinkFrom::Src)
477481
continue;
478482

@@ -497,6 +501,23 @@ bool ModuleLinker::run() {
497501
for (Function &GV : llvm::make_early_inc_range(DstM))
498502
dropReplacedComdat(GV, ReplacedDstComdats);
499503

504+
if (!NonPrevailingComdats.empty()) {
505+
DenseSet<GlobalObject *> AliasedGlobals;
506+
for (auto &GA : SrcM->aliases())
507+
if (GlobalObject *GO = GA.getAliaseeObject(); GO && GO->getComdat())
508+
AliasedGlobals.insert(GO);
509+
for (const Comdat *C : NonPrevailingComdats) {
510+
SmallVector<GlobalObject *> ToUpdate;
511+
for (GlobalObject *GO : C->getUsers())
512+
if (GO->hasPrivateLinkage() && !AliasedGlobals.contains(GO))
513+
ToUpdate.push_back(GO);
514+
for (GlobalObject *GO : ToUpdate) {
515+
GO->setLinkage(GlobalValue::AvailableExternallyLinkage);
516+
GO->setComdat(nullptr);
517+
}
518+
}
519+
}
520+
500521
for (GlobalVariable &GV : SrcM->globals())
501522
if (GV.hasLinkOnceLinkage())
502523
if (const Comdat *SC = GV.getComdat())

llvm/test/Linker/comdat-nonprevailing-decl.ll

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
; RUN: rm -rf %t && split-file %s %t
22
; RUN: llvm-link -S %t/1.ll %t/1-aux.ll -o - | FileCheck %s
3+
; RUN: llvm-link -S %t/2.ll %t/2-aux.ll -o - | FileCheck %s --check-prefix=CHECK2
34

45
;--- 1.ll
56
$c = comdat any
@@ -23,3 +24,31 @@ define ptr @f3() {
2324
ret ptr @v3
2425
}
2526

27+
;--- 2.ll
28+
;; Check that a private global variable from a non-prevailing comdat group is
29+
;; converted into 'available_externally' and excluded from the comdat group.
30+
31+
; CHECK2: $__profc_foo = comdat any
32+
; CHECK2: @llvm.compiler.used = appending global [2 x ptr] [ptr @__profd_foo.[[SUFFIX:[0-9]+]], ptr @__profd_foo]
33+
; CHECK2: @__profd_foo.[[SUFFIX]] = private global ptr @__profc_foo, comdat($__profc_foo)
34+
; CHECK2: @__profc_foo = linkonce_odr global i64 1, comdat
35+
; CHECK2: @__profd_foo = available_externally dso_local global ptr @__profc_foo{{$}}
36+
37+
$__profc_foo = comdat any
38+
@__profc_foo = linkonce_odr global i64 1, comdat
39+
@__profd_foo = private global ptr @__profc_foo, comdat($__profc_foo)
40+
@llvm.compiler.used = appending global [1 x ptr] [ ptr @__profd_foo ]
41+
42+
define ptr @bar() {
43+
ret ptr @__profc_foo
44+
}
45+
46+
;--- 2-aux.ll
47+
$__profc_foo = comdat any
48+
@__profc_foo = linkonce_odr global i64 1, comdat
49+
@__profd_foo = private global ptr @__profc_foo, comdat($__profc_foo)
50+
@llvm.compiler.used = appending global [1 x ptr] [ ptr @__profd_foo ]
51+
52+
define ptr @baz() {
53+
ret ptr @__profc_foo
54+
}

0 commit comments

Comments
 (0)