llvm.org GIT mirror llvm / bd57345
[ThinLTO] Add an auto-hide feature When a symbol is not exported outside of the DSO, it is can be hidden. Usually we try to internalize as much as possible, but it is not always possible, for instance a symbol can be referenced outside of the LTO unit, or there can be cross-module reference in ThinLTO. This is a recommit of r293912 after fixing build failures, and a recommit of r293918 after fixing LLD tests. Differential Revision: https://reviews.llvm.org/D28978 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293970 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 3 years ago
12 changed file(s) with 128 addition(s) and 53 deletion(s). Raw diff Collapse all Expand all
125125 /// llvm.global_ctors that the linker does not know about.
126126 unsigned LiveRoot : 1;
127127
128 /// Indicate if the global value should be hidden.
129 unsigned AutoHide : 1;
130
128131 /// Convenience Constructors
129132 explicit GVFlags(GlobalValue::LinkageTypes Linkage,
130 bool NotEligibleToImport, bool LiveRoot)
133 bool NotEligibleToImport, bool LiveRoot, bool AutoHide)
131134 : Linkage(Linkage), NotEligibleToImport(NotEligibleToImport),
132 LiveRoot(LiveRoot) {}
135 LiveRoot(LiveRoot), AutoHide(AutoHide) {}
133136 };
134137
135138 private:
196199 void setLinkage(GlobalValue::LinkageTypes Linkage) {
197200 Flags.Linkage = Linkage;
198201 }
202
203 /// Sets the visibility to be autohidden.
204 void setAutoHide() { Flags.AutoHide = true; }
199205
200206 /// Return true if this global value can't be imported.
201207 bool notEligibleToImport() const { return Flags.NotEligibleToImport; }
7878 auto &Elem = V[KeyInt];
7979 for (auto &FSum : FSums) {
8080 GlobalValueSummary::GVFlags GVFlags(GlobalValue::ExternalLinkage, false,
81 false);
81 false, /* AutoHide */ false);
8282 Elem.push_back(llvm::make_unique(
8383 GVFlags, 0, ArrayRef{},
8484 ArrayRef{}, std::move(FSum.TypeTests)));
5252 function_ref
5353 recordNewLinkage);
5454
55 /// This enum is used for the returned value of the callback passed to
56 /// thinLTOInternalizeAndPromoteInIndex, it indicates if a symbol can be made
57 /// Internal (only referenced from its defining object), Hidden (
58 /// outside the DSO), or Exported (exposed as public API for the DSO).
59 enum SummaryResolution { Internal, Hidden, Exported };
60
5561 /// Update the linkages in the given \p Index to mark exported values
5662 /// as external and non-exported values as internal. The ThinLTO backends
5763 /// must apply the changes to the Module via thinLTOInternalizeModule.
5864 void thinLTOInternalizeAndPromoteInIndex(
5965 ModuleSummaryIndex &Index,
60 function_ref<bool(StringRef, GlobalValue::GUID)> isExported);
66 function_ref<SummaryResolution(StringRef, GlobalValue::GUID)> isExported);
6167
6268 namespace lto {
6369
189189 // FIXME: refactor this to use the same code that inliner is using.
190190 F.isVarArg();
191191 GlobalValueSummary::GVFlags Flags(F.getLinkage(), NotEligibleForImport,
192 /* LiveRoot = */ false);
192 /* LiveRoot = */ false,
193 /* AutoHide */ false);
193194 auto FuncSummary = llvm::make_unique(
194195 Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector(),
195196 TypeTests.takeVector());
206207 findRefEdges(&V, RefEdges, Visited);
207208 bool NonRenamableLocal = isNonRenamableLocal(V);
208209 GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
209 /* LiveRoot = */ false);
210 /* LiveRoot = */ false,
211 /* AutoHide */ false);
210212 auto GVarSummary =
211213 llvm::make_unique(Flags, RefEdges.takeVector());
212214 if (NonRenamableLocal)
219221 DenseSet &CantBePromoted) {
220222 bool NonRenamableLocal = isNonRenamableLocal(A);
221223 GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal,
222 /* LiveRoot = */ false);
224 /* LiveRoot = */ false,
225 /* AutoHide */ false);
223226 auto AS = llvm::make_unique(Flags, ArrayRef{});
224227 auto *Aliasee = A.getBaseObject();
225228 auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee);
338341 assert(GV->isDeclaration() && "Def in module asm already has definition");
339342 GlobalValueSummary::GVFlags GVFlags(GlobalValue::InternalLinkage,
340343 /* NotEligibleToImport */ true,
341 /* LiveRoot */ true);
344 /* LiveRoot */ true,
345 /* AutoHide */ false);
342346 CantBePromoted.insert(GlobalValue::getGUID(Name));
343347 // Create the appropriate summary type.
344348 if (isa(GV)) {
799799 // like getDecodedLinkage() above. Any future change to the linkage enum and
800800 // to getDecodedLinkage() will need to be taken into account here as above.
801801 auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits
802 RawFlags = RawFlags >> 4;
803 bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3;
802 bool NotEligibleToImport = ((RawFlags >> 4) & 0x1) || Version < 3;
804803 // The LiveRoot flag wasn't introduced until version 3. For dead stripping
805804 // to work correctly on earlier versions, we must conservatively treat all
806805 // values as live.
807 bool LiveRoot = (RawFlags & 0x2) || Version < 3;
808 return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, LiveRoot);
806 bool LiveRoot = ((RawFlags >> 5) & 0x1) || Version < 3;
807 bool AutoHide = (RawFlags >> 6) & 0x1;
808 return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, LiveRoot,
809 AutoHide);
809810 }
810811
811812 static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {
970970 static uint64_t getEncodedGVSummaryFlags(GlobalValueSummary::GVFlags Flags) {
971971 uint64_t RawFlags = 0;
972972
973 RawFlags |= Flags.NotEligibleToImport; // bool
974 RawFlags |= (Flags.LiveRoot << 1);
975973 // Linkage don't need to be remapped at that time for the summary. Any future
976974 // change to the getEncodedLinkage() function will need to be taken into
977975 // account here as well.
978 RawFlags = (RawFlags << 4) | Flags.Linkage; // 4 bits
979
976 RawFlags |= Flags.Linkage; // 4 bits linkage
977 RawFlags |= (Flags.NotEligibleToImport << 4); // bool
978 RawFlags |= (Flags.LiveRoot << 5); // bool
979 RawFlags |= (Flags.AutoHide << 6); // bool
980980 return RawFlags;
981981 }
982982
202202
203203 static void thinLTOInternalizeAndPromoteGUID(
204204 GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID,
205 function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
205 function_ref<SummaryResolution(StringRef, GlobalValue::GUID)> isExported) {
206206 for (auto &S : GVSummaryList) {
207 if (isExported(S->modulePath(), GUID)) {
207 auto ExportResolution = isExported(S->modulePath(), GUID);
208 if (ExportResolution != Internal) {
208209 if (GlobalValue::isLocalLinkage(S->linkage()))
209210 S->setLinkage(GlobalValue::ExternalLinkage);
211 if (ExportResolution == Hidden)
212 S->setAutoHide();
210213 } else if (!GlobalValue::isLocalLinkage(S->linkage()))
211214 S->setLinkage(GlobalValue::InternalLinkage);
212215 }
216219 // as external and non-exported values as internal.
217220 void llvm::thinLTOInternalizeAndPromoteInIndex(
218221 ModuleSummaryIndex &Index,
219 function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
222 function_ref<SummaryResolution(StringRef, GlobalValue::GUID)> isExported) {
220223 for (auto &I : Index)
221224 thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported);
222225 }
950953 const GlobalValueSummary *S) {
951954 return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath();
952955 };
953 auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
956 auto isExported = [&](StringRef ModuleIdentifier,
957 GlobalValue::GUID GUID) -> SummaryResolution {
954958 const auto &ExportList = ExportLists.find(ModuleIdentifier);
955 return (ExportList != ExportLists.end() &&
956 ExportList->second.count(GUID)) ||
957 ExportedGUIDs.count(GUID);
959 if ((ExportList != ExportLists.end() && ExportList->second.count(GUID)) ||
960 ExportedGUIDs.count(GUID)) {
961 // We could do better by hiding when a symbol is in
962 // GUIDPreservedSymbols because it is only referenced from regular LTO
963 // or from native files and not outside the final binary, but that's
964 // something the native linker could do as gwell.
965 if (GUIDPreservedSymbols.count(GUID))
966 return Exported;
967 return Hidden;
968 }
969 return Internal;
958970 };
959971 thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
960972
233233
234234 // Convert the PreservedSymbols map from "Name" based to "GUID" based.
235235 static DenseSet
236 computeGUIDPreservedSymbols(const StringSet<> &PreservedSymbols,
237 const Triple &TheTriple) {
238 DenseSet GUIDPreservedSymbols(PreservedSymbols.size());
239 for (auto &Entry : PreservedSymbols) {
236 convertSymbolNamesToGUID(const StringSet<> &NamedSymbols,
237 const Triple &TheTriple) {
238 DenseSet GUIDSymbols(NamedSymbols.size());
239 for (auto &Entry : NamedSymbols) {
240240 StringRef Name = Entry.first();
241241 if (TheTriple.isOSBinFormatMachO() && Name.size() > 0 && Name[0] == '_')
242242 Name = Name.drop_front();
243 GUIDPreservedSymbols.insert(GlobalValue::getGUID(Name));
244 }
245 return GUIDPreservedSymbols;
243 GUIDSymbols.insert(GlobalValue::getGUID(Name));
244 }
245 return GUIDSymbols;
246246 }
247247
248248 std::unique_ptr codegenModule(Module &TheModule,
553553 }
554554
555555 void ThinLTOCodeGenerator::crossReferenceSymbol(StringRef Name) {
556 // FIXME: At the moment, we don't take advantage of this extra information,
557 // we're conservatively considering cross-references as preserved.
558 // CrossReferencedSymbols.insert(Name);
559 PreservedSymbols.insert(Name);
556 CrossReferencedSymbols.insert(Name);
560557 }
561558
562559 // TargetMachine factory
619616 Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
620617
621618 // Convert the preserved symbols set from string to GUID
622 auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(
619 auto GUIDPreservedSymbols = convertSymbolNamesToGUID(
623620 PreservedSymbols, Triple(TheModule.getTargetTriple()));
624621
625622 // Compute "dead" symbols, we don't want to import/export these!
640637
641638 // Promote the exported values in the index, so that they are promoted
642639 // in the module.
643 auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
640 auto isExported = [&](StringRef ModuleIdentifier,
641 GlobalValue::GUID GUID) -> SummaryResolution {
644642 const auto &ExportList = ExportLists.find(ModuleIdentifier);
645 return (ExportList != ExportLists.end() &&
646 ExportList->second.count(GUID)) ||
647 GUIDPreservedSymbols.count(GUID);
643 if ((ExportList != ExportLists.end() && ExportList->second.count(GUID)) ||
644 GUIDPreservedSymbols.count(GUID))
645 return Exported;
646 return Internal;
648647 };
649648 thinLTOInternalizeAndPromoteInIndex(Index, isExported);
650649
664663 Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
665664
666665 // Convert the preserved symbols set from string to GUID
667 auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(
666 auto GUIDPreservedSymbols = convertSymbolNamesToGUID(
668667 PreservedSymbols, Triple(TheModule.getTargetTriple()));
669668
670669 // Compute "dead" symbols, we don't want to import/export these!
738737
739738 // Convert the preserved symbols set from string to GUID
740739 auto GUIDPreservedSymbols =
741 computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple);
740 convertSymbolNamesToGUID(PreservedSymbols, TMBuilder.TheTriple);
742741
743742 // Collect for each module the list of function it defines (GUID -> Summary).
744743 StringMap ModuleToDefinedGVSummaries(ModuleCount);
760759 return;
761760
762761 // Internalization
763 auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
762 auto isExported = [&](StringRef ModuleIdentifier,
763 GlobalValue::GUID GUID) -> SummaryResolution {
764764 const auto &ExportList = ExportLists.find(ModuleIdentifier);
765 return (ExportList != ExportLists.end() &&
766 ExportList->second.count(GUID)) ||
767 GUIDPreservedSymbols.count(GUID);
765 if ((ExportList != ExportLists.end() && ExportList->second.count(GUID)) ||
766 GUIDPreservedSymbols.count(GUID))
767 return Exported;
768 return Internal;
768769 };
769770 thinLTOInternalizeAndPromoteInIndex(Index, isExported);
770771 thinLTOInternalizeModule(TheModule,
893894 // Convert the preserved symbols set from string to GUID, this is needed for
894895 // computing the caching hash and the internalization.
895896 auto GUIDPreservedSymbols =
896 computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple);
897 convertSymbolNamesToGUID(PreservedSymbols, TMBuilder.TheTriple);
898 auto GUIDCrossRefSymbols =
899 convertSymbolNamesToGUID(CrossReferencedSymbols, TMBuilder.TheTriple);
897900
898901 // Compute "dead" symbols, we don't want to import/export these!
899902 auto DeadSymbols = computeDeadSymbols(*Index, GUIDPreservedSymbols);
915918 // impacts the caching.
916919 resolveWeakForLinkerInIndex(*Index, ResolvedODR);
917920
918 auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
921 auto isExported = [&](StringRef ModuleIdentifier,
922 GlobalValue::GUID GUID) -> SummaryResolution {
923 if (GUIDPreservedSymbols.count(GUID))
924 return Exported;
925 if (GUIDCrossRefSymbols.count(GUID))
926 return Hidden;
919927 const auto &ExportList = ExportLists.find(ModuleIdentifier);
920 return (ExportList != ExportLists.end() &&
921 ExportList->second.count(GUID)) ||
922 GUIDPreservedSymbols.count(GUID);
928 if (ExportList != ExportLists.end() && ExportList->second.count(GUID))
929 return Hidden;
930 return Internal;
923931 };
924932
925933 // Use global summary-based analysis to identify symbols that can be
643643 return !GlobalValue::isLocalLinkage(Linkage);
644644 };
645645
646 // Try to auto-hide the symbols.
647 for (auto &GO : TheModule.global_objects()) {
648 const auto &GS = DefinedGlobals.find(GO.getGUID());
649 if (GS != DefinedGlobals.end() && GS->second->flags().AutoHide)
650 GO.setVisibility(GlobalValue::HiddenVisibility);
651 }
652
646653 // FIXME: See if we can just internalize directly here via linkage changes
647654 // based on the index, rather than invoking internalizeModule.
648655 llvm::internalizeModule(TheModule, MustPreserveGV);
0 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-apple-macosx10.11.0"
2
3 define weak_odr void @weakodrfunc() {
4 ret void
5 }
22 ; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc
33
44 ; RUN: llvm-lto -exported-symbol=_main -thinlto-action=promote %t1.bc -thinlto-index=%t.index.bc -o - | llvm-lto -exported-symbol=_main -thinlto-action=internalize -thinlto-index %t.index.bc -thinlto-module-id=%t1.bc - -o - | llvm-dis -o - | FileCheck %s
5 ; RUN: llvm-lto -exported-symbol=_main -thinlto-action=promote %t2.bc -thinlto-index=%t.index.bc -o - | llvm-lto -exported-symbol=_main -thinlto-action=internalize -thinlto-index %t.index.bc -thinlto-module-id=%t2.bc - -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK2
5 ; RUN: llvm-lto -exported-symbol=_main -thinlto-action=promote %t2.bc -thinlto-index=%t.index.bc -o - | llvm-lto -exported-symbol=_main -thinlto-action=internalize -thinlto-index %t.index.bc -thinlto-module-id=%t2.bc - -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK2-LTO
66
77 ; RUN: llvm-lto -exported-symbol=_main -thinlto-action=run %t1.bc %t2.bc
88 ; RUN: llvm-nm %t1.bc.thinlto.o | FileCheck %s --check-prefix=CHECK-NM
1818 ; RUN: -r %t2.bc,_dead_func,pl \
1919 ; RUN: -r %t2.bc,_another_dead_func,pl
2020 ; RUN: llvm-dis < %t.out.0.3.import.bc | FileCheck %s
21 ; RUN: llvm-dis < %t.out.1.3.import.bc | FileCheck %s --check-prefix=CHECK2
21 ; RUN: llvm-dis < %t.out.1.3.import.bc | FileCheck %s --check-prefix=CHECK2-LTO2
2222 ; RUN: llvm-nm %t.out.1 | FileCheck %s --check-prefix=CHECK2-NM
2323
2424 ; Dead-stripping on the index allows to internalize these,
3333
3434 ; Make sure we didn't internalize @boo, which is reachable via
3535 ; llvm.global_ctors
36 ; CHECK2: define void @boo()
36 ; CHECK2-LTO: define void @boo()
37 ; CHECK2-LTO2: define hidden void @boo()
3738 ; We should have eventually revoved @baz since it was internalized and unused
3839 ; CHECK2-NM-NOT: _baz
3940
0 ; RUN: opt -module-summary %s -o %t1.bc
1 ; RUN: opt -module-summary %p/Inputs/weak_autohide.ll -o %t2.bc
2
3 ; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
4 ; RUN: -r=%t1.bc,_strong_func,pxl \
5 ; RUN: -r=%t1.bc,_weakodrfunc,pl \
6 ; RUN: -r=%t2.bc,_weakodrfunc,l
7 ; RUN: llvm-dis < %t.o.0.2.internalize.bc | FileCheck %s --check-prefix=AUTOHIDE
8
9
10 ; AUTOHIDE: weak_odr hidden void @weakodrfunc
11
12 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
13 target triple = "x86_64-apple-macosx10.11.0"
14
15 define weak_odr void @weakodrfunc() #0 {
16 ret void
17 }
18
19 define void @strong_func() #0 {
20 call void @weakodrfunc()
21 ret void
22 }
23