Skip to content

Commit 0115262

Browse files
committed
[Linker] Handle comdat nodeduplicate
For a variable in a comdat nodeduplicate, its initializer may be significant. E.g. its content may be implicitly referenced by another comdat member (or required to parallel to another comdat member by the runtime when explicit section is used). We can clone it into an unnamed private linkage variable to preserve its content. This partially fixes PR51394 (Sony's proprietary linker using LTO): no error will be reported. This is partial because we do not guarantee the global variable order if the runtime has parallel section requirement. --- There is a similar issue for regular LTO, but unrelated to PR51394: with lib/LTO (using either ld.lld or LLVMgold.so), linking two modules with a weak function of the same name, can leave one weak profc and two private profd, due to lib/LTO's current deficiency that it mixes the two concepts together: comdat selection and symbol resolution. If the issue is considered important, we should suppress private profd for the weak+ regular LTO case. Reviewed By: phosek Differential Revision: https://reviews.llvm.org/D108879
1 parent 319ce98 commit 0115262

File tree

2 files changed

+44
-31
lines changed

2 files changed

+44
-31
lines changed

llvm/lib/Linker/LinkModules.cpp

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ using namespace llvm;
2424

2525
namespace {
2626

27-
enum class LinkFrom { Dst, Src };
27+
enum class LinkFrom { Dst, Src, Both };
2828

2929
/// This is an implementation class for the LinkModules function, which is the
3030
/// entrypoint for this file.
@@ -105,7 +105,7 @@ class ModuleLinker {
105105
void dropReplacedComdat(GlobalValue &GV,
106106
const DenseSet<const Comdat *> &ReplacedDstComdats);
107107

108-
bool linkIfNeeded(GlobalValue &GV);
108+
bool linkIfNeeded(GlobalValue &GV, SmallVectorImpl<GlobalValue *> &GVToClone);
109109

110110
public:
111111
ModuleLinker(IRMover &Mover, std::unique_ptr<Module> SrcM, unsigned Flags,
@@ -179,25 +179,9 @@ bool ModuleLinker::computeResultingSelectionKind(StringRef ComdatName,
179179
// Go with Dst.
180180
From = LinkFrom::Dst;
181181
break;
182-
case Comdat::SelectionKind::NoDeduplicate: {
183-
const GlobalVariable *DstGV;
184-
const GlobalVariable *SrcGV;
185-
if (getComdatLeader(DstM, ComdatName, DstGV) ||
186-
getComdatLeader(*SrcM, ComdatName, SrcGV))
187-
return true;
188-
189-
if (SrcGV->isWeakForLinker()) {
190-
// Go with Dst.
191-
From = LinkFrom::Dst;
192-
} else if (DstGV->isWeakForLinker()) {
193-
// Go with Src.
194-
From = LinkFrom::Src;
195-
} else {
196-
return emitError("Linking COMDATs named '" + ComdatName +
197-
"': nodeduplicate has been violated!");
198-
}
182+
case Comdat::SelectionKind::NoDeduplicate:
183+
From = LinkFrom::Both;
199184
break;
200-
}
201185
case Comdat::SelectionKind::ExactMatch:
202186
case Comdat::SelectionKind::Largest:
203187
case Comdat::SelectionKind::SameSize: {
@@ -342,7 +326,8 @@ bool ModuleLinker::shouldLinkFromSource(bool &LinkFromSrc,
342326
"': symbol multiply defined!");
343327
}
344328

345-
bool ModuleLinker::linkIfNeeded(GlobalValue &GV) {
329+
bool ModuleLinker::linkIfNeeded(GlobalValue &GV,
330+
SmallVectorImpl<GlobalValue *> &GVToClone) {
346331
GlobalValue *DGV = getLinkedToGlobal(&GV);
347332

348333
if (shouldLinkOnlyNeeded()) {
@@ -404,6 +389,8 @@ bool ModuleLinker::linkIfNeeded(GlobalValue &GV) {
404389
bool LinkFromSrc = true;
405390
if (DGV && shouldLinkFromSource(LinkFromSrc, *DGV, GV))
406391
return true;
392+
if (DGV && ComdatFrom == LinkFrom::Both)
393+
GVToClone.push_back(LinkFromSrc ? DGV : &GV);
407394
if (LinkFromSrc)
408395
ValuesToLink.insert(&GV);
409396
return false;
@@ -530,22 +517,45 @@ bool ModuleLinker::run() {
530517

531518
// Insert all of the globals in src into the DstM module... without linking
532519
// initializers (which could refer to functions not yet mapped over).
520+
SmallVector<GlobalValue *, 0> GVToClone;
533521
for (GlobalVariable &GV : SrcM->globals())
534-
if (linkIfNeeded(GV))
522+
if (linkIfNeeded(GV, GVToClone))
535523
return true;
536524

537525
for (Function &SF : *SrcM)
538-
if (linkIfNeeded(SF))
526+
if (linkIfNeeded(SF, GVToClone))
539527
return true;
540528

541529
for (GlobalAlias &GA : SrcM->aliases())
542-
if (linkIfNeeded(GA))
530+
if (linkIfNeeded(GA, GVToClone))
543531
return true;
544532

545533
for (GlobalIFunc &GI : SrcM->ifuncs())
546-
if (linkIfNeeded(GI))
534+
if (linkIfNeeded(GI, GVToClone))
547535
return true;
548536

537+
// For a variable in a comdat nodeduplicate, its initializer should be
538+
// preserved (its content may be implicitly used by other members) even if
539+
// symbol resolution does not pick it. Clone it into an unnamed private
540+
// variable.
541+
for (GlobalValue *GV : GVToClone) {
542+
if (auto *Var = dyn_cast<GlobalVariable>(GV)) {
543+
auto *NewVar = new GlobalVariable(*Var->getParent(), Var->getValueType(),
544+
Var->isConstant(), Var->getLinkage(),
545+
Var->getInitializer());
546+
NewVar->copyAttributesFrom(Var);
547+
NewVar->setVisibility(GlobalValue::DefaultVisibility);
548+
NewVar->setLinkage(GlobalValue::PrivateLinkage);
549+
NewVar->setDSOLocal(true);
550+
NewVar->setComdat(Var->getComdat());
551+
if (Var->getParent() != &Mover.getModule())
552+
ValuesToLink.insert(NewVar);
553+
} else {
554+
emitError("linking '" + GV->getName() +
555+
"': non-variables in comdat nodeduplicate are not handled");
556+
}
557+
}
558+
549559
for (unsigned I = 0; I < ValuesToLink.size(); ++I) {
550560
GlobalValue *GV = ValuesToLink[I];
551561
const Comdat *SC = GV->getComdat();

llvm/test/Linker/comdat-nodeduplicate.ll

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
; RUN: rm -rf %t && split-file %s %t
22
; RUN: not llvm-link -S %t/1.ll %t/1-aux.ll 2>&1 | FileCheck %s
33

4-
; CHECK: error: Linking COMDATs named 'foo': nodeduplicate has been violated!
4+
; CHECK: Linking globals named 'foo': symbol multiply defined!
55

66
; RUN: llvm-link -S %t/2.ll %t/2-aux.ll | FileCheck %s --check-prefix=CHECK2
77
; RUN: llvm-link -S %t/2-aux.ll %t/2.ll | FileCheck %s --check-prefix=CHECK2
88

9-
; CHECK2-DAG: @foo = global i64 2, section "data", comdat, align 8
10-
; CHECK2-DAG: @bar = weak global i64 0, section "cnts", comdat($foo)
9+
; CHECK2-DAG: @[[#]] = private global i64 0, section "data", comdat($foo)
10+
; CHECK2-DAG: @[[#]] = private global i64 0, section "cnts", comdat($foo)
11+
; CHECK2-DAG: @foo = hidden global i64 2, section "data", comdat, align 8
12+
; CHECK2-DAG: @bar = dso_local global i64 3, section "cnts", comdat($foo), align 16
1113
; CHECK2-DAG: @qux = weak_odr global i64 4, comdat($foo)
14+
; CHECK2-DAG: @fred = linkonce global i64 5, comdat($foo)
1215

13-
; RUN: not llvm-link -S %t/non-var.ll %t/non-var.ll 2>&1 | FileCheck %s --check-prefix=NONVAR
16+
; RUN: llvm-link -S %t/non-var.ll %t/non-var.ll 2>&1 | FileCheck %s --check-prefix=NONVAR
1417

15-
; NONVAR: error: Linking COMDATs named 'foo': GlobalVariable required for data dependent selection!
18+
; NONVAR: linking 'foo': non-variables in comdat nodeduplicate are not handled
1619

1720
;--- 1.ll
1821
$foo = comdat nodeduplicate
@@ -30,7 +33,7 @@ $foo = comdat nodeduplicate
3033

3134
;--- 2-aux.ll
3235
$foo = comdat nodeduplicate
33-
@foo = weak global i64 0, section "data", comdat($foo)
36+
@foo = weak hidden global i64 0, section "data", comdat($foo)
3437
@bar = dso_local global i64 3, section "cnts", comdat($foo), align 16
3538
@fred = linkonce global i64 5, comdat($foo)
3639

0 commit comments

Comments
 (0)