summaryrefslogtreecommitdiff
path: root/lib/LTO/LTO.cpp
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2017-11-01 17:58:39 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2017-11-01 17:58:39 +0000
commitf284f00fe090463d4d64151585be85ba72cc38ec (patch)
treec04c5331556049934220092c0d98d6a889d011d1 /lib/LTO/LTO.cpp
parentfa81b6ba937a76f7d05c224ec5ae20099734c052 (diff)
LTO: Apply global DCE to ThinLTO modules at LTO opt level 0.
This is necessary because DCE is applied to full LTO modules. Without this change, a reference from a dead ThinLTO global to a dead full LTO global will result in an undefined reference at link time. This problem is only observable when --gc-sections is disabled, or when targeting COFF, as the COFF port of lld requires all symbols to have a definition even if all references are dead (this is consistent with link.exe). This change also adds an EliminateAvailableExternally pass at -O0. This is necessary to handle the situation on Windows where a non-prevailing copy of a linkonce_odr function has an SEH filter function; any such filters must be DCE'd because they will contain a call to the llvm.localrecover intrinsic, passing as an argument the address of the function that the filter belongs to, and llvm.localrecover requires this function to be defined locally. Fixes PR35142. Differential Revision: https://reviews.llvm.org/D39484 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317108 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/LTO/LTO.cpp')
-rw-r--r--lib/LTO/LTO.cpp65
1 files changed, 34 insertions, 31 deletions
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp
index 4fb36e7998e..017dd201f9c 100644
--- a/lib/LTO/LTO.cpp
+++ b/lib/LTO/LTO.cpp
@@ -1098,42 +1098,45 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
ThinLTO.ModuleMap.size());
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
- if (Conf.OptLevel > 0) {
+ if (Conf.OptLevel > 0)
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
ImportLists, ExportLists);
- std::set<GlobalValue::GUID> ExportedGUIDs;
- for (auto &Res : GlobalResolutions) {
- // First check if the symbol was flagged as having external references.
- if (Res.second.Partition != GlobalResolution::External)
- continue;
- // IRName will be defined if we have seen the prevailing copy of
- // this value. If not, no need to mark as exported from a ThinLTO
- // partition (and we can't get the GUID).
- if (Res.second.IRName.empty())
- continue;
- auto GUID = GlobalValue::getGUID(
- GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
- // Mark exported unless index-based analysis determined it to be dead.
- if (ThinLTO.CombinedIndex.isGUIDLive(GUID))
- ExportedGUIDs.insert(GUID);
- }
-
- // Any functions referenced by the jump table in the regular LTO object must
- // be exported.
- for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs())
- ExportedGUIDs.insert(
- GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def)));
-
- auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
- const auto &ExportList = ExportLists.find(ModuleIdentifier);
- return (ExportList != ExportLists.end() &&
- ExportList->second.count(GUID)) ||
- ExportedGUIDs.count(GUID);
- };
- thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
+ // Figure out which symbols need to be internalized. This also needs to happen
+ // at -O0 because summary-based DCE is implemented using internalization, and
+ // we must apply DCE consistently with the full LTO module in order to avoid
+ // undefined references during the final link.
+ std::set<GlobalValue::GUID> ExportedGUIDs;
+ for (auto &Res : GlobalResolutions) {
+ // First check if the symbol was flagged as having external references.
+ if (Res.second.Partition != GlobalResolution::External)
+ continue;
+ // IRName will be defined if we have seen the prevailing copy of
+ // this value. If not, no need to mark as exported from a ThinLTO
+ // partition (and we can't get the GUID).
+ if (Res.second.IRName.empty())
+ continue;
+ auto GUID = GlobalValue::getGUID(
+ GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
+ // Mark exported unless index-based analysis determined it to be dead.
+ if (ThinLTO.CombinedIndex.isGUIDLive(GUID))
+ ExportedGUIDs.insert(GUID);
}
+ // Any functions referenced by the jump table in the regular LTO object must
+ // be exported.
+ for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs())
+ ExportedGUIDs.insert(
+ GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def)));
+
+ auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
+ const auto &ExportList = ExportLists.find(ModuleIdentifier);
+ return (ExportList != ExportLists.end() &&
+ ExportList->second.count(GUID)) ||
+ ExportedGUIDs.count(GUID);
+ };
+ thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
+
auto isPrevailing = [&](GlobalValue::GUID GUID,
const GlobalValueSummary *S) {
return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath();