Skip to content

Commit dc4c8cf

Browse files
committed
[LTO] Handles commons in monolithic LTO
The gold-plugin was doing this internally, now the API is handling commons correctly based on the given resolution. Differential Revision: https://reviews.llvm.org/D23739 llvm-svn: 279417
1 parent d310b47 commit dc4c8cf

File tree

5 files changed

+111
-58
lines changed

5 files changed

+111
-58
lines changed

llvm/include/llvm/LTO/LTO.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,11 @@ class LTO {
306306

307307
struct RegularLTOState {
308308
RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf);
309+
struct CommonResolution {
310+
uint64_t Size = 0;
311+
unsigned Align = 0;
312+
};
313+
std::map<std::string, CommonResolution> Commons;
309314

310315
unsigned ParallelCodeGenParallelismLevel;
311316
LTOLLVMContext Ctx;

llvm/lib/LTO/LTO.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,14 @@ Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
292292
break;
293293
}
294294
}
295+
// Common resolution: collect the maximum size/alignment.
296+
// FIXME: right now we ignore the prevailing information, it is not clear
297+
// what is the "right" behavior here.
298+
if (Sym.getFlags() & object::BasicSymbolRef::SF_Common) {
299+
auto &CommonRes = RegularLTO.Commons[Sym.getIRName()];
300+
CommonRes.Size = std::max(CommonRes.Size, Sym.getCommonSize());
301+
CommonRes.Align = std::max(CommonRes.Align, Sym.getCommonAlignment());
302+
}
295303

296304
// FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
297305
}
@@ -361,6 +369,31 @@ Error LTO::run(AddOutputFn AddOutput) {
361369
}
362370

363371
Error LTO::runRegularLTO(AddOutputFn AddOutput) {
372+
// Make sure commons have the right size/alignment: we kept the largest from
373+
// all the prevailing when adding the inputs, and we apply it here.
374+
for (auto &I : RegularLTO.Commons) {
375+
ArrayType *Ty =
376+
ArrayType::get(Type::getInt8Ty(RegularLTO.Ctx), I.second.Size);
377+
GlobalVariable *OldGV = RegularLTO.CombinedModule->getNamedGlobal(I.first);
378+
if (OldGV && OldGV->getType()->getElementType() == Ty) {
379+
// Don't create a new global if the type is already correct, just make
380+
// sure the alignment is correct.
381+
OldGV->setAlignment(I.second.Align);
382+
continue;
383+
}
384+
auto *GV = new GlobalVariable(*RegularLTO.CombinedModule, Ty, false,
385+
GlobalValue::CommonLinkage,
386+
ConstantAggregateZero::get(Ty), "");
387+
GV->setAlignment(I.second.Align);
388+
if (OldGV) {
389+
OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType()));
390+
GV->takeName(OldGV);
391+
OldGV->eraseFromParent();
392+
} else {
393+
GV->setName(I.first);
394+
}
395+
}
396+
364397
if (Conf.PreOptModuleHook &&
365398
!Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
366399
return Error();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
target triple = "x86_64-apple-macosx10.11.0"
2+
3+
@v = common global i16 0, align 4
4+
5+
define i16 *@bar() {
6+
ret i16 *@v
7+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
; RUN: llvm-as < %s > %t1.bc
2+
; RUN: llvm-as < %p/Inputs/common.ll > %t2.bc
3+
4+
; Test that the common merging (size + alignment) is properly handled
5+
6+
; Client marked the "large with little alignment" one as prevailing
7+
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
8+
; RUN: -r %t1.bc,v,x \
9+
; RUN: -r %t2.bc,v,px \
10+
; RUN: -r %t1.bc,foo,px \
11+
; RUN: -r %t2.bc,bar,px
12+
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
13+
14+
; Same as before, but reversing the order of the inputs
15+
; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
16+
; RUN: -r %t1.bc,v,x \
17+
; RUN: -r %t2.bc,v,px \
18+
; RUN: -r %t1.bc,foo,px \
19+
; RUN: -r %t2.bc,bar,px
20+
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
21+
22+
23+
; Client marked the "small with large alignment" one as prevailing
24+
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
25+
; RUN: -r %t1.bc,v,px \
26+
; RUN: -r %t2.bc,v,x \
27+
; RUN: -r %t1.bc,foo,px \
28+
; RUN: -r %t2.bc,bar,px
29+
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
30+
31+
; Same as before, but reversing the order of the inputs
32+
; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
33+
; RUN: -r %t1.bc,v,px \
34+
; RUN: -r %t2.bc,v,x \
35+
; RUN: -r %t1.bc,foo,px \
36+
; RUN: -r %t2.bc,bar,px
37+
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
38+
39+
40+
; Client didn't mark any as prevailing, we keep the first one we see as "external"
41+
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
42+
; RUN: -r %t1.bc,v,x \
43+
; RUN: -r %t2.bc,v,x \
44+
; RUN: -r %t1.bc,foo,px \
45+
; RUN: -r %t2.bc,bar,px
46+
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
47+
48+
; Same as before, but reversing the order of the inputs
49+
; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
50+
; RUN: -r %t1.bc,v,x \
51+
; RUN: -r %t2.bc,v,x \
52+
; RUN: -r %t1.bc,foo,px \
53+
; RUN: -r %t2.bc,bar,px
54+
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
55+
56+
target triple = "x86_64-apple-macosx10.11.0"
57+
58+
@v = common global i8 0, align 8
59+
60+
61+
; CHECK: @v = common global [2 x i8] zeroinitializer, align 8
62+
63+
define i8 *@foo() {
64+
ret i8 *@v
65+
}

llvm/tools/gold/gold-plugin.cpp

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,6 @@ struct ResolutionInfo {
8989
bool DefaultVisibility = true;
9090
};
9191

92-
struct CommonResolution {
93-
bool Prevailing = false;
94-
bool VisibleToRegularObj = false;
95-
uint64_t Size = 0;
96-
unsigned Align = 0;
97-
};
98-
9992
}
10093

10194
static ld_plugin_add_symbols add_symbols = nullptr;
@@ -109,7 +102,6 @@ static std::string output_name = "";
109102
static std::list<claimed_file> Modules;
110103
static DenseMap<int, void *> FDToLeaderHandle;
111104
static StringMap<ResolutionInfo> ResInfo;
112-
static std::map<std::string, CommonResolution> Commons;
113105
static std::vector<std::string> Cleanup;
114106
static llvm::TargetOptions TargetOpts;
115107
static size_t MaxTasks;
@@ -572,12 +564,10 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View) {
572564
toString(ObjOrErr.takeError()).c_str());
573565

