llvm.org GIT mirror llvm / 156e0da
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@279417 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 4 years ago
5 changed file(s) with 111 addition(s) and 58 deletion(s). Raw diff Collapse all Expand all
305305
306306 struct RegularLTOState {
307307 RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf);
308 struct CommonResolution {
309 uint64_t Size = 0;
310 unsigned Align = 0;
311 };
312 std::map Commons;
308313
309314 unsigned ParallelCodeGenParallelismLevel;
310315 LTOLLVMContext Ctx;
291291 break;
292292 }
293293 }
294 // Common resolution: collect the maximum size/alignment.
295 // FIXME: right now we ignore the prevailing information, it is not clear
296 // what is the "right" behavior here.
297 if (Sym.getFlags() & object::BasicSymbolRef::SF_Common) {
298 auto &CommonRes = RegularLTO.Commons[Sym.getIRName()];
299 CommonRes.Size = std::max(CommonRes.Size, Sym.getCommonSize());
300 CommonRes.Align = std::max(CommonRes.Align, Sym.getCommonAlignment());
301 }
294302
295303 // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
296304 }
360368 }
361369
362370 Error LTO::runRegularLTO(AddOutputFn AddOutput) {
371 // Make sure commons have the right size/alignment: we kept the largest from
372 // all the prevailing when adding the inputs, and we apply it here.
373 for (auto &I : RegularLTO.Commons) {
374 ArrayType *Ty =
375 ArrayType::get(Type::getInt8Ty(RegularLTO.Ctx), I.second.Size);
376 GlobalVariable *OldGV = RegularLTO.CombinedModule->getNamedGlobal(I.first);
377 if (OldGV && OldGV->getType()->getElementType() == Ty) {
378 // Don't create a new global if the type is already correct, just make
379 // sure the alignment is correct.
380 OldGV->setAlignment(I.second.Align);
381 continue;
382 }
383 auto *GV = new GlobalVariable(*RegularLTO.CombinedModule, Ty, false,
384 GlobalValue::CommonLinkage,
385 ConstantAggregateZero::get(Ty), "");
386 GV->setAlignment(I.second.Align);
387 if (OldGV) {
388 OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType()));
389 GV->takeName(OldGV);
390 OldGV->eraseFromParent();
391 } else {
392 GV->setName(I.first);
393 }
394 }
395
363396 if (Conf.PreOptModuleHook &&
364397 !Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
365398 return Error();
0 target triple = "x86_64-apple-macosx10.11.0"
1
2 @v = common global i16 0, align 4
3
4 define i16 *@bar() {
5 ret i16 *@v
6 }
0 ; RUN: llvm-as < %s > %t1.bc
1 ; RUN: llvm-as < %p/Inputs/common.ll > %t2.bc
2
3 ; Test that the common merging (size + alignment) is properly handled
4
5 ; Client marked the "large with little alignment" one as prevailing
6 ; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
7 ; RUN: -r %t1.bc,v,x \
8 ; RUN: -r %t2.bc,v,px \
9 ; RUN: -r %t1.bc,foo,px \
10 ; RUN: -r %t2.bc,bar,px
11 ; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
12
13 ; Same as before, but reversing the order of the inputs
14 ; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
15 ; RUN: -r %t1.bc,v,x \
16 ; RUN: -r %t2.bc,v,px \
17 ; RUN: -r %t1.bc,foo,px \
18 ; RUN: -r %t2.bc,bar,px
19 ; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
20
21
22 ; Client marked the "small with large alignment" one as prevailing
23 ; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
24 ; RUN: -r %t1.bc,v,px \
25 ; RUN: -r %t2.bc,v,x \
26 ; RUN: -r %t1.bc,foo,px \
27 ; RUN: -r %t2.bc,bar,px
28 ; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
29
30 ; Same as before, but reversing the order of the inputs
31 ; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
32 ; RUN: -r %t1.bc,v,px \
33 ; RUN: -r %t2.bc,v,x \
34 ; RUN: -r %t1.bc,foo,px \
35 ; RUN: -r %t2.bc,bar,px
36 ; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
37
38
39 ; Client didn't mark any as prevailing, we keep the first one we see as "external"
40 ; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
41 ; RUN: -r %t1.bc,v,x \
42 ; RUN: -r %t2.bc,v,x \
43 ; RUN: -r %t1.bc,foo,px \
44 ; RUN: -r %t2.bc,bar,px
45 ; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
46
47 ; Same as before, but reversing the order of the inputs
48 ; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
49 ; RUN: -r %t1.bc,v,x \
50 ; RUN: -r %t2.bc,v,x \
51 ; RUN: -r %t1.bc,foo,px \
52 ; RUN: -r %t2.bc,bar,px
53 ; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s
54
55 target triple = "x86_64-apple-macosx10.11.0"
56
57 @v = common global i8 0, align 8
58
59
60 ; CHECK: @v = common global [2 x i8] zeroinitializer, align 8
61
62 define i8 *@foo() {
63 ret i8 *@v
64 }
8888 bool DefaultVisibility = true;
8989 };
9090
91 struct CommonResolution {
92 bool Prevailing = false;
93 bool VisibleToRegularObj = false;
94 uint64_t Size = 0;
95 unsigned Align = 0;
96 };
97
9891 }
9992
10093 static ld_plugin_add_symbols add_symbols = nullptr;
108101 static std::list Modules;
109102 static DenseMap FDToLeaderHandle;
110103 static StringMap ResInfo;
111 static std::map Commons;
112104 static std::vector Cleanup;
113105 static llvm::TargetOptions TargetOpts;
114106 static size_t MaxTasks;
571563 toString(ObjOrErr.takeError()).c_str());
572564
573565 InputFile &Obj = **ObjOrErr;
574 bool HasThinLTOSummary =
575 hasGlobalValueSummary(Obj.getMemoryBufferRef(), diagnosticHandler);
576566
577567 unsigned SymNum = 0;
578568 std::vector Resols(F.syms.size());
579 for (auto &ObjSym : Obj.symbols()) {
569 for (LLVM_ATTRIBUTE_UNUSED auto &ObjSym : Obj.symbols()) {
580570 ld_plugin_symbol &Sym = F.syms[SymNum];
581571 SymbolResolution &R = Resols[SymNum];
582572 ++SymNum;
617607 if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF &&
618608 (IsExecutable || !Res.DefaultVisibility))
619609 R.FinalDefinitionInLinkageUnit = true;
620
621 if ((ObjSym.getFlags() & object::BasicSymbolRef::SF_Common) &&
622 !HasThinLTOSummary) {
623 // We ignore gold's resolution for common symbols. A common symbol with
624 // the correct size and alignment is added to the module by the pre-opt
625 // module hook if any common symbol prevailed.
626 CommonResolution &CommonRes = Commons[ObjSym.getIRName()];
627 if (R.Prevailing) {
628 CommonRes.Prevailing = true;
629 CommonRes.VisibleToRegularObj = R.VisibleToRegularObj;
630 }
631 CommonRes.Size = std::max(CommonRes.Size, ObjSym.getCommonSize());
632 CommonRes.Align = std::max(CommonRes.Align, ObjSym.getCommonAlignment());
633 R.Prevailing = false;
634 }
635610
636611 freeSymName(Sym);
637612 }
667642 }
668643 }
669644
670 /// Add all required common symbols to M, which is expected to be the first
671 /// combined module.
672 static void addCommons(Module &M) {
673 for (auto &I : Commons) {
674 if (!I.second.Prevailing)
675 continue;
676 ArrayType *Ty =
677 ArrayType::get(Type::getInt8Ty(M.getContext()), I.second.Size);
678 GlobalVariable *OldGV = M.getNamedGlobal(I.first);
679 auto *GV = new GlobalVariable(M, Ty, false, GlobalValue::CommonLinkage,
680 ConstantAggregateZero::get(Ty), "");
681 GV->setAlignment(I.second.Align);
682 if (OldGV) {
683 OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType()));
684 GV->takeName(OldGV);
685 OldGV->eraseFromParent();
686 } else {
687 GV->setName(I.first);
688 }
689 // We may only internalize commons if there is a single LTO task because
690 // other native object files may require the common.
691 if (MaxTasks == 1 && !I.second.VisibleToRegularObj)
692 GV->setLinkage(GlobalValue::InternalLinkage);
693 }
694 }
695
696645 static CodeGenOpt::Level getCGOptLevel() {
697646 switch (options::OptLevel) {
698647 case 0:
771720 Conf.DefaultTriple = sys::getDefaultTargetTriple();
772721
773722 Conf.DiagHandler = diagnosticHandler;
774
775 Conf.PreOptModuleHook = [](size_t Task, Module &M) {
776 if (Task == 0)
777 addCommons(M);
778 return true;
779 };
780723
781724 switch (options::TheOutputType) {
782725 case options::OT_NORMAL: