17c4a1a8dSMehdi Amini //===-ThinLTOCodeGenerator.cpp - LLVM Link Time Optimizer -----------------===//
27c4a1a8dSMehdi Amini //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67c4a1a8dSMehdi Amini //
77c4a1a8dSMehdi Amini //===----------------------------------------------------------------------===//
87c4a1a8dSMehdi Amini //
97c4a1a8dSMehdi Amini // This file implements the Thin Link Time Optimization library. This library is
107c4a1a8dSMehdi Amini // intended to be used by linker to optimize code at link time.
117c4a1a8dSMehdi Amini //
127c4a1a8dSMehdi Amini //===----------------------------------------------------------------------===//
137c4a1a8dSMehdi Amini
145c73220fSPeter Collingbourne #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
154c1a1d3cSReid Kleckner #include "llvm/Support/CommandLine.h"
167c4a1a8dSMehdi Amini
17f5b8a312Smodimo #include "llvm/ADT/ScopeExit.h"
18cec0cae3STeresa Johnson #include "llvm/ADT/Statistic.h"
1926ab5772STeresa Johnson #include "llvm/ADT/StringExtras.h"
20e978f6bcSFlorian Hahn #include "llvm/Analysis/AliasAnalysis.h"
21384ca190SMehdi Amini #include "llvm/Analysis/ModuleSummaryAnalysis.h"
22d9830eb7SPiotr Padlewski #include "llvm/Analysis/ProfileSummaryInfo.h"
237c4a1a8dSMehdi Amini #include "llvm/Analysis/TargetLibraryInfo.h"
24ad17679aSTeresa Johnson #include "llvm/Bitcode/BitcodeReader.h"
25ad17679aSTeresa Johnson #include "llvm/Bitcode/BitcodeWriter.h"
26cec0cae3STeresa Johnson #include "llvm/Bitcode/BitcodeWriterPass.h"
27432a3883SNico Weber #include "llvm/Config/llvm-config.h"
28981a7998SAdrian Prantl #include "llvm/IR/DebugInfo.h"
296bda14b3SChandler Carruth #include "llvm/IR/DiagnosticPrinter.h"
30fa5a4e1bSserge-sans-paille #include "llvm/IR/LegacyPassManager.h"
3126ab5772STeresa Johnson #include "llvm/IR/LLVMContext.h"
327531a503SFrancis Visoiu Mistrih #include "llvm/IR/LLVMRemarkStreamer.h"
337c4a1a8dSMehdi Amini #include "llvm/IR/Mangler.h"
34a43fd952SFedor Sergeev #include "llvm/IR/PassTimingInfo.h"
35981a7998SAdrian Prantl #include "llvm/IR/Verifier.h"
367c4a1a8dSMehdi Amini #include "llvm/IRReader/IRReader.h"
37df6edc52STeresa Johnson #include "llvm/LTO/LTO.h"
385a7056faSEaswaran Raman #include "llvm/LTO/SummaryBasedOptimizations.h"
397c4a1a8dSMehdi Amini #include "llvm/MC/SubtargetFeature.h"
4089b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
41059464feSMehdi Amini #include "llvm/Object/IRObjectFile.h"
42e978f6bcSFlorian Hahn #include "llvm/Passes/PassBuilder.h"
43e978f6bcSFlorian Hahn #include "llvm/Passes/StandardInstrumentations.h"
443acda917SWei Wang #include "llvm/Remarks/HotnessThresholdParser.h"
45f95f77adSMehdi Amini #include "llvm/Support/CachePruning.h"
46f95f77adSMehdi Amini #include "llvm/Support/Debug.h"
4719f176b9SMehdi Amini #include "llvm/Support/Error.h"
48f69c9178SJan Korous #include "llvm/Support/FileUtilities.h"
49f95f77adSMehdi Amini #include "llvm/Support/Path.h"
50f95f77adSMehdi Amini #include "llvm/Support/SHA1.h"
5179f2d093SWeiming Zhao #include "llvm/Support/SmallVectorMemoryBuffer.h"
527c4a1a8dSMehdi Amini #include "llvm/Support/ThreadPool.h"
53ec544c55STeresa Johnson #include "llvm/Support/Threading.h"
5419f176b9SMehdi Amini #include "llvm/Support/ToolOutputFile.h"
557c4a1a8dSMehdi Amini #include "llvm/Target/TargetMachine.h"
5620faf789Smodimo #include "llvm/Transforms/IPO/FunctionAttrs.h"
577c4a1a8dSMehdi Amini #include "llvm/Transforms/IPO/FunctionImport.h"
58059464feSMehdi Amini #include "llvm/Transforms/IPO/Internalize.h"
59eb34c3e8SEugene Leviant #include "llvm/Transforms/IPO/WholeProgramDevirt.h"
607c4a1a8dSMehdi Amini #include "llvm/Transforms/ObjCARC.h"
617c4a1a8dSMehdi Amini #include "llvm/Transforms/Utils/FunctionImportUtils.h"
627c4a1a8dSMehdi Amini
63819e9cdfSMehdi Amini #include <numeric>
64819e9cdfSMehdi Amini
65089303d8SAndrew Ng #if !defined(_MSC_VER) && !defined(__MINGW32__)
66089303d8SAndrew Ng #include <unistd.h>
67089303d8SAndrew Ng #else
68089303d8SAndrew Ng #include <io.h>
69089303d8SAndrew Ng #endif
70089303d8SAndrew Ng
717c4a1a8dSMehdi Amini using namespace llvm;
727c4a1a8dSMehdi Amini
731aafabf7SMehdi Amini #define DEBUG_TYPE "thinlto"
741aafabf7SMehdi Amini
7509b4a8daSMehdi Amini namespace llvm {
7609b4a8daSMehdi Amini // Flags -discard-value-names, defined in LTOCodeGenerator.cpp
7709b4a8daSMehdi Amini extern cl::opt<bool> LTODiscardValueNames;
787a21113cSFrancis Visoiu Mistrih extern cl::opt<std::string> RemarksFilename;
797a21113cSFrancis Visoiu Mistrih extern cl::opt<std::string> RemarksPasses;
807a21113cSFrancis Visoiu Mistrih extern cl::opt<bool> RemarksWithHotness;
813acda917SWei Wang extern cl::opt<Optional<uint64_t>, false, remarks::HotnessThresholdParser>
823acda917SWei Wang RemarksHotnessThreshold;
8334667519SFrancis Visoiu Mistrih extern cl::opt<std::string> RemarksFormat;
8409b4a8daSMehdi Amini }
8509b4a8daSMehdi Amini
867c4a1a8dSMehdi Amini namespace {
877c4a1a8dSMehdi Amini
886f846c85SAlexandre Ganea // Default to using all available threads in the system, but using only one
896f846c85SAlexandre Ganea // thred per core, as indicated by the usage of
906f846c85SAlexandre Ganea // heavyweight_hardware_concurrency() below.
918404aeb5SAlexandre Ganea static cl::opt<int> ThreadCount("threads", cl::init(0));
927c4a1a8dSMehdi Amini
937c4a1a8dSMehdi Amini // Simple helper to save temporary files for debug.
saveTempBitcode(const Module & TheModule,StringRef TempDir,unsigned count,StringRef Suffix)947c4a1a8dSMehdi Amini static void saveTempBitcode(const Module &TheModule, StringRef TempDir,
957c4a1a8dSMehdi Amini unsigned count, StringRef Suffix) {
967c4a1a8dSMehdi Amini if (TempDir.empty())
977c4a1a8dSMehdi Amini return;
987c4a1a8dSMehdi Amini // User asked to save temps, let dump the bitcode file after import.
993a13ed60SBenjamin Kramer std::string SaveTempPath = (TempDir + llvm::Twine(count) + Suffix).str();
1007c4a1a8dSMehdi Amini std::error_code EC;
101d9b948b6SFangrui Song raw_fd_ostream OS(SaveTempPath, EC, sys::fs::OF_None);
1027c4a1a8dSMehdi Amini if (EC)
1037c4a1a8dSMehdi Amini report_fatal_error(Twine("Failed to open ") + SaveTempPath +
1047c4a1a8dSMehdi Amini " to save optimized bitcode\n");
1056a86e25dSRafael Espindola WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true);
1067c4a1a8dSMehdi Amini }
1077c4a1a8dSMehdi Amini
1084d2613f2STeresa Johnson static const GlobalValueSummary *
getFirstDefinitionForLinker(const GlobalValueSummaryList & GVSummaryList)1094d2613f2STeresa Johnson getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) {
1104d2613f2STeresa Johnson // If there is any strong definition anywhere, get it.
1114d2613f2STeresa Johnson auto StrongDefForLinker = llvm::find_if(
1124d2613f2STeresa Johnson GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
1134d2613f2STeresa Johnson auto Linkage = Summary->linkage();
1144d2613f2STeresa Johnson return !GlobalValue::isAvailableExternallyLinkage(Linkage) &&
1154d2613f2STeresa Johnson !GlobalValue::isWeakForLinker(Linkage);
1164d2613f2STeresa Johnson });
1174d2613f2STeresa Johnson if (StrongDefForLinker != GVSummaryList.end())
1184d2613f2STeresa Johnson return StrongDefForLinker->get();
1195a2e5d32SMehdi Amini // Get the first *linker visible* definition for this global in the summary
1205a2e5d32SMehdi Amini // list.
1215a2e5d32SMehdi Amini auto FirstDefForLinker = llvm::find_if(
12228e457bcSTeresa Johnson GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
12328e457bcSTeresa Johnson auto Linkage = Summary->linkage();
1245a2e5d32SMehdi Amini return !GlobalValue::isAvailableExternallyLinkage(Linkage);
1255a2e5d32SMehdi Amini });
1264d2613f2STeresa Johnson // Extern templates can be emitted as available_externally.
1274d2613f2STeresa Johnson if (FirstDefForLinker == GVSummaryList.end())
1284d2613f2STeresa Johnson return nullptr;
1294d2613f2STeresa Johnson return FirstDefForLinker->get();
130fa6e414eSHans Wennborg }
1315a2e5d32SMehdi Amini
1324d2613f2STeresa Johnson // Populate map of GUID to the prevailing copy for any multiply defined
1334d2613f2STeresa Johnson // symbols. Currently assume first copy is prevailing, or any strong
1344d2613f2STeresa Johnson // definition. Can be refined with Linker information in the future.
computePrevailingCopies(const ModuleSummaryIndex & Index,DenseMap<GlobalValue::GUID,const GlobalValueSummary * > & PrevailingCopy)1354d2613f2STeresa Johnson static void computePrevailingCopies(
1364d2613f2STeresa Johnson const ModuleSummaryIndex &Index,
1374d2613f2STeresa Johnson DenseMap<GlobalValue::GUID, const GlobalValueSummary *> &PrevailingCopy) {
13828e457bcSTeresa Johnson auto HasMultipleCopies = [&](const GlobalValueSummaryList &GVSummaryList) {
13928e457bcSTeresa Johnson return GVSummaryList.size() > 1;
14028e457bcSTeresa Johnson };
1415a2e5d32SMehdi Amini
1424d2613f2STeresa Johnson for (auto &I : Index) {
1439667b91bSPeter Collingbourne if (HasMultipleCopies(I.second.SummaryList))
1449667b91bSPeter Collingbourne PrevailingCopy[I.first] =
1459667b91bSPeter Collingbourne getFirstDefinitionForLinker(I.second.SummaryList);
146a71a5a62SMehdi Amini }
1475a2e5d32SMehdi Amini }
1485a2e5d32SMehdi Amini
14905a358cdSSteven Wu static StringMap<lto::InputFile *>
generateModuleMap(std::vector<std::unique_ptr<lto::InputFile>> & Modules)15005a358cdSSteven Wu generateModuleMap(std::vector<std::unique_ptr<lto::InputFile>> &Modules) {
15105a358cdSSteven Wu StringMap<lto::InputFile *> ModuleMap;
15205a358cdSSteven Wu for (auto &M : Modules) {
15305a358cdSSteven Wu assert(ModuleMap.find(M->getName()) == ModuleMap.end() &&
1547c4a1a8dSMehdi Amini "Expect unique Buffer Identifier");
15505a358cdSSteven Wu ModuleMap[M->getName()] = M.get();
1567c4a1a8dSMehdi Amini }
1577c4a1a8dSMehdi Amini return ModuleMap;
1587c4a1a8dSMehdi Amini }
1597c4a1a8dSMehdi Amini
promoteModule(Module & TheModule,const ModuleSummaryIndex & Index,bool ClearDSOLocalOnDeclarations)160d2ef8c1fSFangrui Song static void promoteModule(Module &TheModule, const ModuleSummaryIndex &Index,
161d2ef8c1fSFangrui Song bool ClearDSOLocalOnDeclarations) {
162d2ef8c1fSFangrui Song if (renameModuleForThinLTO(TheModule, Index, ClearDSOLocalOnDeclarations))
1637c4a1a8dSMehdi Amini report_fatal_error("renameModuleForThinLTO failed");
1647c4a1a8dSMehdi Amini }
1657c4a1a8dSMehdi Amini
166981a7998SAdrian Prantl namespace {
167981a7998SAdrian Prantl class ThinLTODiagnosticInfo : public DiagnosticInfo {
168981a7998SAdrian Prantl const Twine &Msg;
169981a7998SAdrian Prantl public:
ThinLTODiagnosticInfo(const Twine & DiagMsg,DiagnosticSeverity Severity=DS_Error)170981a7998SAdrian Prantl ThinLTODiagnosticInfo(const Twine &DiagMsg,
171981a7998SAdrian Prantl DiagnosticSeverity Severity = DS_Error)
172981a7998SAdrian Prantl : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}
print(DiagnosticPrinter & DP) const173981a7998SAdrian Prantl void print(DiagnosticPrinter &DP) const override { DP << Msg; }
174981a7998SAdrian Prantl };
175981a7998SAdrian Prantl }
176981a7998SAdrian Prantl
177981a7998SAdrian Prantl /// Verify the module and strip broken debug info.
verifyLoadedModule(Module & TheModule)178981a7998SAdrian Prantl static void verifyLoadedModule(Module &TheModule) {
179981a7998SAdrian Prantl bool BrokenDebugInfo = false;
180a8b2ddbdSAdrian Prantl if (verifyModule(TheModule, &dbgs(), &BrokenDebugInfo))
181981a7998SAdrian Prantl report_fatal_error("Broken module found, compilation aborted!");
182981a7998SAdrian Prantl if (BrokenDebugInfo) {
183981a7998SAdrian Prantl TheModule.getContext().diagnose(ThinLTODiagnosticInfo(
184981a7998SAdrian Prantl "Invalid debug info found, debug info will be stripped", DS_Warning));
185981a7998SAdrian Prantl StripDebugInfo(TheModule);
186981a7998SAdrian Prantl }
187981a7998SAdrian Prantl }
188981a7998SAdrian Prantl
loadModuleFromInput(lto::InputFile * Input,LLVMContext & Context,bool Lazy,bool IsImporting)18905a358cdSSteven Wu static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile *Input,
19005a358cdSSteven Wu LLVMContext &Context,
19105a358cdSSteven Wu bool Lazy,
19205a358cdSSteven Wu bool IsImporting) {
19305a358cdSSteven Wu auto &Mod = Input->getSingleBitcodeModule();
194dac43b49SPeter Collingbourne SMDiagnostic Err;
195dac43b49SPeter Collingbourne Expected<std::unique_ptr<Module>> ModuleOrErr =
19605a358cdSSteven Wu Lazy ? Mod.getLazyModule(Context,
197a61f5e37STeresa Johnson /* ShouldLazyLoadMetadata */ true, IsImporting)
19805a358cdSSteven Wu : Mod.parseModule(Context);
199dac43b49SPeter Collingbourne if (!ModuleOrErr) {
200dac43b49SPeter Collingbourne handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
20105a358cdSSteven Wu SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
202dac43b49SPeter Collingbourne SourceMgr::DK_Error, EIB.message());
203dac43b49SPeter Collingbourne Err.print("ThinLTO", errs());
204dac43b49SPeter Collingbourne });
205dac43b49SPeter Collingbourne report_fatal_error("Can't load module, abort.");
206dac43b49SPeter Collingbourne }
207981a7998SAdrian Prantl if (!Lazy)
208981a7998SAdrian Prantl verifyLoadedModule(*ModuleOrErr.get());
20905a358cdSSteven Wu return std::move(*ModuleOrErr);
210dac43b49SPeter Collingbourne }
211dac43b49SPeter Collingbourne
21201e32130SMehdi Amini static void
crossImportIntoModule(Module & TheModule,const ModuleSummaryIndex & Index,StringMap<lto::InputFile * > & ModuleMap,const FunctionImporter::ImportMapTy & ImportList,bool ClearDSOLocalOnDeclarations)21301e32130SMehdi Amini crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index,
21405a358cdSSteven Wu StringMap<lto::InputFile *> &ModuleMap,
215d2ef8c1fSFangrui Song const FunctionImporter::ImportMapTy &ImportList,
216d2ef8c1fSFangrui Song bool ClearDSOLocalOnDeclarations) {
217dac43b49SPeter Collingbourne auto Loader = [&](StringRef Identifier) {
21805a358cdSSteven Wu auto &Input = ModuleMap[Identifier];
21905a358cdSSteven Wu return loadModuleFromInput(Input, TheModule.getContext(),
220a61f5e37STeresa Johnson /*Lazy=*/true, /*IsImporting*/ true);
221dac43b49SPeter Collingbourne };
222dac43b49SPeter Collingbourne
223d2ef8c1fSFangrui Song FunctionImporter Importer(Index, Loader, ClearDSOLocalOnDeclarations);
22466043797SAdrian Prantl Expected<bool> Result = Importer.importFunctions(TheModule, ImportList);
22583a807ebSMehdi Amini if (!Result) {
22683a807ebSMehdi Amini handleAllErrors(Result.takeError(), [&](ErrorInfoBase &EIB) {
22783a807ebSMehdi Amini SMDiagnostic Err = SMDiagnostic(TheModule.getModuleIdentifier(),
22883a807ebSMehdi Amini SourceMgr::DK_Error, EIB.message());
22983a807ebSMehdi Amini Err.print("ThinLTO", errs());
23083a807ebSMehdi Amini });
2317f00d0a1SPeter Collingbourne report_fatal_error("importFunctions failed");
2327c4a1a8dSMehdi Amini }
233981a7998SAdrian Prantl // Verify again after cross-importing.
234981a7998SAdrian Prantl verifyLoadedModule(TheModule);
23583a807ebSMehdi Amini }
2367c4a1a8dSMehdi Amini
optimizeModule(Module & TheModule,TargetMachine & TM,unsigned OptLevel,bool Freestanding,bool DebugPassManager,ModuleSummaryIndex * Index)237cc7fbf71SMehdi Amini static void optimizeModule(Module &TheModule, TargetMachine &TM,
238eb34c3e8SEugene Leviant unsigned OptLevel, bool Freestanding,
239ceadf6eeSNikita Popov bool DebugPassManager, ModuleSummaryIndex *Index) {
240e978f6bcSFlorian Hahn Optional<PGOOptions> PGOOpt;
241e978f6bcSFlorian Hahn LoopAnalysisManager LAM;
242e978f6bcSFlorian Hahn FunctionAnalysisManager FAM;
243e978f6bcSFlorian Hahn CGSCCAnalysisManager CGAM;
244e978f6bcSFlorian Hahn ModuleAnalysisManager MAM;
245e978f6bcSFlorian Hahn
246e978f6bcSFlorian Hahn PassInstrumentationCallbacks PIC;
247e978f6bcSFlorian Hahn StandardInstrumentations SI(DebugPassManager);
248e978f6bcSFlorian Hahn SI.registerCallbacks(PIC, &FAM);
249e978f6bcSFlorian Hahn PipelineTuningOptions PTO;
250e978f6bcSFlorian Hahn PTO.LoopVectorization = true;
251e978f6bcSFlorian Hahn PTO.SLPVectorization = true;
252e978f6bcSFlorian Hahn PassBuilder PB(&TM, PTO, PGOOpt, &PIC);
253e978f6bcSFlorian Hahn
254e978f6bcSFlorian Hahn std::unique_ptr<TargetLibraryInfoImpl> TLII(
255e978f6bcSFlorian Hahn new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())));
256e978f6bcSFlorian Hahn if (Freestanding)
257e978f6bcSFlorian Hahn TLII->disableAllFunctions();
258e978f6bcSFlorian Hahn FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
259e978f6bcSFlorian Hahn
260e978f6bcSFlorian Hahn // Register all the basic analyses with the managers.
261e978f6bcSFlorian Hahn PB.registerModuleAnalyses(MAM);
262e978f6bcSFlorian Hahn PB.registerCGSCCAnalyses(CGAM);
263e978f6bcSFlorian Hahn PB.registerFunctionAnalyses(FAM);
264e978f6bcSFlorian Hahn PB.registerLoopAnalyses(LAM);
265e978f6bcSFlorian Hahn PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
266e978f6bcSFlorian Hahn
267e978f6bcSFlorian Hahn ModulePassManager MPM;
268e978f6bcSFlorian Hahn
2697a797b29STarindu Jayatilaka OptimizationLevel OL;
270e978f6bcSFlorian Hahn
271e978f6bcSFlorian Hahn switch (OptLevel) {
272e978f6bcSFlorian Hahn default:
273e978f6bcSFlorian Hahn llvm_unreachable("Invalid optimization level");
274e978f6bcSFlorian Hahn case 0:
2757a797b29STarindu Jayatilaka OL = OptimizationLevel::O0;
276e978f6bcSFlorian Hahn break;
277e978f6bcSFlorian Hahn case 1:
2787a797b29STarindu Jayatilaka OL = OptimizationLevel::O1;
279e978f6bcSFlorian Hahn break;
280e978f6bcSFlorian Hahn case 2:
2817a797b29STarindu Jayatilaka OL = OptimizationLevel::O2;
282e978f6bcSFlorian Hahn break;
283e978f6bcSFlorian Hahn case 3:
2847a797b29STarindu Jayatilaka OL = OptimizationLevel::O3;
285e978f6bcSFlorian Hahn break;
286e978f6bcSFlorian Hahn }
287e978f6bcSFlorian Hahn
288e978f6bcSFlorian Hahn MPM.addPass(PB.buildThinLTODefaultPipeline(OL, Index));
289e978f6bcSFlorian Hahn
290e978f6bcSFlorian Hahn MPM.run(TheModule, MAM);
291e978f6bcSFlorian Hahn }
292e978f6bcSFlorian Hahn
29305a358cdSSteven Wu static void
addUsedSymbolToPreservedGUID(const lto::InputFile & File,DenseSet<GlobalValue::GUID> & PreservedGUID)29405a358cdSSteven Wu addUsedSymbolToPreservedGUID(const lto::InputFile &File,
29505a358cdSSteven Wu DenseSet<GlobalValue::GUID> &PreservedGUID) {
29605a358cdSSteven Wu for (const auto &Sym : File.symbols()) {
29705a358cdSSteven Wu if (Sym.isUsed())
29805a358cdSSteven Wu PreservedGUID.insert(GlobalValue::getGUID(Sym.getIRName()));
29905a358cdSSteven Wu }
30005a358cdSSteven Wu }
30105a358cdSSteven Wu
302059464feSMehdi Amini // Convert the PreservedSymbols map from "Name" based to "GUID" based.
computeGUIDPreservedSymbols(const lto::InputFile & File,const StringSet<> & PreservedSymbols,const Triple & TheTriple,DenseSet<GlobalValue::GUID> & GUIDs)30334b289b6SSteven Wu static void computeGUIDPreservedSymbols(const lto::InputFile &File,
30434b289b6SSteven Wu const StringSet<> &PreservedSymbols,
30534b289b6SSteven Wu const Triple &TheTriple,
30634b289b6SSteven Wu DenseSet<GlobalValue::GUID> &GUIDs) {
30734b289b6SSteven Wu // Iterate the symbols in the input file and if the input has preserved symbol
30834b289b6SSteven Wu // compute the GUID for the symbol.
30934b289b6SSteven Wu for (const auto &Sym : File.symbols()) {
31097866b8dSSteven Wu if (PreservedSymbols.count(Sym.getName()) && !Sym.getIRName().empty())
31134b289b6SSteven Wu GUIDs.insert(GlobalValue::getGUID(GlobalValue::getGlobalIdentifier(
31234b289b6SSteven Wu Sym.getIRName(), GlobalValue::ExternalLinkage, "")));
31334b289b6SSteven Wu }
31434b289b6SSteven Wu }
31534b289b6SSteven Wu
316059464feSMehdi Amini static DenseSet<GlobalValue::GUID>
computeGUIDPreservedSymbols(const lto::InputFile & File,const StringSet<> & PreservedSymbols,const Triple & TheTriple)31734b289b6SSteven Wu computeGUIDPreservedSymbols(const lto::InputFile &File,
31834b289b6SSteven Wu const StringSet<> &PreservedSymbols,
319059464feSMehdi Amini const Triple &TheTriple) {
3201380edf4SMehdi Amini DenseSet<GlobalValue::GUID> GUIDPreservedSymbols(PreservedSymbols.size());
32134b289b6SSteven Wu computeGUIDPreservedSymbols(File, PreservedSymbols, TheTriple,
32234b289b6SSteven Wu GUIDPreservedSymbols);
3231380edf4SMehdi Amini return GUIDPreservedSymbols;
324059464feSMehdi Amini }
325059464feSMehdi Amini
codegenModule(Module & TheModule,TargetMachine & TM)3267c4a1a8dSMehdi Amini std::unique_ptr<MemoryBuffer> codegenModule(Module &TheModule,
3277c4a1a8dSMehdi Amini TargetMachine &TM) {
3287c4a1a8dSMehdi Amini SmallVector<char, 128> OutputBuffer;
3297c4a1a8dSMehdi Amini
3307c4a1a8dSMehdi Amini // CodeGen
3317c4a1a8dSMehdi Amini {
3327c4a1a8dSMehdi Amini raw_svector_ostream OS(OutputBuffer);
3337c4a1a8dSMehdi Amini legacy::PassManager PM;
334215d59e7SMehdi Amini
335215d59e7SMehdi Amini // If the bitcode files contain ARC code and were compiled with optimization,
336215d59e7SMehdi Amini // the ObjCARCContractPass must be run, so do it unconditionally here.
337215d59e7SMehdi Amini PM.add(createObjCARCContractPass());
338215d59e7SMehdi Amini
339215d59e7SMehdi Amini // Setup the codegen now.
3401dfede31SReid Kleckner if (TM.addPassesToEmitFile(PM, OS, nullptr, CGFT_ObjectFile,
3417c4a1a8dSMehdi Amini /* DisableVerify */ true))
3427c4a1a8dSMehdi Amini report_fatal_error("Failed to setup codegen");
3437c4a1a8dSMehdi Amini
3447c4a1a8dSMehdi Amini // Run codegen now. resulting binary is in OutputBuffer.
3457c4a1a8dSMehdi Amini PM.run(TheModule);
3467c4a1a8dSMehdi Amini }
347d0262c23SJan Svoboda return std::make_unique<SmallVectorMemoryBuffer>(
348d0262c23SJan Svoboda std::move(OutputBuffer), /*RequiresNullTerminator=*/false);
3497c4a1a8dSMehdi Amini }
3507c4a1a8dSMehdi Amini
351f95f77adSMehdi Amini /// Manage caching for a single Module.
352f95f77adSMehdi Amini class ModuleCacheEntry {
353f95f77adSMehdi Amini SmallString<128> EntryPath;
354f95f77adSMehdi Amini
355f95f77adSMehdi Amini public:
356f95f77adSMehdi Amini // Create a cache entry. This compute a unique hash for the Module considering
357f95f77adSMehdi Amini // the current list of export/import, and offer an interface to query to
358f95f77adSMehdi Amini // access the content in the cache.
ModuleCacheEntry(StringRef CachePath,const ModuleSummaryIndex & Index,StringRef ModuleID,const FunctionImporter::ImportMapTy & ImportList,const FunctionImporter::ExportSetTy & ExportList,const std::map<GlobalValue::GUID,GlobalValue::LinkageTypes> & ResolvedODR,const GVSummaryMapTy & DefinedGVSummaries,unsigned OptLevel,bool Freestanding,const TargetMachineBuilder & TMBuilder)359f95f77adSMehdi Amini ModuleCacheEntry(
360f95f77adSMehdi Amini StringRef CachePath, const ModuleSummaryIndex &Index, StringRef ModuleID,
361f95f77adSMehdi Amini const FunctionImporter::ImportMapTy &ImportList,
362f95f77adSMehdi Amini const FunctionImporter::ExportSetTy &ExportList,
363f95f77adSMehdi Amini const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
3645f312ad4STeresa Johnson const GVSummaryMapTy &DefinedGVSummaries, unsigned OptLevel,
365b5a46c1fSMehdi Amini bool Freestanding, const TargetMachineBuilder &TMBuilder) {
366f95f77adSMehdi Amini if (CachePath.empty())
367f95f77adSMehdi Amini return;
368f95f77adSMehdi Amini
36900fa1409SMehdi Amini if (!Index.modulePaths().count(ModuleID))
37000fa1409SMehdi Amini // The module does not have an entry, it can't have a hash at all
37100fa1409SMehdi Amini return;
37200fa1409SMehdi Amini
3735f312ad4STeresa Johnson if (all_of(Index.getModuleHash(ModuleID),
3745f312ad4STeresa Johnson [](uint32_t V) { return V == 0; }))
375f82bda0aSMehdi Amini // No hash entry, no caching!
376f82bda0aSMehdi Amini return;
377f82bda0aSMehdi Amini
3785f312ad4STeresa Johnson llvm::lto::Config Conf;
3795f312ad4STeresa Johnson Conf.OptLevel = OptLevel;
3805f312ad4STeresa Johnson Conf.Options = TMBuilder.Options;
3815f312ad4STeresa Johnson Conf.CPU = TMBuilder.MCpu;
3825f312ad4STeresa Johnson Conf.MAttrs.push_back(TMBuilder.MAttr);
3835f312ad4STeresa Johnson Conf.RelocModel = TMBuilder.RelocModel;
3845f312ad4STeresa Johnson Conf.CGOptLevel = TMBuilder.CGOptLevel;
3855f312ad4STeresa Johnson Conf.Freestanding = Freestanding;
3865f312ad4STeresa Johnson SmallString<40> Key;
3875f312ad4STeresa Johnson computeLTOCacheKey(Key, Conf, Index, ModuleID, ImportList, ExportList,
3885f312ad4STeresa Johnson ResolvedODR, DefinedGVSummaries);
389bf46e741SEugene Leviant
39025a17ba4SPeter Collingbourne // This choice of file name allows the cache to be pruned (see pruneCache()
39125a17ba4SPeter Collingbourne // in include/llvm/Support/CachePruning.h).
3925f312ad4STeresa Johnson sys::path::append(EntryPath, CachePath, "llvmcache-" + Key);
393f95f77adSMehdi Amini }
394f95f77adSMehdi Amini
395059464feSMehdi Amini // Access the path to this entry in the cache.
getEntryPath()396059464feSMehdi Amini StringRef getEntryPath() { return EntryPath; }
397059464feSMehdi Amini
398f95f77adSMehdi Amini // Try loading the buffer for this cache entry.
tryLoadingBuffer()399f95f77adSMehdi Amini ErrorOr<std::unique_ptr<MemoryBuffer>> tryLoadingBuffer() {
400f95f77adSMehdi Amini if (EntryPath.empty())
401f95f77adSMehdi Amini return std::error_code();
402089303d8SAndrew Ng SmallString<64> ResultPath;
403f002fcb2SReid Kleckner Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(
404f002fcb2SReid Kleckner Twine(EntryPath), sys::fs::OF_UpdateAtime, &ResultPath);
405f002fcb2SReid Kleckner if (!FDOrErr)
406f002fcb2SReid Kleckner return errorToErrorCode(FDOrErr.takeError());
407cc418a3aSReid Kleckner ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getOpenFile(
408f002fcb2SReid Kleckner *FDOrErr, EntryPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false);
409f002fcb2SReid Kleckner sys::fs::closeFile(*FDOrErr);
410089303d8SAndrew Ng return MBOrErr;
411f95f77adSMehdi Amini }
412f95f77adSMehdi Amini
413f95f77adSMehdi Amini // Cache the Produced object file
write(const MemoryBuffer & OutputBuffer)4148e13bc45SMehdi Amini void write(const MemoryBuffer &OutputBuffer) {
415f95f77adSMehdi Amini if (EntryPath.empty())
4168e13bc45SMehdi Amini return;
417f95f77adSMehdi Amini
418f95f77adSMehdi Amini // Write to a temporary to avoid race condition
419f95f77adSMehdi Amini SmallString<128> TempFilename;
4200b01dfbbSEkaterina Romanova SmallString<128> CachePath(EntryPath);
4210b01dfbbSEkaterina Romanova llvm::sys::path::remove_filename(CachePath);
4220b01dfbbSEkaterina Romanova sys::path::append(TempFilename, CachePath, "Thin-%%%%%%.tmp.o");
423f69c9178SJan Korous
424f69c9178SJan Korous if (auto Err = handleErrors(
425f69c9178SJan Korous llvm::writeFileAtomically(TempFilename, EntryPath,
426f69c9178SJan Korous OutputBuffer.getBuffer()),
427f69c9178SJan Korous [](const llvm::AtomicFileWriteError &E) {
428f69c9178SJan Korous std::string ErrorMsgBuffer;
429f69c9178SJan Korous llvm::raw_string_ostream S(ErrorMsgBuffer);
430f69c9178SJan Korous E.log(S);
431f69c9178SJan Korous
432f69c9178SJan Korous if (E.Error ==
433f69c9178SJan Korous llvm::atomic_write_error::failed_to_create_uniq_file) {
434f69c9178SJan Korous errs() << "Error: " << ErrorMsgBuffer << "\n";
435f95f77adSMehdi Amini report_fatal_error("ThinLTO: Can't get a temporary file");
436f95f77adSMehdi Amini }
437f69c9178SJan Korous })) {
438f69c9178SJan Korous // FIXME
439f69c9178SJan Korous consumeError(std::move(Err));
440f95f77adSMehdi Amini }
441f95f77adSMehdi Amini }
442f95f77adSMehdi Amini };
443f95f77adSMehdi Amini
4444d2613f2STeresa Johnson static std::unique_ptr<MemoryBuffer>
ProcessThinLTOModule(Module & TheModule,ModuleSummaryIndex & Index,StringMap<lto::InputFile * > & ModuleMap,TargetMachine & TM,const FunctionImporter::ImportMapTy & ImportList,const FunctionImporter::ExportSetTy & ExportList,const DenseSet<GlobalValue::GUID> & GUIDPreservedSymbols,const GVSummaryMapTy & DefinedGlobals,const ThinLTOCodeGenerator::CachingOptions & CacheOptions,bool DisableCodeGen,StringRef SaveTempsDir,bool Freestanding,unsigned OptLevel,unsigned count,bool DebugPassManager)4454d2613f2STeresa Johnson ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index,
44605a358cdSSteven Wu StringMap<lto::InputFile *> &ModuleMap, TargetMachine &TM,
44701e32130SMehdi Amini const FunctionImporter::ImportMapTy &ImportList,
448059464feSMehdi Amini const FunctionImporter::ExportSetTy &ExportList,
449059464feSMehdi Amini const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
4504d2613f2STeresa Johnson const GVSummaryMapTy &DefinedGlobals,
451c321e534SBenjamin Kramer const ThinLTOCodeGenerator::CachingOptions &CacheOptions,
4524d2613f2STeresa Johnson bool DisableCodeGen, StringRef SaveTempsDir,
453e978f6bcSFlorian Hahn bool Freestanding, unsigned OptLevel, unsigned count,
454ceadf6eeSNikita Popov bool DebugPassManager) {
455*2eade1dbSArthur Eubanks // See comment at call to updateVCallVisibilityInIndex() for why
456*2eade1dbSArthur Eubanks // WholeProgramVisibilityEnabledInLTO is false.
457*2eade1dbSArthur Eubanks updatePublicTypeTestCalls(TheModule,
458*2eade1dbSArthur Eubanks /* WholeProgramVisibilityEnabledInLTO */ false);
459059464feSMehdi Amini
4607c4a1a8dSMehdi Amini // "Benchmark"-like optimization: single-source case
4617c4a1a8dSMehdi Amini bool SingleModule = (ModuleMap.size() == 1);
4627c4a1a8dSMehdi Amini
463d2ef8c1fSFangrui Song // When linking an ELF shared object, dso_local should be dropped. We
464d2ef8c1fSFangrui Song // conservatively do this for -fpic.
465d2ef8c1fSFangrui Song bool ClearDSOLocalOnDeclarations =
466d2ef8c1fSFangrui Song TM.getTargetTriple().isOSBinFormatELF() &&
467d2ef8c1fSFangrui Song TM.getRelocationModel() != Reloc::Static &&
468d2ef8c1fSFangrui Song TheModule.getPIELevel() == PIELevel::Default;
469d2ef8c1fSFangrui Song
4707c4a1a8dSMehdi Amini if (!SingleModule) {
471d2ef8c1fSFangrui Song promoteModule(TheModule, Index, ClearDSOLocalOnDeclarations);
4727c4a1a8dSMehdi Amini
473e61652a3SPirama Arumuga Nainar // Apply summary-based prevailing-symbol resolution decisions.
47420faf789Smodimo thinLTOFinalizeInModule(TheModule, DefinedGlobals, /*PropagateAttrs=*/true);
4755a2e5d32SMehdi Amini
4767c4a1a8dSMehdi Amini // Save temps: after promotion.
4774b300e0aSMehdi Amini saveTempBitcode(TheModule, SaveTempsDir, count, ".1.promoted.bc");
478059464feSMehdi Amini }
4797c4a1a8dSMehdi Amini
4804d2613f2STeresa Johnson // Be friendly and don't nuke totally the module when the client didn't
4814d2613f2STeresa Johnson // supply anything to preserve.
4824d2613f2STeresa Johnson if (!ExportList.empty() || !GUIDPreservedSymbols.empty()) {
4834d2613f2STeresa Johnson // Apply summary-based internalization decisions.
4844d2613f2STeresa Johnson thinLTOInternalizeModule(TheModule, DefinedGlobals);
4854d2613f2STeresa Johnson }
486059464feSMehdi Amini
487059464feSMehdi Amini // Save internalized bitcode
4884b300e0aSMehdi Amini saveTempBitcode(TheModule, SaveTempsDir, count, ".2.internalized.bc");
489059464feSMehdi Amini
490059464feSMehdi Amini if (!SingleModule) {
491d2ef8c1fSFangrui Song crossImportIntoModule(TheModule, Index, ModuleMap, ImportList,
492d2ef8c1fSFangrui Song ClearDSOLocalOnDeclarations);
4937c4a1a8dSMehdi Amini
4947c4a1a8dSMehdi Amini // Save temps: after cross-module import.
4954b300e0aSMehdi Amini saveTempBitcode(TheModule, SaveTempsDir, count, ".3.imported.bc");
4967c4a1a8dSMehdi Amini }
4977c4a1a8dSMehdi Amini
498ceadf6eeSNikita Popov optimizeModule(TheModule, TM, OptLevel, Freestanding, DebugPassManager,
4998b8da01dSWael Yehia &Index);
5007c4a1a8dSMehdi Amini
5014b300e0aSMehdi Amini saveTempBitcode(TheModule, SaveTempsDir, count, ".4.opt.bc");
5027c4a1a8dSMehdi Amini
50343b657b5SMehdi Amini if (DisableCodeGen) {
50443b657b5SMehdi Amini // Configured to stop before CodeGen, serialize the bitcode and return.
50543b657b5SMehdi Amini SmallVector<char, 128> OutputBuffer;
50643b657b5SMehdi Amini {
50743b657b5SMehdi Amini raw_svector_ostream OS(OutputBuffer);
5085461d8bdSDehao Chen ProfileSummaryInfo PSI(TheModule);
50994624acaSTeresa Johnson auto Index = buildModuleSummaryIndex(TheModule, nullptr, &PSI);
5106a86e25dSRafael Espindola WriteBitcodeToFile(TheModule, OS, true, &Index);
51143b657b5SMehdi Amini }
512d0262c23SJan Svoboda return std::make_unique<SmallVectorMemoryBuffer>(
513d0262c23SJan Svoboda std::move(OutputBuffer), /*RequiresNullTerminator=*/false);
51443b657b5SMehdi Amini }
51543b657b5SMehdi Amini
5167c4a1a8dSMehdi Amini return codegenModule(TheModule, TM);
5177c4a1a8dSMehdi Amini }
5187c4a1a8dSMehdi Amini
519e61652a3SPirama Arumuga Nainar /// Resolve prevailing symbols. Record resolutions in the \p ResolvedODR map
5204d2613f2STeresa Johnson /// for caching, and in the \p Index for application during the ThinLTO
5214d2613f2STeresa Johnson /// backends. This is needed for correctness for exported symbols (ensure
5224d2613f2STeresa Johnson /// at least one copy kept) and a compile-time optimization (to drop duplicate
5234d2613f2STeresa Johnson /// copies when possible).
resolvePrevailingInIndex(ModuleSummaryIndex & Index,StringMap<std::map<GlobalValue::GUID,GlobalValue::LinkageTypes>> & ResolvedODR,const DenseSet<GlobalValue::GUID> & GUIDPreservedSymbols,const DenseMap<GlobalValue::GUID,const GlobalValueSummary * > & PrevailingCopy)524e61652a3SPirama Arumuga Nainar static void resolvePrevailingInIndex(
5254d2613f2STeresa Johnson ModuleSummaryIndex &Index,
5264d2613f2STeresa Johnson StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>>
52737b80122STeresa Johnson &ResolvedODR,
528ea314fd4STeresa Johnson const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
529ea314fd4STeresa Johnson const DenseMap<GlobalValue::GUID, const GlobalValueSummary *>
530ea314fd4STeresa Johnson &PrevailingCopy) {
5314d2613f2STeresa Johnson
5324d2613f2STeresa Johnson auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
5334d2613f2STeresa Johnson const auto &Prevailing = PrevailingCopy.find(GUID);
5344d2613f2STeresa Johnson // Not in map means that there was only one copy, which must be prevailing.
5354d2613f2STeresa Johnson if (Prevailing == PrevailingCopy.end())
5364d2613f2STeresa Johnson return true;
5374d2613f2STeresa Johnson return Prevailing->second == S;
5384d2613f2STeresa Johnson };
5394d2613f2STeresa Johnson
5404d2613f2STeresa Johnson auto recordNewLinkage = [&](StringRef ModuleIdentifier,
5414d2613f2STeresa Johnson GlobalValue::GUID GUID,
5424d2613f2STeresa Johnson GlobalValue::LinkageTypes NewLinkage) {
5434d2613f2STeresa Johnson ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
5444d2613f2STeresa Johnson };
5454d2613f2STeresa Johnson
54654fb3ca9SFangrui Song // TODO Conf.VisibilityScheme can be lto::Config::ELF for ELF.
54754fb3ca9SFangrui Song lto::Config Conf;
54854fb3ca9SFangrui Song thinLTOResolvePrevailingInIndex(Conf, Index, isPrevailing, recordNewLinkage,
54937b80122STeresa Johnson GUIDPreservedSymbols);
5504d2613f2STeresa Johnson }
5514d2613f2STeresa Johnson
5527c4a1a8dSMehdi Amini // Initialize the TargetMachine builder for a given Triple
initTMBuilder(TargetMachineBuilder & TMBuilder,const Triple & TheTriple)5537c4a1a8dSMehdi Amini static void initTMBuilder(TargetMachineBuilder &TMBuilder,
5547c4a1a8dSMehdi Amini const Triple &TheTriple) {
5557c4a1a8dSMehdi Amini // Set a default CPU for Darwin triples (copied from LTOCodeGenerator).
5567c4a1a8dSMehdi Amini // FIXME this looks pretty terrible...
5577c4a1a8dSMehdi Amini if (TMBuilder.MCpu.empty() && TheTriple.isOSDarwin()) {
5587c4a1a8dSMehdi Amini if (TheTriple.getArch() == llvm::Triple::x86_64)
5597c4a1a8dSMehdi Amini TMBuilder.MCpu = "core2";
5607c4a1a8dSMehdi Amini else if (TheTriple.getArch() == llvm::Triple::x86)
5617c4a1a8dSMehdi Amini TMBuilder.MCpu = "yonah";
562f1c28929STim Northover else if (TheTriple.getArch() == llvm::Triple::aarch64 ||
563f1c28929STim Northover TheTriple.getArch() == llvm::Triple::aarch64_32)
5647c4a1a8dSMehdi Amini TMBuilder.MCpu = "cyclone";
5657c4a1a8dSMehdi Amini }
5667c4a1a8dSMehdi Amini TMBuilder.TheTriple = std::move(TheTriple);
5677c4a1a8dSMehdi Amini }
5687c4a1a8dSMehdi Amini
5697c4a1a8dSMehdi Amini } // end anonymous namespace
5707c4a1a8dSMehdi Amini
addModule(StringRef Identifier,StringRef Data)5717c4a1a8dSMehdi Amini void ThinLTOCodeGenerator::addModule(StringRef Identifier, StringRef Data) {
57205a358cdSSteven Wu MemoryBufferRef Buffer(Data, Identifier);
573b10bff11SAkira Hatanaka
57405a358cdSSteven Wu auto InputOrError = lto::InputFile::create(Buffer);
57505a358cdSSteven Wu if (!InputOrError)
57621661607SSimon Pilgrim report_fatal_error(Twine("ThinLTO cannot create input file: ") +
57705a358cdSSteven Wu toString(InputOrError.takeError()));
578b10bff11SAkira Hatanaka
57905a358cdSSteven Wu auto TripleStr = (*InputOrError)->getTargetTriple();
580cd513a41SPeter Collingbourne Triple TheTriple(TripleStr);
581b10bff11SAkira Hatanaka
582b10bff11SAkira Hatanaka if (Modules.empty())
5837c4a1a8dSMehdi Amini initTMBuilder(TMBuilder, Triple(TheTriple));
584b10bff11SAkira Hatanaka else if (TMBuilder.TheTriple != TheTriple) {
585b10bff11SAkira Hatanaka if (!TMBuilder.TheTriple.isCompatibleWith(TheTriple))
586b10bff11SAkira Hatanaka report_fatal_error("ThinLTO modules with incompatible triples not "
587b10bff11SAkira Hatanaka "supported");
588b10bff11SAkira Hatanaka initTMBuilder(TMBuilder, Triple(TMBuilder.TheTriple.merge(TheTriple)));
5897c4a1a8dSMehdi Amini }
590b10bff11SAkira Hatanaka
59105a358cdSSteven Wu Modules.emplace_back(std::move(*InputOrError));
5927c4a1a8dSMehdi Amini }
5937c4a1a8dSMehdi Amini
preserveSymbol(StringRef Name)5947c4a1a8dSMehdi Amini void ThinLTOCodeGenerator::preserveSymbol(StringRef Name) {
5957c4a1a8dSMehdi Amini PreservedSymbols.insert(Name);
5967c4a1a8dSMehdi Amini }
5977c4a1a8dSMehdi Amini
crossReferenceSymbol(StringRef Name)5987c4a1a8dSMehdi Amini void ThinLTOCodeGenerator::crossReferenceSymbol(StringRef Name) {
5991380edf4SMehdi Amini // FIXME: At the moment, we don't take advantage of this extra information,
6001380edf4SMehdi Amini // we're conservatively considering cross-references as preserved.
6011380edf4SMehdi Amini // CrossReferencedSymbols.insert(Name);
6021380edf4SMehdi Amini PreservedSymbols.insert(Name);
6037c4a1a8dSMehdi Amini }
6047c4a1a8dSMehdi Amini
6057c4a1a8dSMehdi Amini // TargetMachine factory
create() const6067c4a1a8dSMehdi Amini std::unique_ptr<TargetMachine> TargetMachineBuilder::create() const {
6077c4a1a8dSMehdi Amini std::string ErrMsg;
6087c4a1a8dSMehdi Amini const Target *TheTarget =
6097c4a1a8dSMehdi Amini TargetRegistry::lookupTarget(TheTriple.str(), ErrMsg);
6107c4a1a8dSMehdi Amini if (!TheTarget) {
61121661607SSimon Pilgrim report_fatal_error(Twine("Can't load target for this Triple: ") + ErrMsg);
6127c4a1a8dSMehdi Amini }
6137c4a1a8dSMehdi Amini
6147c4a1a8dSMehdi Amini // Use MAttr as the default set of features.
6157c4a1a8dSMehdi Amini SubtargetFeatures Features(MAttr);
6167c4a1a8dSMehdi Amini Features.getDefaultSubtargetFeatures(TheTriple);
6177c4a1a8dSMehdi Amini std::string FeatureStr = Features.getString();
618cc7fbf71SMehdi Amini
6191756d679SElla Ma std::unique_ptr<TargetMachine> TM(
62079e238afSRafael Espindola TheTarget->createTargetMachine(TheTriple.str(), MCpu, FeatureStr, Options,
62179e238afSRafael Espindola RelocModel, None, CGOptLevel));
6221756d679SElla Ma assert(TM && "Cannot create target machine");
6231756d679SElla Ma
6241756d679SElla Ma return TM;
6257c4a1a8dSMehdi Amini }
6267c4a1a8dSMehdi Amini
6277c4a1a8dSMehdi Amini /**
62826ab5772STeresa Johnson * Produce the combined summary index from all the bitcode files:
6297c4a1a8dSMehdi Amini * "thin-link".
6307c4a1a8dSMehdi Amini */
linkCombinedIndex()63126ab5772STeresa Johnson std::unique_ptr<ModuleSummaryIndex> ThinLTOCodeGenerator::linkCombinedIndex() {
63274d22dd7SPeter Collingbourne std::unique_ptr<ModuleSummaryIndex> CombinedIndex =
6330eaee545SJonas Devlieghere std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false);
6347c4a1a8dSMehdi Amini uint64_t NextModuleId = 0;
63505a358cdSSteven Wu for (auto &Mod : Modules) {
63605a358cdSSteven Wu auto &M = Mod->getSingleBitcodeModule();
63705a358cdSSteven Wu if (Error Err =
63805a358cdSSteven Wu M.readSummary(*CombinedIndex, Mod->getName(), NextModuleId++)) {
6397c4a1a8dSMehdi Amini // FIXME diagnose
6406de481a3SPeter Collingbourne logAllUnhandledErrors(
64174d22dd7SPeter Collingbourne std::move(Err), errs(),
642c15d60b7SPeter Collingbourne "error: can't create module summary index for buffer: ");
6437c4a1a8dSMehdi Amini return nullptr;
6447c4a1a8dSMehdi Amini }
6457c4a1a8dSMehdi Amini }
6467c4a1a8dSMehdi Amini return CombinedIndex;
6477c4a1a8dSMehdi Amini }
6487c4a1a8dSMehdi Amini
649bfa3f0c3SBenjamin Kramer namespace {
650eb34c3e8SEugene Leviant struct IsExported {
651eb34c3e8SEugene Leviant const StringMap<FunctionImporter::ExportSetTy> &ExportLists;
652eb34c3e8SEugene Leviant const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols;
653eb34c3e8SEugene Leviant
IsExported__anon39b237c20e11::IsExported654eb34c3e8SEugene Leviant IsExported(const StringMap<FunctionImporter::ExportSetTy> &ExportLists,
655eb34c3e8SEugene Leviant const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols)
656eb34c3e8SEugene Leviant : ExportLists(ExportLists), GUIDPreservedSymbols(GUIDPreservedSymbols) {}
657eb34c3e8SEugene Leviant
operator ()__anon39b237c20e11::IsExported6583d708bf5Sevgeny bool operator()(StringRef ModuleIdentifier, ValueInfo VI) const {
6592421b6faSGeorge Rimar const auto &ExportList = ExportLists.find(ModuleIdentifier);
6603d708bf5Sevgeny return (ExportList != ExportLists.end() && ExportList->second.count(VI)) ||
6613d708bf5Sevgeny GUIDPreservedSymbols.count(VI.getGUID());
662eb34c3e8SEugene Leviant }
6632421b6faSGeorge Rimar };
6642421b6faSGeorge Rimar
665eb34c3e8SEugene Leviant struct IsPrevailing {
666eb34c3e8SEugene Leviant const DenseMap<GlobalValue::GUID, const GlobalValueSummary *> &PrevailingCopy;
IsPrevailing__anon39b237c20e11::IsPrevailing667eb34c3e8SEugene Leviant IsPrevailing(const DenseMap<GlobalValue::GUID, const GlobalValueSummary *>
668eb34c3e8SEugene Leviant &PrevailingCopy)
669eb34c3e8SEugene Leviant : PrevailingCopy(PrevailingCopy) {}
670eb34c3e8SEugene Leviant
operator ()__anon39b237c20e11::IsPrevailing671eb34c3e8SEugene Leviant bool operator()(GlobalValue::GUID GUID, const GlobalValueSummary *S) const {
672ea314fd4STeresa Johnson const auto &Prevailing = PrevailingCopy.find(GUID);
673ea314fd4STeresa Johnson // Not in map means that there was only one copy, which must be prevailing.
674ea314fd4STeresa Johnson if (Prevailing == PrevailingCopy.end())
675ea314fd4STeresa Johnson return true;
676ea314fd4STeresa Johnson return Prevailing->second == S;
677ea314fd4STeresa Johnson };
678eb34c3e8SEugene Leviant };
679950b800cSMichael Liao } // namespace
6802421b6faSGeorge Rimar
computeDeadSymbolsInIndex(ModuleSummaryIndex & Index,const DenseSet<GlobalValue::GUID> & GUIDPreservedSymbols)681eaf5172cSGeorge Rimar static void computeDeadSymbolsInIndex(
682eaf5172cSGeorge Rimar ModuleSummaryIndex &Index,
683eaf5172cSGeorge Rimar const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
684eaf5172cSGeorge Rimar // We have no symbols resolution available. And can't do any better now in the
685eaf5172cSGeorge Rimar // case where the prevailing symbol is in a native object. It can be refined
686eaf5172cSGeorge Rimar // with linker information in the future.
687eaf5172cSGeorge Rimar auto isPrevailing = [&](GlobalValue::GUID G) {
688eaf5172cSGeorge Rimar return PrevailingType::Unknown;
689eaf5172cSGeorge Rimar };
690bf46e741SEugene Leviant computeDeadSymbolsWithConstProp(Index, GUIDPreservedSymbols, isPrevailing,
691bf46e741SEugene Leviant /* ImportEnabled = */ true);
692eaf5172cSGeorge Rimar }
693eaf5172cSGeorge Rimar
6947c4a1a8dSMehdi Amini /**
6957c4a1a8dSMehdi Amini * Perform promotion and renaming of exported internal functions.
6964d2613f2STeresa Johnson * Index is updated to reflect linkage changes from weak resolution.
6977c4a1a8dSMehdi Amini */
promote(Module & TheModule,ModuleSummaryIndex & Index,const lto::InputFile & File)69805a358cdSSteven Wu void ThinLTOCodeGenerator::promote(Module &TheModule, ModuleSummaryIndex &Index,
69905a358cdSSteven Wu const lto::InputFile &File) {
700a71a5a62SMehdi Amini auto ModuleCount = Index.modulePaths().size();
7011aafabf7SMehdi Amini auto ModuleIdentifier = TheModule.getModuleIdentifier();
7024fef68cbSTeresa Johnson
7031aafabf7SMehdi Amini // Collect for each module the list of function it defines (GUID -> Summary).
704c851d216STeresa Johnson StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
7051aafabf7SMehdi Amini Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
7065a2e5d32SMehdi Amini
7076c475a75STeresa Johnson // Convert the preserved symbols set from string to GUID
7081380edf4SMehdi Amini auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(
70934b289b6SSteven Wu File, PreservedSymbols, Triple(TheModule.getTargetTriple()));
7106c475a75STeresa Johnson
71105a358cdSSteven Wu // Add used symbol to the preserved symbols.
71205a358cdSSteven Wu addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols);
71305a358cdSSteven Wu
7146c475a75STeresa Johnson // Compute "dead" symbols, we don't want to import/export these!
715eaf5172cSGeorge Rimar computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
7166c475a75STeresa Johnson
717a71a5a62SMehdi Amini // Generate import/export list
718a71a5a62SMehdi Amini StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
719a71a5a62SMehdi Amini StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
720a71a5a62SMehdi Amini ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
72156584bbfSEvgeniy Stepanov ExportLists);
722a71a5a62SMehdi Amini
723ea314fd4STeresa Johnson DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
724ea314fd4STeresa Johnson computePrevailingCopies(Index, PrevailingCopy);
725ea314fd4STeresa Johnson
726e61652a3SPirama Arumuga Nainar // Resolve prevailing symbols
7274d2613f2STeresa Johnson StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
728ea314fd4STeresa Johnson resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
729ea314fd4STeresa Johnson PrevailingCopy);
7304d2613f2STeresa Johnson
73120faf789Smodimo thinLTOFinalizeInModule(TheModule,
73220faf789Smodimo ModuleToDefinedGVSummaries[ModuleIdentifier],
73320faf789Smodimo /*PropagateAttrs=*/false);
734f41e70d6SSteven Wu
7354fef68cbSTeresa Johnson // Promote the exported values in the index, so that they are promoted
7364fef68cbSTeresa Johnson // in the module.
737eb34c3e8SEugene Leviant thinLTOInternalizeAndPromoteInIndex(
738eb34c3e8SEugene Leviant Index, IsExported(ExportLists, GUIDPreservedSymbols),
739eb34c3e8SEugene Leviant IsPrevailing(PrevailingCopy));
7404fef68cbSTeresa Johnson
741d2ef8c1fSFangrui Song // FIXME Set ClearDSOLocalOnDeclarations.
742d2ef8c1fSFangrui Song promoteModule(TheModule, Index, /*ClearDSOLocalOnDeclarations=*/false);
7437c4a1a8dSMehdi Amini }
7447c4a1a8dSMehdi Amini
7457c4a1a8dSMehdi Amini /**
7467c4a1a8dSMehdi Amini * Perform cross-module importing for the module identified by ModuleIdentifier.
7477c4a1a8dSMehdi Amini */
crossModuleImport(Module & TheModule,ModuleSummaryIndex & Index,const lto::InputFile & File)7487c4a1a8dSMehdi Amini void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule,
74905a358cdSSteven Wu ModuleSummaryIndex &Index,
75005a358cdSSteven Wu const lto::InputFile &File) {
7517c4a1a8dSMehdi Amini auto ModuleMap = generateModuleMap(Modules);
7521aafabf7SMehdi Amini auto ModuleCount = Index.modulePaths().size();
7531aafabf7SMehdi Amini
7541aafabf7SMehdi Amini // Collect for each module the list of function it defines (GUID -> Summary).
755c851d216STeresa Johnson StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount);
7561aafabf7SMehdi Amini Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
75701e32130SMehdi Amini
7586c475a75STeresa Johnson // Convert the preserved symbols set from string to GUID
7591380edf4SMehdi Amini auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(
76034b289b6SSteven Wu File, PreservedSymbols, Triple(TheModule.getTargetTriple()));
7616c475a75STeresa Johnson
76205a358cdSSteven Wu addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols);
76305a358cdSSteven Wu
7646c475a75STeresa Johnson // Compute "dead" symbols, we don't want to import/export these!
765eaf5172cSGeorge Rimar computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
7666c475a75STeresa Johnson
76701e32130SMehdi Amini // Generate import/export list
76801e32130SMehdi Amini StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
76901e32130SMehdi Amini StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
7701aafabf7SMehdi Amini ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
77156584bbfSEvgeniy Stepanov ExportLists);
77201e32130SMehdi Amini auto &ImportList = ImportLists[TheModule.getModuleIdentifier()];
77301e32130SMehdi Amini
774d2ef8c1fSFangrui Song // FIXME Set ClearDSOLocalOnDeclarations.
775d2ef8c1fSFangrui Song crossImportIntoModule(TheModule, Index, ModuleMap, ImportList,
776d2ef8c1fSFangrui Song /*ClearDSOLocalOnDeclarations=*/false);
7777c4a1a8dSMehdi Amini }
7787c4a1a8dSMehdi Amini
7797c4a1a8dSMehdi Amini /**
78084174c37STeresa Johnson * Compute the list of summaries needed for importing into module.
78184174c37STeresa Johnson */
gatherImportedSummariesForModule(Module & TheModule,ModuleSummaryIndex & Index,std::map<std::string,GVSummaryMapTy> & ModuleToSummariesForIndex,const lto::InputFile & File)78284174c37STeresa Johnson void ThinLTOCodeGenerator::gatherImportedSummariesForModule(
78393f99962STeresa Johnson Module &TheModule, ModuleSummaryIndex &Index,
78405a358cdSSteven Wu std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex,
78505a358cdSSteven Wu const lto::InputFile &File) {
78684174c37STeresa Johnson auto ModuleCount = Index.modulePaths().size();
78793f99962STeresa Johnson auto ModuleIdentifier = TheModule.getModuleIdentifier();
78884174c37STeresa Johnson
78984174c37STeresa Johnson // Collect for each module the list of function it defines (GUID -> Summary).
79084174c37STeresa Johnson StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount);
79184174c37STeresa Johnson Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
79284174c37STeresa Johnson
79393f99962STeresa Johnson // Convert the preserved symbols set from string to GUID
79493f99962STeresa Johnson auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(
79534b289b6SSteven Wu File, PreservedSymbols, Triple(TheModule.getTargetTriple()));
79693f99962STeresa Johnson
79705a358cdSSteven Wu addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols);
79805a358cdSSteven Wu
79993f99962STeresa Johnson // Compute "dead" symbols, we don't want to import/export these!
80093f99962STeresa Johnson computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
80193f99962STeresa Johnson
80284174c37STeresa Johnson // Generate import/export list
80384174c37STeresa Johnson StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
80484174c37STeresa Johnson StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
80584174c37STeresa Johnson ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
80684174c37STeresa Johnson ExportLists);
80784174c37STeresa Johnson
80893f99962STeresa Johnson llvm::gatherImportedSummariesForModule(
80993f99962STeresa Johnson ModuleIdentifier, ModuleToDefinedGVSummaries,
81093f99962STeresa Johnson ImportLists[ModuleIdentifier], ModuleToSummariesForIndex);
81184174c37STeresa Johnson }
81284174c37STeresa Johnson
81384174c37STeresa Johnson /**
8148570fe47STeresa Johnson * Emit the list of files needed for importing into module.
8158570fe47STeresa Johnson */
emitImports(Module & TheModule,StringRef OutputName,ModuleSummaryIndex & Index,const lto::InputFile & File)81693f99962STeresa Johnson void ThinLTOCodeGenerator::emitImports(Module &TheModule, StringRef OutputName,
81705a358cdSSteven Wu ModuleSummaryIndex &Index,
81805a358cdSSteven Wu const lto::InputFile &File) {
8198570fe47STeresa Johnson auto ModuleCount = Index.modulePaths().size();
82093f99962STeresa Johnson auto ModuleIdentifier = TheModule.getModuleIdentifier();
8218570fe47STeresa Johnson
8228570fe47STeresa Johnson // Collect for each module the list of function it defines (GUID -> Summary).
8238570fe47STeresa Johnson StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount);
8248570fe47STeresa Johnson Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
8258570fe47STeresa Johnson
82693f99962STeresa Johnson // Convert the preserved symbols set from string to GUID
82793f99962STeresa Johnson auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(
82834b289b6SSteven Wu File, PreservedSymbols, Triple(TheModule.getTargetTriple()));
82993f99962STeresa Johnson
83005a358cdSSteven Wu addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols);
83105a358cdSSteven Wu
83293f99962STeresa Johnson // Compute "dead" symbols, we don't want to import/export these!
83393f99962STeresa Johnson computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
83493f99962STeresa Johnson
8358570fe47STeresa Johnson // Generate import/export list
8368570fe47STeresa Johnson StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
8378570fe47STeresa Johnson StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
8388570fe47STeresa Johnson ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
8398570fe47STeresa Johnson ExportLists);
8408570fe47STeresa Johnson
841c0320ef4STeresa Johnson std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
84293f99962STeresa Johnson llvm::gatherImportedSummariesForModule(
84393f99962STeresa Johnson ModuleIdentifier, ModuleToDefinedGVSummaries,
84493f99962STeresa Johnson ImportLists[ModuleIdentifier], ModuleToSummariesForIndex);
845c0320ef4STeresa Johnson
8468570fe47STeresa Johnson std::error_code EC;
84793f99962STeresa Johnson if ((EC = EmitImportsFiles(ModuleIdentifier, OutputName,
84893f99962STeresa Johnson ModuleToSummariesForIndex)))
8498570fe47STeresa Johnson report_fatal_error(Twine("Failed to open ") + OutputName +
8508570fe47STeresa Johnson " to save imports lists\n");
8518570fe47STeresa Johnson }
8528570fe47STeresa Johnson
8538570fe47STeresa Johnson /**
85405a358cdSSteven Wu * Perform internalization. Runs promote and internalization together.
85505a358cdSSteven Wu * Index is updated to reflect linkage changes.
856059464feSMehdi Amini */
internalize(Module & TheModule,ModuleSummaryIndex & Index,const lto::InputFile & File)857059464feSMehdi Amini void ThinLTOCodeGenerator::internalize(Module &TheModule,
85805a358cdSSteven Wu ModuleSummaryIndex &Index,
85905a358cdSSteven Wu const lto::InputFile &File) {
860059464feSMehdi Amini initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple()));
861059464feSMehdi Amini auto ModuleCount = Index.modulePaths().size();
862059464feSMehdi Amini auto ModuleIdentifier = TheModule.getModuleIdentifier();
863059464feSMehdi Amini
864059464feSMehdi Amini // Convert the preserved symbols set from string to GUID
865059464feSMehdi Amini auto GUIDPreservedSymbols =
86634b289b6SSteven Wu computeGUIDPreservedSymbols(File, PreservedSymbols, TMBuilder.TheTriple);
867059464feSMehdi Amini
86805a358cdSSteven Wu addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols);
86905a358cdSSteven Wu
870059464feSMehdi Amini // Collect for each module the list of function it defines (GUID -> Summary).
871c851d216STeresa Johnson StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount);
872059464feSMehdi Amini Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
873059464feSMehdi Amini
8746c475a75STeresa Johnson // Compute "dead" symbols, we don't want to import/export these!
875eaf5172cSGeorge Rimar computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
8766c475a75STeresa Johnson
877059464feSMehdi Amini // Generate import/export list
878059464feSMehdi Amini StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
879059464feSMehdi Amini StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
880059464feSMehdi Amini ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
88156584bbfSEvgeniy Stepanov ExportLists);
882059464feSMehdi Amini auto &ExportList = ExportLists[ModuleIdentifier];
883059464feSMehdi Amini
8844d2613f2STeresa Johnson // Be friendly and don't nuke totally the module when the client didn't
8854d2613f2STeresa Johnson // supply anything to preserve.
8864d2613f2STeresa Johnson if (ExportList.empty() && GUIDPreservedSymbols.empty())
8874d2613f2STeresa Johnson return;
8884d2613f2STeresa Johnson
889ea314fd4STeresa Johnson DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
890ea314fd4STeresa Johnson computePrevailingCopies(Index, PrevailingCopy);
891ea314fd4STeresa Johnson
89205a358cdSSteven Wu // Resolve prevailing symbols
89305a358cdSSteven Wu StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
894ea314fd4STeresa Johnson resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
895ea314fd4STeresa Johnson PrevailingCopy);
89605a358cdSSteven Wu
89705a358cdSSteven Wu // Promote the exported values in the index, so that they are promoted
89805a358cdSSteven Wu // in the module.
899eb34c3e8SEugene Leviant thinLTOInternalizeAndPromoteInIndex(
900eb34c3e8SEugene Leviant Index, IsExported(ExportLists, GUIDPreservedSymbols),
901eb34c3e8SEugene Leviant IsPrevailing(PrevailingCopy));
90205a358cdSSteven Wu
903d2ef8c1fSFangrui Song // FIXME Set ClearDSOLocalOnDeclarations.
904d2ef8c1fSFangrui Song promoteModule(TheModule, Index, /*ClearDSOLocalOnDeclarations=*/false);
90505a358cdSSteven Wu
90605a358cdSSteven Wu // Internalization
90720faf789Smodimo thinLTOFinalizeInModule(TheModule,
90820faf789Smodimo ModuleToDefinedGVSummaries[ModuleIdentifier],
90920faf789Smodimo /*PropagateAttrs=*/false);
91005a358cdSSteven Wu
9114d2613f2STeresa Johnson thinLTOInternalizeModule(TheModule,
9124d2613f2STeresa Johnson ModuleToDefinedGVSummaries[ModuleIdentifier]);
913059464feSMehdi Amini }
914059464feSMehdi Amini
915059464feSMehdi Amini /**
9167c4a1a8dSMehdi Amini * Perform post-importing ThinLTO optimizations.
9177c4a1a8dSMehdi Amini */
optimize(Module & TheModule)9187c4a1a8dSMehdi Amini void ThinLTOCodeGenerator::optimize(Module &TheModule) {
9197c4a1a8dSMehdi Amini initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple()));
920059464feSMehdi Amini
921059464feSMehdi Amini // Optimize now
922eb34c3e8SEugene Leviant optimizeModule(TheModule, *TMBuilder.create(), OptLevel, Freestanding,
923ceadf6eeSNikita Popov DebugPassManager, nullptr);
9247c4a1a8dSMehdi Amini }
9257c4a1a8dSMehdi Amini
9268e13bc45SMehdi Amini /// Write out the generated object file, either from CacheEntryPath or from
9278e13bc45SMehdi Amini /// OutputBuffer, preferring hard-link when possible.
9288e13bc45SMehdi Amini /// Returns the path to the generated file in SavedObjectsDirectoryPath.
9296c9f6fd1SSteven Wu std::string
writeGeneratedObject(int count,StringRef CacheEntryPath,const MemoryBuffer & OutputBuffer)9306c9f6fd1SSteven Wu ThinLTOCodeGenerator::writeGeneratedObject(int count, StringRef CacheEntryPath,
9318e13bc45SMehdi Amini const MemoryBuffer &OutputBuffer) {
9326c9f6fd1SSteven Wu auto ArchName = TMBuilder.TheTriple.getArchName();
9338e13bc45SMehdi Amini SmallString<128> OutputPath(SavedObjectsDirectoryPath);
9346c9f6fd1SSteven Wu llvm::sys::path::append(OutputPath,
9356c9f6fd1SSteven Wu Twine(count) + "." + ArchName + ".thinlto.o");
9368e13bc45SMehdi Amini OutputPath.c_str(); // Ensure the string is null terminated.
9378e13bc45SMehdi Amini if (sys::fs::exists(OutputPath))
9388e13bc45SMehdi Amini sys::fs::remove(OutputPath);
9398e13bc45SMehdi Amini
9408e13bc45SMehdi Amini // We don't return a memory buffer to the linker, just a list of files.
9418e13bc45SMehdi Amini if (!CacheEntryPath.empty()) {
9428e13bc45SMehdi Amini // Cache is enabled, hard-link the entry (or copy if hard-link fails).
9438e13bc45SMehdi Amini auto Err = sys::fs::create_hard_link(CacheEntryPath, OutputPath);
9448e13bc45SMehdi Amini if (!Err)
945adcd0268SBenjamin Kramer return std::string(OutputPath.str());
9468e13bc45SMehdi Amini // Hard linking failed, try to copy.
9478e13bc45SMehdi Amini Err = sys::fs::copy_file(CacheEntryPath, OutputPath);
9488e13bc45SMehdi Amini if (!Err)
949adcd0268SBenjamin Kramer return std::string(OutputPath.str());
9508e13bc45SMehdi Amini // Copy failed (could be because the CacheEntry was removed from the cache
9518e13bc45SMehdi Amini // in the meantime by another process), fall back and try to write down the
9528e13bc45SMehdi Amini // buffer to the output.
953d7fad626Sromanova-ekaterina errs() << "remark: can't link or copy from cached entry '" << CacheEntryPath
9548e13bc45SMehdi Amini << "' to '" << OutputPath << "'\n";
9558e13bc45SMehdi Amini }
9568e13bc45SMehdi Amini // No cache entry, just write out the buffer.
9578e13bc45SMehdi Amini std::error_code Err;
958d9b948b6SFangrui Song raw_fd_ostream OS(OutputPath, Err, sys::fs::OF_None);
9598e13bc45SMehdi Amini if (Err)
96021661607SSimon Pilgrim report_fatal_error(Twine("Can't open output '") + OutputPath + "'\n");
9618e13bc45SMehdi Amini OS << OutputBuffer.getBuffer();
962adcd0268SBenjamin Kramer return std::string(OutputPath.str());
9638e13bc45SMehdi Amini }
9648e13bc45SMehdi Amini
9657c4a1a8dSMehdi Amini // Main entry point for the ThinLTO processing
run()9667c4a1a8dSMehdi Amini void ThinLTOCodeGenerator::run() {
967f5b8a312Smodimo timeTraceProfilerBegin("ThinLink", StringRef(""));
968f5b8a312Smodimo auto TimeTraceScopeExit = llvm::make_scope_exit([]() {
969f5b8a312Smodimo if (llvm::timeTraceProfilerEnabled())
970f5b8a312Smodimo llvm::timeTraceProfilerEnd();
971f5b8a312Smodimo });
972b2990466SMehdi Amini // Prepare the resulting object vector
973b2990466SMehdi Amini assert(ProducedBinaries.empty() && "The generator should not be reused");
974b2990466SMehdi Amini if (SavedObjectsDirectoryPath.empty())
975b2990466SMehdi Amini ProducedBinaries.resize(Modules.size());
976b2990466SMehdi Amini else {
977b2990466SMehdi Amini sys::fs::create_directories(SavedObjectsDirectoryPath);
978b2990466SMehdi Amini bool IsDir;
979b2990466SMehdi Amini sys::fs::is_directory(SavedObjectsDirectoryPath, IsDir);
980b2990466SMehdi Amini if (!IsDir)
98121661607SSimon Pilgrim report_fatal_error(Twine("Unexistent dir: '") + SavedObjectsDirectoryPath + "'");
982b2990466SMehdi Amini ProducedBinaryFiles.resize(Modules.size());
983b2990466SMehdi Amini }
984b2990466SMehdi Amini
98543b657b5SMehdi Amini if (CodeGenOnly) {
98643b657b5SMehdi Amini // Perform only parallel codegen and return.
98743b657b5SMehdi Amini ThreadPool Pool;
98843b657b5SMehdi Amini int count = 0;
98905a358cdSSteven Wu for (auto &Mod : Modules) {
99043b657b5SMehdi Amini Pool.async([&](int count) {
99143b657b5SMehdi Amini LLVMContext Context;
99243b657b5SMehdi Amini Context.setDiscardValueNames(LTODiscardValueNames);
99343b657b5SMehdi Amini
99443b657b5SMehdi Amini // Parse module now
99505a358cdSSteven Wu auto TheModule = loadModuleFromInput(Mod.get(), Context, false,
996a61f5e37STeresa Johnson /*IsImporting*/ false);
99743b657b5SMehdi Amini
99843b657b5SMehdi Amini // CodeGen
999cf90203bSSteven Wu auto OutputBuffer = codegenModule(*TheModule, *TMBuilder.create());
1000b2990466SMehdi Amini if (SavedObjectsDirectoryPath.empty())
1001b2990466SMehdi Amini ProducedBinaries[count] = std::move(OutputBuffer);
1002b2990466SMehdi Amini else
10036c9f6fd1SSteven Wu ProducedBinaryFiles[count] =
10046c9f6fd1SSteven Wu writeGeneratedObject(count, "", *OutputBuffer);
100543b657b5SMehdi Amini }, count++);
100643b657b5SMehdi Amini }
100743b657b5SMehdi Amini
100843b657b5SMehdi Amini return;
100943b657b5SMehdi Amini }
101043b657b5SMehdi Amini
10117c4a1a8dSMehdi Amini // Sequential linking phase
10127c4a1a8dSMehdi Amini auto Index = linkCombinedIndex();
10137c4a1a8dSMehdi Amini
10147c4a1a8dSMehdi Amini // Save temps: index.
10157c4a1a8dSMehdi Amini if (!SaveTempsDir.empty()) {
10167c4a1a8dSMehdi Amini auto SaveTempPath = SaveTempsDir + "index.bc";
10177c4a1a8dSMehdi Amini std::error_code EC;
1018d9b948b6SFangrui Song raw_fd_ostream OS(SaveTempPath, EC, sys::fs::OF_None);
10197c4a1a8dSMehdi Amini if (EC)
10207c4a1a8dSMehdi Amini report_fatal_error(Twine("Failed to open ") + SaveTempPath +
10217c4a1a8dSMehdi Amini " to save optimized bitcode\n");
10227aaf024dSFangrui Song writeIndexToFile(*Index, OS);
10237c4a1a8dSMehdi Amini }
10247c4a1a8dSMehdi Amini
10257c4a1a8dSMehdi Amini
10267c4a1a8dSMehdi Amini // Prepare the module map.
10277c4a1a8dSMehdi Amini auto ModuleMap = generateModuleMap(Modules);
102801e32130SMehdi Amini auto ModuleCount = Modules.size();
102901e32130SMehdi Amini
10301aafabf7SMehdi Amini // Collect for each module the list of function it defines (GUID -> Summary).
1031c851d216STeresa Johnson StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount);
10321aafabf7SMehdi Amini Index->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
10331aafabf7SMehdi Amini
10346c475a75STeresa Johnson // Convert the preserved symbols set from string to GUID, this is needed for
10356c475a75STeresa Johnson // computing the caching hash and the internalization.
103634b289b6SSteven Wu DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
103734b289b6SSteven Wu for (const auto &M : Modules)
103834b289b6SSteven Wu computeGUIDPreservedSymbols(*M, PreservedSymbols, TMBuilder.TheTriple,
103934b289b6SSteven Wu GUIDPreservedSymbols);
10406c475a75STeresa Johnson
104105a358cdSSteven Wu // Add used symbol from inputs to the preserved symbols.
104205a358cdSSteven Wu for (const auto &M : Modules)
104305a358cdSSteven Wu addUsedSymbolToPreservedGUID(*M, GUIDPreservedSymbols);
104405a358cdSSteven Wu
10456c475a75STeresa Johnson // Compute "dead" symbols, we don't want to import/export these!
1046eaf5172cSGeorge Rimar computeDeadSymbolsInIndex(*Index, GUIDPreservedSymbols);
10476c475a75STeresa Johnson
10485a7056faSEaswaran Raman // Synthesize entry counts for functions in the combined index.
10495a7056faSEaswaran Raman computeSyntheticCounts(*Index);
10505a7056faSEaswaran Raman
10512f63d549STeresa Johnson // Currently there is no support for enabling whole program visibility via a
10522f63d549STeresa Johnson // linker option in the old LTO API, but this call allows it to be specified
10532f63d549STeresa Johnson // via the internal option. Must be done before WPD below.
1054*2eade1dbSArthur Eubanks if (hasWholeProgramVisibility(/* WholeProgramVisibilityEnabledInLTO */ false))
1055*2eade1dbSArthur Eubanks Index->setWithWholeProgramVisibility();
10562f63d549STeresa Johnson updateVCallVisibilityInIndex(*Index,
10571487747eSTeresa Johnson /* WholeProgramVisibilityEnabledInLTO */ false,
10581487747eSTeresa Johnson // FIXME: This needs linker information via a
10591487747eSTeresa Johnson // TBD new interface.
10601487747eSTeresa Johnson /* DynamicExportSymbols */ {});
10612f63d549STeresa Johnson
1062eb34c3e8SEugene Leviant // Perform index-based WPD. This will return immediately if there are
1063eb34c3e8SEugene Leviant // no index entries in the typeIdMetadata map (e.g. if we are instead
1064eb34c3e8SEugene Leviant // performing IR-based WPD in hybrid regular/thin LTO mode).
1065eb34c3e8SEugene Leviant std::map<ValueInfo, std::vector<VTableSlotSummary>> LocalWPDTargetsMap;
1066eb34c3e8SEugene Leviant std::set<GlobalValue::GUID> ExportedGUIDs;
1067eb34c3e8SEugene Leviant runWholeProgramDevirtOnIndex(*Index, ExportedGUIDs, LocalWPDTargetsMap);
1068eb34c3e8SEugene Leviant for (auto GUID : ExportedGUIDs)
1069eb34c3e8SEugene Leviant GUIDPreservedSymbols.insert(GUID);
1070eb34c3e8SEugene Leviant
107101e32130SMehdi Amini // Collect the import/export lists for all modules from the call-graph in the
107201e32130SMehdi Amini // combined index.
107301e32130SMehdi Amini StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
107401e32130SMehdi Amini StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
10751aafabf7SMehdi Amini ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists,
107656584bbfSEvgeniy Stepanov ExportLists);
1077f95f77adSMehdi Amini
10784d2613f2STeresa Johnson // We use a std::map here to be able to have a defined ordering when
10794d2613f2STeresa Johnson // producing a hash for the cache entry.
10804d2613f2STeresa Johnson // FIXME: we should be able to compute the caching hash for the entry based
10814d2613f2STeresa Johnson // on the index, and nuke this map.
10824d2613f2STeresa Johnson StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
10834d2613f2STeresa Johnson
1084ea314fd4STeresa Johnson DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
1085ea314fd4STeresa Johnson computePrevailingCopies(*Index, PrevailingCopy);
1086ea314fd4STeresa Johnson
1087e61652a3SPirama Arumuga Nainar // Resolve prevailing symbols, this has to be computed early because it
10884d2613f2STeresa Johnson // impacts the caching.
1089ea314fd4STeresa Johnson resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols,
1090ea314fd4STeresa Johnson PrevailingCopy);
10914d2613f2STeresa Johnson
10924d2613f2STeresa Johnson // Use global summary-based analysis to identify symbols that can be
10934d2613f2STeresa Johnson // internalized (because they aren't exported or preserved as per callback).
10944d2613f2STeresa Johnson // Changes are made in the index, consumed in the ThinLTO backends.
1095eb34c3e8SEugene Leviant updateIndexWPDForExports(*Index,
1096eb34c3e8SEugene Leviant IsExported(ExportLists, GUIDPreservedSymbols),
1097eb34c3e8SEugene Leviant LocalWPDTargetsMap);
1098eb34c3e8SEugene Leviant thinLTOInternalizeAndPromoteInIndex(
1099eb34c3e8SEugene Leviant *Index, IsExported(ExportLists, GUIDPreservedSymbols),
1100eb34c3e8SEugene Leviant IsPrevailing(PrevailingCopy));
11014d2613f2STeresa Johnson
110220faf789Smodimo thinLTOPropagateFunctionAttrs(*Index, IsPrevailing(PrevailingCopy));
110320faf789Smodimo
1104ec53c89fSSteven Wu // Make sure that every module has an entry in the ExportLists, ImportList,
1105ec53c89fSSteven Wu // GVSummary and ResolvedODR maps to enable threaded access to these maps
1106ec53c89fSSteven Wu // below.
1107ec53c89fSSteven Wu for (auto &Module : Modules) {
110805a358cdSSteven Wu auto ModuleIdentifier = Module->getName();
1109ec53c89fSSteven Wu ExportLists[ModuleIdentifier];
1110ec53c89fSSteven Wu ImportLists[ModuleIdentifier];
1111ec53c89fSSteven Wu ResolvedODR[ModuleIdentifier];
1112ec53c89fSSteven Wu ModuleToDefinedGVSummaries[ModuleIdentifier];
1113141149ffSTeresa Johnson }
1114af52f28dSMehdi Amini
1115617d64f6SAlexandre Ganea std::vector<BitcodeModule *> ModulesVec;
1116617d64f6SAlexandre Ganea ModulesVec.reserve(Modules.size());
1117617d64f6SAlexandre Ganea for (auto &Mod : Modules)
1118617d64f6SAlexandre Ganea ModulesVec.push_back(&Mod->getSingleBitcodeModule());
1119617d64f6SAlexandre Ganea std::vector<int> ModulesOrdering = lto::generateModulesOrdering(ModulesVec);
1120819e9cdfSMehdi Amini
1121f5b8a312Smodimo if (llvm::timeTraceProfilerEnabled())
1122f5b8a312Smodimo llvm::timeTraceProfilerEnd();
1123f5b8a312Smodimo
1124f5b8a312Smodimo TimeTraceScopeExit.release();
1125f5b8a312Smodimo
11267c4a1a8dSMehdi Amini // Parallel optimizer + codegen
11277c4a1a8dSMehdi Amini {
11288404aeb5SAlexandre Ganea ThreadPool Pool(heavyweight_hardware_concurrency(ThreadCount));
1129819e9cdfSMehdi Amini for (auto IndexCount : ModulesOrdering) {
113005a358cdSSteven Wu auto &Mod = Modules[IndexCount];
11317c4a1a8dSMehdi Amini Pool.async([&](int count) {
113205a358cdSSteven Wu auto ModuleIdentifier = Mod->getName();
1133a71a5a62SMehdi Amini auto &ExportList = ExportLists[ModuleIdentifier];
11341aafabf7SMehdi Amini
1135bf46e741SEugene Leviant auto &DefinedGVSummaries = ModuleToDefinedGVSummaries[ModuleIdentifier];
1136f95f77adSMehdi Amini
1137f95f77adSMehdi Amini // The module may be cached, this helps handling it.
1138059464feSMehdi Amini ModuleCacheEntry CacheEntry(CacheOptions.Path, *Index, ModuleIdentifier,
1139059464feSMehdi Amini ImportLists[ModuleIdentifier], ExportList,
11404d2613f2STeresa Johnson ResolvedODR[ModuleIdentifier],
11415f312ad4STeresa Johnson DefinedGVSummaries, OptLevel, Freestanding,
11425f312ad4STeresa Johnson TMBuilder);
11438e13bc45SMehdi Amini auto CacheEntryPath = CacheEntry.getEntryPath();
1144f95f77adSMehdi Amini
1145f95f77adSMehdi Amini {
1146f95f77adSMehdi Amini auto ErrOrBuffer = CacheEntry.tryLoadingBuffer();
1147d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "Cache " << (ErrOrBuffer ? "hit" : "miss")
1148d34e60caSNicola Zaghen << " '" << CacheEntryPath << "' for buffer "
1149d34e60caSNicola Zaghen << count << " " << ModuleIdentifier << "\n");
1150059464feSMehdi Amini
1151f95f77adSMehdi Amini if (ErrOrBuffer) {
1152f95f77adSMehdi Amini // Cache Hit!
11538e13bc45SMehdi Amini if (SavedObjectsDirectoryPath.empty())
1154f95f77adSMehdi Amini ProducedBinaries[count] = std::move(ErrOrBuffer.get());
11558e13bc45SMehdi Amini else
11568e13bc45SMehdi Amini ProducedBinaryFiles[count] = writeGeneratedObject(
11576c9f6fd1SSteven Wu count, CacheEntryPath, *ErrOrBuffer.get());
1158f95f77adSMehdi Amini return;
1159f95f77adSMehdi Amini }
1160f95f77adSMehdi Amini }
1161f95f77adSMehdi Amini
1162f95f77adSMehdi Amini LLVMContext Context;
1163f95f77adSMehdi Amini Context.setDiscardValueNames(LTODiscardValueNames);
1164f95f77adSMehdi Amini Context.enableDebugTypeODRUniquing();
11657531a503SFrancis Visoiu Mistrih auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
116634667519SFrancis Visoiu Mistrih Context, RemarksFilename, RemarksPasses, RemarksFormat,
11673acda917SWei Wang RemarksWithHotness, RemarksHotnessThreshold, count);
116819f176b9SMehdi Amini if (!DiagFileOrErr) {
116919f176b9SMehdi Amini errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n";
117019f176b9SMehdi Amini report_fatal_error("ThinLTO: Can't get an output file for the "
117119f176b9SMehdi Amini "remarks");
117219f176b9SMehdi Amini }
1173f95f77adSMehdi Amini
11747c4a1a8dSMehdi Amini // Parse module now
117505a358cdSSteven Wu auto TheModule = loadModuleFromInput(Mod.get(), Context, false,
1176a61f5e37STeresa Johnson /*IsImporting*/ false);
11777c4a1a8dSMehdi Amini
11787c4a1a8dSMehdi Amini // Save temps: original file.
11797c4a1a8dSMehdi Amini saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc");
11807c4a1a8dSMehdi Amini
11811aafabf7SMehdi Amini auto &ImportList = ImportLists[ModuleIdentifier];
1182059464feSMehdi Amini // Run the main process now, and generates a binary
1183f95f77adSMehdi Amini auto OutputBuffer = ProcessThinLTOModule(
118401e32130SMehdi Amini *TheModule, *Index, ModuleMap, *TMBuilder.create(), ImportList,
11854d2613f2STeresa Johnson ExportList, GUIDPreservedSymbols,
11864d2613f2STeresa Johnson ModuleToDefinedGVSummaries[ModuleIdentifier], CacheOptions,
1187e978f6bcSFlorian Hahn DisableCodeGen, SaveTempsDir, Freestanding, OptLevel, count,
1188ceadf6eeSNikita Popov DebugPassManager);
1189f95f77adSMehdi Amini
11908e13bc45SMehdi Amini // Commit to the cache (if enabled)
11918e13bc45SMehdi Amini CacheEntry.write(*OutputBuffer);
11928e13bc45SMehdi Amini
11938e13bc45SMehdi Amini if (SavedObjectsDirectoryPath.empty()) {
11948e13bc45SMehdi Amini // We need to generated a memory buffer for the linker.
11958e13bc45SMehdi Amini if (!CacheEntryPath.empty()) {
11960b01dfbbSEkaterina Romanova // When cache is enabled, reload from the cache if possible.
11970b01dfbbSEkaterina Romanova // Releasing the buffer from the heap and reloading it from the
11980b01dfbbSEkaterina Romanova // cache file with mmap helps us to lower memory pressure.
11990b01dfbbSEkaterina Romanova // The freed memory can be used for the next input file.
12000b01dfbbSEkaterina Romanova // The final binary link will read from the VFS cache (hopefully!)
12010b01dfbbSEkaterina Romanova // or from disk (if the memory pressure was too high).
12028e13bc45SMehdi Amini auto ReloadedBufferOrErr = CacheEntry.tryLoadingBuffer();
12038e13bc45SMehdi Amini if (auto EC = ReloadedBufferOrErr.getError()) {
12040b01dfbbSEkaterina Romanova // On error, keep the preexisting buffer and print a diagnostic.
1205d7fad626Sromanova-ekaterina errs() << "remark: can't reload cached file '" << CacheEntryPath
12068e13bc45SMehdi Amini << "': " << EC.message() << "\n";
12078e13bc45SMehdi Amini } else {
12088e13bc45SMehdi Amini OutputBuffer = std::move(*ReloadedBufferOrErr);
12098e13bc45SMehdi Amini }
12108e13bc45SMehdi Amini }
1211f95f77adSMehdi Amini ProducedBinaries[count] = std::move(OutputBuffer);
12128e13bc45SMehdi Amini return;
12138e13bc45SMehdi Amini }
12148e13bc45SMehdi Amini ProducedBinaryFiles[count] = writeGeneratedObject(
12156c9f6fd1SSteven Wu count, CacheEntryPath, *OutputBuffer);
1216819e9cdfSMehdi Amini }, IndexCount);
12177c4a1a8dSMehdi Amini }
12187c4a1a8dSMehdi Amini }
12197c4a1a8dSMehdi Amini
1220cead56fbSPeter Collingbourne pruneCache(CacheOptions.Path, CacheOptions.Policy);
1221f95f77adSMehdi Amini
12227c4a1a8dSMehdi Amini // If statistics were requested, print them out now.
12237c4a1a8dSMehdi Amini if (llvm::AreStatisticsEnabled())
12247c4a1a8dSMehdi Amini llvm::PrintStatistics();
1225852f6fdeSJames Henderson reportAndResetTimings();
12267c4a1a8dSMehdi Amini }
1227