llvm.org GIT mirror llvm / f284f00
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 Peter Collingbourne 2 years ago
4 changed file(s) with 60 addition(s) and 33 deletion(s). Raw diff Collapse all Expand all
10971097 ThinLTO.ModuleMap.size());
10981098 StringMap> ResolvedODR;
10991099
1100 if (Conf.OptLevel > 0) {
1100 if (Conf.OptLevel > 0)
11011101 ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
11021102 ImportLists, ExportLists);
11031103
1104 std::set ExportedGUIDs;
1105 for (auto &Res : GlobalResolutions) {
1106 // First check if the symbol was flagged as having external references.
1107 if (Res.second.Partition != GlobalResolution::External)
1108 continue;
1109 // IRName will be defined if we have seen the prevailing copy of
1110 // this value. If not, no need to mark as exported from a ThinLTO
1111 // partition (and we can't get the GUID).
1112 if (Res.second.IRName.empty())
1113 continue;
1114 auto GUID = GlobalValue::getGUID(
1115 GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
1116 // Mark exported unless index-based analysis determined it to be dead.
1117 if (ThinLTO.CombinedIndex.isGUIDLive(GUID))
1118 ExportedGUIDs.insert(GUID);
1119 }
1120
1121 // Any functions referenced by the jump table in the regular LTO object must
1122 // be exported.
1123 for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs())
1124 ExportedGUIDs.insert(
1125 GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def)));
1126
1127 auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
1128 const auto &ExportList = ExportLists.find(ModuleIdentifier);
1129 return (ExportList != ExportLists.end() &&
1130 ExportList->second.count(GUID)) ||
1131 ExportedGUIDs.count(GUID);
1132 };
1133 thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
1134 }
1104 // Figure out which symbols need to be internalized. This also needs to happen
1105 // at -O0 because summary-based DCE is implemented using internalization, and
1106 // we must apply DCE consistently with the full LTO module in order to avoid
1107 // undefined references during the final link.
1108 std::set ExportedGUIDs;
1109 for (auto &Res : GlobalResolutions) {
1110 // First check if the symbol was flagged as having external references.
1111 if (Res.second.Partition != GlobalResolution::External)
1112 continue;
1113 // IRName will be defined if we have seen the prevailing copy of
1114 // this value. If not, no need to mark as exported from a ThinLTO
1115 // partition (and we can't get the GUID).
1116 if (Res.second.IRName.empty())
1117 continue;
1118 auto GUID = GlobalValue::getGUID(
1119 GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
1120 // Mark exported unless index-based analysis determined it to be dead.
1121 if (ThinLTO.CombinedIndex.isGUIDLive(GUID))
1122 ExportedGUIDs.insert(GUID);
1123 }
1124
1125 // Any functions referenced by the jump table in the regular LTO object must
1126 // be exported.
1127 for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs())
1128 ExportedGUIDs.insert(
1129 GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def)));
1130
1131 auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
1132 const auto &ExportList = ExportLists.find(ModuleIdentifier);
1133 return (ExportList != ExportLists.end() &&
1134 ExportList->second.count(GUID)) ||
1135 ExportedGUIDs.count(GUID);
1136 };
1137 thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
11351138
11361139 auto isPrevailing = [&](GlobalValue::GUID GUID,
11371140 const GlobalValueSummary *S) {
417417 else if (GlobalExtensionsNotEmpty() || !Extensions.empty())
418418 MPM.add(createBarrierNoopPass());
419419
420 if (PerformThinLTO) {
421 // Drop available_externally and unreferenced globals. This is necessary
422 // with ThinLTO in order to avoid leaving undefined references to dead
423 // globals in the object file.
424 MPM.add(createEliminateAvailableExternallyPass());
425 MPM.add(createGlobalDCEPass());
426 }
427
420428 addExtensionsToPM(EP_EnabledOnOptLevel0, MPM);
421429
422430 // Rename anon globals to be able to export them in the summary.
1313 }
1414
1515 declare void @dead2()
16
17 define linkonce_odr i8* @odr() {
18 ret i8* bitcast (void ()* @dead3 to i8*)
19 }
20
21 define internal void @dead3() {
22 ret void
23 }
0 ; RUN: opt -module-summary -o %t %s
11 ; RUN: opt -module-summary -o %t2 %S/Inputs/dead-strip-fulllto.ll
2
23 ; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \
3 ; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, \
4 ; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, -r %t2,odr, \
45 ; RUN: -save-temps -o %t3
6 ; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s
7 ; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s
8
9 ; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \
10 ; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, -r %t2,odr, \
11 ; RUN: -save-temps -o %t3 -O0
512 ; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s
613 ; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s
714
1320 ; THIN-NOT: dead
1421 ; THIN: T live1
1522 ; THIN: U live2
23 ; THIN-NOT: odr
1624
1725 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1826 target triple = "x86_64-unknown-linux-gnu"