summaryrefslogtreecommitdiff
path: root/lib/LTO/LTO.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/LTO/LTO.cpp
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/LTO/LTO.cpp')
-rw-r--r--lib/LTO/LTO.cpp158
1 files changed, 109 insertions, 49 deletions
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp
index 64e5186255bd..68d210cb7d73 100644
--- a/lib/LTO/LTO.cpp
+++ b/lib/LTO/LTO.cpp
@@ -12,11 +12,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/LTO/LTO.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/Analysis.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LegacyPassManager.h"
@@ -50,6 +52,10 @@ using namespace object;
#define DEBUG_TYPE "lto"
+static cl::opt<bool>
+ DumpThinCGSCCs("dump-thin-cg-sccs", cl::init(false), cl::Hidden,
+ cl::desc("Dump the SCCs in the ThinLTO index's callgraph"));
+
// The values are (type identifier, summary) pairs.
typedef DenseMap<
GlobalValue::GUID,
@@ -132,6 +138,7 @@ static void computeCacheKey(
AddString(Conf.AAPipeline);
AddString(Conf.OverrideTriple);
AddString(Conf.DefaultTriple);
+ AddString(Conf.DwoDir);
// Include the hash for the current module
auto ModHash = Index.getModuleHash(ModuleID);
@@ -149,7 +156,7 @@ static void computeCacheKey(
AddUint64(Entry.second.size());
for (auto &Fn : Entry.second)
- AddUint64(Fn.first);
+ AddUint64(Fn);
}
// Include the hash for the resolved ODR.
@@ -177,8 +184,11 @@ static void computeCacheKey(
auto AddUsedThings = [&](GlobalValueSummary *GS) {
if (!GS) return;
- for (const ValueInfo &VI : GS->refs())
+ AddUnsigned(GS->isLive());
+ for (const ValueInfo &VI : GS->refs()) {
+ AddUnsigned(VI.isDSOLocal());
AddUsedCfiGlobal(VI.getGUID());
+ }
if (auto *FS = dyn_cast<FunctionSummary>(GS)) {
for (auto &TT : FS->type_tests())
UsedTypeIds.insert(TT);
@@ -190,8 +200,10 @@ static void computeCacheKey(
UsedTypeIds.insert(TT.VFunc.GUID);
for (auto &TT : FS->type_checked_load_const_vcalls())
UsedTypeIds.insert(TT.VFunc.GUID);
- for (auto &ET : FS->calls())
+ for (auto &ET : FS->calls()) {
+ AddUnsigned(ET.first.isDSOLocal());
AddUsedCfiGlobal(ET.first.getGUID());
+ }
}
};
@@ -209,7 +221,7 @@ static void computeCacheKey(
// so we need to collect their used resolutions as well.
for (auto &ImpM : ImportList)
for (auto &ImpF : ImpM.second)
- AddUsedThings(Index.findSummaryInModule(ImpF.first, ImpM.first()));
+ AddUsedThings(Index.findSummaryInModule(ImpF, ImpM.first()));
auto AddTypeIdSummary = [&](StringRef TId, const TypeIdSummary &S) {
AddString(TId);
@@ -388,7 +400,8 @@ LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel,
Ctx(Conf), CombinedModule(llvm::make_unique<Module>("ld-temp.o", Ctx)),
Mover(llvm::make_unique<IRMover>(*CombinedModule)) {}
-LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) : Backend(Backend) {
+LTO::ThinLTOState::ThinLTOState(ThinBackend Backend)
+ : Backend(Backend), CombinedIndex(/*HaveGVs*/ false) {
if (!Backend)
this->Backend =
createInProcessThinBackend(llvm::heavyweight_hardware_concurrency());
@@ -415,11 +428,27 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
- auto &GlobalRes = GlobalResolutions[Sym.getName()];
+ StringRef Name = Sym.getName();
+ Triple TT(RegularLTO.CombinedModule->getTargetTriple());
+ // Strip the __imp_ prefix from COFF dllimport symbols (similar to the
+ // way they are handled by lld), otherwise we can end up with two
+ // global resolutions (one with and one for a copy of the symbol without).
+ if (TT.isOSBinFormatCOFF() && Name.startswith("__imp_"))
+ Name = Name.substr(strlen("__imp_"));
+ auto &GlobalRes = GlobalResolutions[Name];
GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
if (Res.Prevailing) {
- assert(GlobalRes.IRName.empty() &&
+ assert(!GlobalRes.Prevailing &&
"Multiple prevailing defs are not allowed");
+ GlobalRes.Prevailing = true;
+ GlobalRes.IRName = Sym.getIRName();
+ } else if (!GlobalRes.Prevailing && GlobalRes.IRName.empty()) {
+ // Sometimes it can be two copies of symbol in a module and prevailing
+ // symbol can have no IR name. That might happen if symbol is defined in
+ // module level inline asm block. In case we have multiple modules with
+ // the same symbol we want to use IR name of the prevailing symbol.
+ // Otherwise, if we haven't seen a prevailing symbol, set the name so that
+ // we can later use it to check if there is any prevailing copy in IR.
GlobalRes.IRName = Sym.getIRName();
}
@@ -639,7 +668,8 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
}
// Set the 'local' flag based on the linker resolution for this symbol.
- GV->setDSOLocal(Res.FinalDefinitionInLinkageUnit);
+ if (Res.FinalDefinitionInLinkageUnit)
+ GV->setDSOLocal(true);
}
// Common resolution: collect the maximum size/alignment over all commons.
// We also record if we see an instance of a common as prevailing, so that
@@ -744,20 +774,52 @@ unsigned LTO::getMaxTasks() const {
Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
// Compute "dead" symbols, we don't want to import/export these!
DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
+ DenseMap<GlobalValue::GUID, PrevailingType> GUIDPrevailingResolutions;
for (auto &Res : GlobalResolutions) {
- if (Res.second.VisibleOutsideSummary &&
- // IRName will be defined if we have seen the prevailing copy of
- // this value. If not, no need to preserve any ThinLTO copies.
- !Res.second.IRName.empty())
+ // Normally resolution have IR name of symbol. We can do nothing here
+ // otherwise. See comments in GlobalResolution struct for more details.
+ if (Res.second.IRName.empty())
+ continue;
+
+ GlobalValue::GUID GUID = GlobalValue::getGUID(
+ GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
+
+ if (Res.second.VisibleOutsideSummary && Res.second.Prevailing)
GUIDPreservedSymbols.insert(GlobalValue::getGUID(
GlobalValue::dropLLVMManglingEscape(Res.second.IRName)));
+
+ GUIDPrevailingResolutions[GUID] =
+ Res.second.Prevailing ? PrevailingType::Yes : PrevailingType::No;
+ }
+
+ auto isPrevailing = [&](GlobalValue::GUID G) {
+ auto It = GUIDPrevailingResolutions.find(G);
+ if (It == GUIDPrevailingResolutions.end())
+ return PrevailingType::Unknown;
+ return It->second;
+ };
+ computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols, isPrevailing);
+
+ // Setup output file to emit statistics.
+ std::unique_ptr<ToolOutputFile> StatsFile = nullptr;
+ if (!Conf.StatsFile.empty()) {
+ EnableStatistics(false);
+ std::error_code EC;
+ StatsFile =
+ llvm::make_unique<ToolOutputFile>(Conf.StatsFile, EC, sys::fs::F_None);
+ if (EC)
+ return errorCodeToError(EC);
+ StatsFile->keep();
}
- computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
+ Error Result = runRegularLTO(AddStream);
+ if (!Result)
+ Result = runThinLTO(AddStream, Cache);
+
+ if (StatsFile)
+ PrintStatisticsJSON(StatsFile->os());
- if (auto E = runRegularLTO(AddStream))
- return E;
- return runThinLTO(AddStream, Cache);
+ return Result;
}
Error LTO::runRegularLTO(AddStreamFn AddStream) {
@@ -801,7 +863,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
if (!Conf.CodeGenOnly) {
for (const auto &R : GlobalResolutions) {
- if (R.second.IRName.empty())
+ if (!R.second.isPrevailingIRSymbol())
continue;
if (R.second.Partition != 0 &&
R.second.Partition != GlobalResolution::External)
@@ -810,7 +872,8 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
GlobalValue *GV =
RegularLTO.CombinedModule->getNamedValue(R.second.IRName);
// Ignore symbols defined in other partitions.
- if (!GV || GV->hasLocalLinkage())
+ // Also skip declarations, which are not allowed to have internal linkage.
+ if (!GV || GV->hasLocalLinkage() || GV->isDeclaration())
continue;
GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global
: GlobalValue::UnnamedAddr::None);
@@ -1003,20 +1066,19 @@ namespace {
class WriteIndexesThinBackend : public ThinBackendProc {
std::string OldPrefix, NewPrefix;
bool ShouldEmitImportsFiles;
-
- std::string LinkedObjectsFileName;
- std::unique_ptr<llvm::raw_fd_ostream> LinkedObjectsFile;
+ raw_fd_ostream *LinkedObjectsFile;
+ lto::IndexWriteCallback OnWrite;
public:
WriteIndexesThinBackend(
Config &Conf, ModuleSummaryIndex &CombinedIndex,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
std::string OldPrefix, std::string NewPrefix, bool ShouldEmitImportsFiles,
- std::string LinkedObjectsFileName)
+ raw_fd_ostream *LinkedObjectsFile, lto::IndexWriteCallback OnWrite)
: ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries),
OldPrefix(OldPrefix), NewPrefix(NewPrefix),
ShouldEmitImportsFiles(ShouldEmitImportsFiles),
- LinkedObjectsFileName(LinkedObjectsFileName) {}
+ LinkedObjectsFile(LinkedObjectsFile), OnWrite(OnWrite) {}
Error start(
unsigned Task, BitcodeModule BM,
@@ -1028,30 +1090,29 @@ public:
std::string NewModulePath =
getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix);
- std::error_code EC;
- if (!LinkedObjectsFileName.empty()) {
- if (!LinkedObjectsFile) {
- LinkedObjectsFile = llvm::make_unique<raw_fd_ostream>(
- LinkedObjectsFileName, EC, sys::fs::OpenFlags::F_None);
- if (EC)
- return errorCodeToError(EC);
- }
+ if (LinkedObjectsFile)
*LinkedObjectsFile << NewModulePath << '\n';
- }
std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries,
ImportList, ModuleToSummariesForIndex);
+ std::error_code EC;
raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC,
sys::fs::OpenFlags::F_None);
if (EC)
return errorCodeToError(EC);
WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex);
- if (ShouldEmitImportsFiles)
- return errorCodeToError(
- EmitImportsFiles(ModulePath, NewModulePath + ".imports", ImportList));
+ if (ShouldEmitImportsFiles) {
+ EC = EmitImportsFiles(ModulePath, NewModulePath + ".imports",
+ ModuleToSummariesForIndex);
+ if (EC)
+ return errorCodeToError(EC);
+ }
+
+ if (OnWrite)
+ OnWrite(ModulePath);
return Error::success();
}
@@ -1059,16 +1120,15 @@ public:
};
} // end anonymous namespace
-ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix,
- std::string NewPrefix,
- bool ShouldEmitImportsFiles,
- std::string LinkedObjectsFile) {
+ThinBackend lto::createWriteIndexesThinBackend(
+ std::string OldPrefix, std::string NewPrefix, bool ShouldEmitImportsFiles,
+ raw_fd_ostream *LinkedObjectsFile, IndexWriteCallback OnWrite) {
return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, NativeObjectCache Cache) {
return llvm::make_unique<WriteIndexesThinBackend>(
Conf, CombinedIndex, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix,
- ShouldEmitImportsFiles, LinkedObjectsFile);
+ ShouldEmitImportsFiles, LinkedObjectsFile, OnWrite);
};
}
@@ -1102,6 +1162,9 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) {
ThinLTO.ModuleMap.size());
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
+ if (DumpThinCGSCCs)
+ ThinLTO.CombinedIndex.dumpSCCs(outs());
+
if (Conf.OptLevel > 0)
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
ImportLists, ExportLists);
@@ -1112,13 +1175,10 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) {
// 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())
+ // If the symbol does not have external references or it is not prevailing,
+ // then not need to mark it as exported from a ThinLTO partition.
+ if (Res.second.Partition != GlobalResolution::External ||
+ !Res.second.isPrevailingIRSymbol())
continue;
auto GUID = GlobalValue::getGUID(
GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
@@ -1175,6 +1235,8 @@ Expected<std::unique_ptr<ToolOutputFile>>
lto::setupOptimizationRemarks(LLVMContext &Context,
StringRef LTORemarksFilename,
bool LTOPassRemarksWithHotness, int Count) {
+ if (LTOPassRemarksWithHotness)
+ Context.setDiagnosticsHotnessRequested(true);
if (LTORemarksFilename.empty())
return nullptr;
@@ -1189,8 +1251,6 @@ lto::setupOptimizationRemarks(LLVMContext &Context,
return errorCodeToError(EC);
Context.setDiagnosticsOutputFile(
llvm::make_unique<yaml::Output>(DiagnosticFile->os()));
- if (LTOPassRemarksWithHotness)
- Context.setDiagnosticsHotnessRequested(true);
DiagnosticFile->keep();
return std::move(DiagnosticFile);
}