574566
InputFile &Obj = **ObjOrErr;
575-
bool HasThinLTOSummary =
576-
hasGlobalValueSummary(Obj.getMemoryBufferRef(), diagnosticHandler);
577567

578568
unsigned SymNum = 0;
579569
std::vector<SymbolResolution> Resols(F.syms.size());
580-
for (auto &ObjSym : Obj.symbols()) {
570+
for (LLVM_ATTRIBUTE_UNUSED auto &ObjSym : Obj.symbols()) {
581571
ld_plugin_symbol &Sym = F.syms[SymNum];
582572
SymbolResolution &R = Resols[SymNum];
583573
++SymNum;
@@ -619,21 +609,6 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View) {
619609
(IsExecutable || !Res.DefaultVisibility))
620610
R.FinalDefinitionInLinkageUnit = true;
621611

622-
if ((ObjSym.getFlags() & object::BasicSymbolRef::SF_Common) &&
623-
!HasThinLTOSummary) {
624-
// We ignore gold's resolution for common symbols. A common symbol with
625-
// the correct size and alignment is added to the module by the pre-opt
626-
// module hook if any common symbol prevailed.
627-
CommonResolution &CommonRes = Commons[ObjSym.getIRName()];
628-
if (R.Prevailing) {
629-
CommonRes.Prevailing = true;
630-
CommonRes.VisibleToRegularObj = R.VisibleToRegularObj;
631-
}
632-
CommonRes.Size = std::max(CommonRes.Size, ObjSym.getCommonSize());
633-
CommonRes.Align = std::max(CommonRes.Align, ObjSym.getCommonAlignment());
634-
R.Prevailing = false;
635-
}
636-
637612
freeSymName(Sym);
638613
}
639614

@@ -668,32 +643,6 @@ static void getOutputFileName(SmallString<128> InFilename, bool TempOutFile,
668643
}
669644
}
670645

671-
/// Add all required common symbols to M, which is expected to be the first
672-
/// combined module.
673-
static void addCommons(Module &M) {
674-
for (auto &I : Commons) {
675-
if (!I.second.Prevailing)
676-
continue;
677-
ArrayType *Ty =
678-
ArrayType::get(Type::getInt8Ty(M.getContext()), I.second.Size);
679-
GlobalVariable *OldGV = M.getNamedGlobal(I.first);
680-
auto *GV = new GlobalVariable(M, Ty, false, GlobalValue::CommonLinkage,
681-
ConstantAggregateZero::get(Ty), "");
682-
GV->setAlignment(I.second.Align);
683-
if (OldGV) {
684-
OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType()));
685-
GV->takeName(OldGV);
686-
OldGV->eraseFromParent();
687-
} else {
688-
GV->setName(I.first);
689-
}
690-
// We may only internalize commons if there is a single LTO task because
691-
// other native object files may require the common.
692-
if (MaxTasks == 1 && !I.second.VisibleToRegularObj)
693-
GV->setLinkage(GlobalValue::InternalLinkage);
694-
}
695-
}
696-
697646
static CodeGenOpt::Level getCGOptLevel() {
698647
switch (options::OptLevel) {
699648
case 0:
@@ -773,12 +722,6 @@ static std::unique_ptr<LTO> createLTO() {
773722

774723
Conf.DiagHandler = diagnosticHandler;
775724

776-
Conf.PreOptModuleHook = [](size_t Task, Module &M) {
777-
if (Task == 0)
778-
addCommons(M);
779-
return true;
780-
};
781-
782725
switch (options::TheOutputType) {
783726
case options::OT_NORMAL:
784727
break;

0 commit comments

Comments
 (0)