blob: b85471555b0921fc4cf9e4e227a3ee5bac3750c9 [file] [log] [blame]
Teresa Johnson9ba95f92016-08-11 14:58:12 +00001//===-LTOBackend.cpp - LLVM Link Time Optimizer Backend -------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Teresa Johnson9ba95f92016-08-11 14:58:12 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the "backend" phase of LTO, i.e. it performs
10// optimization and code generation on a loaded module. It is generally used
11// internally by the LTO class but can also be used independently, for example
12// to implement a standalone ThinLTO backend.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/LTO/LTOBackend.h"
Davide Italianoec9612d2016-09-07 17:46:16 +000017#include "llvm/Analysis/AliasAnalysis.h"
18#include "llvm/Analysis/CGSCCPassManager.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000019#include "llvm/Analysis/TargetLibraryInfo.h"
20#include "llvm/Analysis/TargetTransformInfo.h"
Teresa Johnsonad176792016-11-11 05:34:58 +000021#include "llvm/Bitcode/BitcodeReader.h"
22#include "llvm/Bitcode/BitcodeWriter.h"
Francis Visoiu Mistrih7531a502019-10-28 14:53:31 -070023#include "llvm/IR/LLVMRemarkStreamer.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000024#include "llvm/IR/LegacyPassManager.h"
Davide Italianoec9612d2016-09-07 17:46:16 +000025#include "llvm/IR/PassManager.h"
26#include "llvm/IR/Verifier.h"
Mehdi Amini970800e2016-08-17 06:23:09 +000027#include "llvm/LTO/LTO.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000028#include "llvm/MC/SubtargetFeature.h"
Peter Collingbourne192d8522017-03-28 23:35:34 +000029#include "llvm/Object/ModuleSymbolTable.h"
Davide Italianoec9612d2016-09-07 17:46:16 +000030#include "llvm/Passes/PassBuilder.h"
Taewook Oh213d8a92019-08-15 17:47:44 +000031#include "llvm/Passes/StandardInstrumentations.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000032#include "llvm/Support/Error.h"
33#include "llvm/Support/FileSystem.h"
Yunlian Jiangbd200b92018-04-13 05:03:28 +000034#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/Path.h"
36#include "llvm/Support/Program.h"
Teresa Johnsonc8e0bb32019-12-12 11:59:36 -080037#include "llvm/Support/SmallVectorMemoryBuffer.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000038#include "llvm/Support/TargetRegistry.h"
39#include "llvm/Support/ThreadPool.h"
Francis Visoiu Mistrih7a211132019-06-14 16:20:51 +000040#include "llvm/Support/raw_ostream.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000041#include "llvm/Target/TargetMachine.h"
42#include "llvm/Transforms/IPO.h"
43#include "llvm/Transforms/IPO/PassManagerBuilder.h"
Chandler Carruth3bab7e12017-01-11 09:43:56 +000044#include "llvm/Transforms/Scalar/LoopPassManager.h"
Teresa Johnson9ba95f92016-08-11 14:58:12 +000045#include "llvm/Transforms/Utils/FunctionImportUtils.h"
46#include "llvm/Transforms/Utils/SplitModule.h"
47
48using namespace llvm;
49using namespace lto;
50
Benjamin Kramer4c2582a2016-10-18 19:39:31 +000051LLVM_ATTRIBUTE_NORETURN static void reportOpenError(StringRef Path, Twine Msg) {
Davide Italianoa416d112016-09-17 22:32:42 +000052 errs() << "failed to open " << Path << ": " << Msg << '\n';
53 errs().flush();
54 exit(1);
55}
56
Teresa Johnson9ba95f92016-08-11 14:58:12 +000057Error Config::addSaveTemps(std::string OutputFileName,
58 bool UseInputModulePath) {
59 ShouldDiscardValueNames = false;
60
61 std::error_code EC;
Jonas Devlieghere0eaee542019-08-15 15:54:37 +000062 ResolutionFile = std::make_unique<raw_fd_ostream>(
Fangrui Songd9b948b2019-08-05 05:43:48 +000063 OutputFileName + "resolution.txt", EC, sys::fs::OpenFlags::OF_Text);
Teresa Johnson9ba95f92016-08-11 14:58:12 +000064 if (EC)
65 return errorCodeToError(EC);
66
67 auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) {
68 // Keep track of the hook provided by the linker, which also needs to run.
69 ModuleHookFn LinkerHook = Hook;
Mehdi Aminif8c2f082016-08-22 16:17:40 +000070 Hook = [=](unsigned Task, const Module &M) {
Teresa Johnson9ba95f92016-08-11 14:58:12 +000071 // If the linker's hook returned false, we need to pass that result
72 // through.
73 if (LinkerHook && !LinkerHook(Task, M))
74 return false;
75
76 std::string PathPrefix;
77 // If this is the combined module (not a ThinLTO backend compile) or the
78 // user hasn't requested using the input module's path, emit to a file
79 // named from the provided OutputFileName with the Task ID appended.
80 if (M.getModuleIdentifier() == "ld-temp.o" || !UseInputModulePath) {
Teresa Johnson81d92072018-05-05 14:37:20 +000081 PathPrefix = OutputFileName;
82 if (Task != (unsigned)-1)
83 PathPrefix += utostr(Task) + ".";
Teresa Johnson9ba95f92016-08-11 14:58:12 +000084 } else
Teresa Johnson81d92072018-05-05 14:37:20 +000085 PathPrefix = M.getModuleIdentifier() + ".";
86 std::string Path = PathPrefix + PathSuffix + ".bc";
Teresa Johnson9ba95f92016-08-11 14:58:12 +000087 std::error_code EC;
Fangrui Songd9b948b2019-08-05 05:43:48 +000088 raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::OF_None);
Davide Italianoa416d112016-09-17 22:32:42 +000089 // Because -save-temps is a debugging feature, we report the error
90 // directly and exit.
91 if (EC)
92 reportOpenError(Path, EC.message());
Rafael Espindola6a86e252018-02-14 19:11:32 +000093 WriteBitcodeToFile(M, OS, /*ShouldPreserveUseListOrder=*/false);
Teresa Johnson9ba95f92016-08-11 14:58:12 +000094 return true;
95 };
96 };
97
98 setHook("0.preopt", PreOptModuleHook);
99 setHook("1.promote", PostPromoteModuleHook);
100 setHook("2.internalize", PostInternalizeModuleHook);
101 setHook("3.import", PostImportModuleHook);
102 setHook("4.opt", PostOptModuleHook);
103 setHook("5.precodegen", PreCodeGenModuleHook);
104
evgenyad364952019-12-18 18:33:15 +0300105 CombinedIndexHook =
106 [=](const ModuleSummaryIndex &Index,
107 const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
108 std::string Path = OutputFileName + "index.bc";
109 std::error_code EC;
110 raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::OF_None);
111 // Because -save-temps is a debugging feature, we report the error
112 // directly and exit.
113 if (EC)
114 reportOpenError(Path, EC.message());
115 WriteIndexToFile(Index, OS);
Eugene Leviant28d8a492018-01-22 13:35:40 +0000116
evgenyad364952019-12-18 18:33:15 +0300117 Path = OutputFileName + "index.dot";
118 raw_fd_ostream OSDot(Path, EC, sys::fs::OpenFlags::OF_None);
119 if (EC)
120 reportOpenError(Path, EC.message());
121 Index.exportToDot(OSDot, GUIDPreservedSymbols);
122 return true;
123 };
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000124
Mehdi Amini41af4302016-11-11 04:28:40 +0000125 return Error::success();
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000126}
127
128namespace {
129
130std::unique_ptr<TargetMachine>
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800131createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) {
Evgeniy Stepanovb9f1b012017-05-22 21:11:35 +0000132 StringRef TheTriple = M.getTargetTriple();
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000133 SubtargetFeatures Features;
134 Features.getDefaultSubtargetFeatures(Triple(TheTriple));
Davide Italiano24c29b12016-09-07 01:08:31 +0000135 for (const std::string &A : Conf.MAttrs)
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000136 Features.AddFeature(A);
137
Evgeniy Stepanovb9f1b012017-05-22 21:11:35 +0000138 Reloc::Model RelocModel;
139 if (Conf.RelocModel)
140 RelocModel = *Conf.RelocModel;
141 else
142 RelocModel =
143 M.getPICLevel() == PICLevel::NotPIC ? Reloc::Static : Reloc::PIC_;
144
Caroline Tice3dea3f92018-09-21 18:41:31 +0000145 Optional<CodeModel::Model> CodeModel;
146 if (Conf.CodeModel)
147 CodeModel = *Conf.CodeModel;
148 else
149 CodeModel = M.getCodeModel();
150
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000151 return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
Evgeniy Stepanovb9f1b012017-05-22 21:11:35 +0000152 TheTriple, Conf.CPU, Features.getString(), Conf.Options, RelocModel,
Caroline Tice3dea3f92018-09-21 18:41:31 +0000153 CodeModel, Conf.CGOptLevel));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000154}
155
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800156static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
Teresa Johnson28023db2018-07-19 14:51:32 +0000157 unsigned OptLevel, bool IsThinLTO,
158 ModuleSummaryIndex *ExportSummary,
159 const ModuleSummaryIndex *ImportSummary) {
Dehao Chen89d32262017-08-02 01:28:31 +0000160 Optional<PGOOptions> PGOOpt;
161 if (!Conf.SampleProfile.empty())
Rong Xudb29a3a2019-03-04 20:21:27 +0000162 PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping,
163 PGOOptions::SampleUse, PGOOptions::NoCSAction, true);
164 else if (Conf.RunCSIRInstr) {
165 PGOOpt = PGOOptions("", Conf.CSIRProfile, Conf.ProfileRemapping,
166 PGOOptions::IRUse, PGOOptions::CSIRInstr);
167 } else if (!Conf.CSIRProfile.empty()) {
168 PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping,
169 PGOOptions::IRUse, PGOOptions::CSIRUse);
170 }
Dehao Chen89d32262017-08-02 01:28:31 +0000171
Taewook Oh213d8a92019-08-15 17:47:44 +0000172 PassInstrumentationCallbacks PIC;
173 StandardInstrumentations SI;
174 SI.registerCallbacks(PIC);
Wei Mi21a47102020-01-09 20:58:31 -0800175 PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC);
Davide Italiano0dd200e2017-01-24 00:58:24 +0000176 AAManager AA;
177
178 // Parse a custom AA pipeline if asked to.
Fedor Sergeevbd6b2132018-10-17 10:36:23 +0000179 if (auto Err = PB.parseAAPipeline(AA, "default"))
Dehao Chen3246dc32017-08-02 03:03:19 +0000180 report_fatal_error("Error parsing default AA pipeline");
Davide Italiano0dd200e2017-01-24 00:58:24 +0000181
Dehao Chen3246dc32017-08-02 03:03:19 +0000182 LoopAnalysisManager LAM(Conf.DebugPassManager);
183 FunctionAnalysisManager FAM(Conf.DebugPassManager);
184 CGSCCAnalysisManager CGAM(Conf.DebugPassManager);
185 ModuleAnalysisManager MAM(Conf.DebugPassManager);
Davide Italiano0dd200e2017-01-24 00:58:24 +0000186
187 // Register the AA manager first so that our version is the one used.
188 FAM.registerPass([&] { return std::move(AA); });
189
190 // Register all the basic analyses with the managers.
191 PB.registerModuleAnalyses(MAM);
192 PB.registerCGSCCAnalyses(CGAM);
193 PB.registerFunctionAnalyses(FAM);
194 PB.registerLoopAnalyses(LAM);
195 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
196
Dehao Chen3246dc32017-08-02 03:03:19 +0000197 ModulePassManager MPM(Conf.DebugPassManager);
Davide Italiano0dd200e2017-01-24 00:58:24 +0000198 // FIXME (davide): verify the input.
199
200 PassBuilder::OptimizationLevel OL;
201
202 switch (OptLevel) {
203 default:
204 llvm_unreachable("Invalid optimization level");
205 case 0:
Mircea Trofin7acfda62020-01-16 08:51:50 -0800206 OL = PassBuilder::OptimizationLevel::O0;
Davide Italiano0dd200e2017-01-24 00:58:24 +0000207 break;
208 case 1:
Mircea Trofin7acfda62020-01-16 08:51:50 -0800209 OL = PassBuilder::OptimizationLevel::O1;
Davide Italiano0dd200e2017-01-24 00:58:24 +0000210 break;
211 case 2:
Mircea Trofin7acfda62020-01-16 08:51:50 -0800212 OL = PassBuilder::OptimizationLevel::O2;
Davide Italiano0dd200e2017-01-24 00:58:24 +0000213 break;
214 case 3:
Mircea Trofin7acfda62020-01-16 08:51:50 -0800215 OL = PassBuilder::OptimizationLevel::O3;
Davide Italiano0dd200e2017-01-24 00:58:24 +0000216 break;
217 }
218
Chandler Carruth8b3be4e2017-06-01 11:39:39 +0000219 if (IsThinLTO)
Teresa Johnson28023db2018-07-19 14:51:32 +0000220 MPM = PB.buildThinLTODefaultPipeline(OL, Conf.DebugPassManager,
221 ImportSummary);
Chandler Carruth8b3be4e2017-06-01 11:39:39 +0000222 else
Teresa Johnson28023db2018-07-19 14:51:32 +0000223 MPM = PB.buildLTODefaultPipeline(OL, Conf.DebugPassManager, ExportSummary);
Davide Italiano0dd200e2017-01-24 00:58:24 +0000224 MPM.run(Mod, MAM);
225
226 // FIXME (davide): verify the output.
227}
228
Davide Italianoec9612d2016-09-07 17:46:16 +0000229static void runNewPMCustomPasses(Module &Mod, TargetMachine *TM,
230 std::string PipelineDesc,
Davide Italiano14e9e8a2016-09-16 21:03:21 +0000231 std::string AAPipelineDesc,
Davide Italianoec9612d2016-09-07 17:46:16 +0000232 bool DisableVerify) {
233 PassBuilder PB(TM);
234 AAManager AA;
Davide Italiano14e9e8a2016-09-16 21:03:21 +0000235
236 // Parse a custom AA pipeline if asked to.
237 if (!AAPipelineDesc.empty())
Fedor Sergeevbd6b2132018-10-17 10:36:23 +0000238 if (auto Err = PB.parseAAPipeline(AA, AAPipelineDesc))
239 report_fatal_error("unable to parse AA pipeline description '" +
240 AAPipelineDesc + "': " + toString(std::move(Err)));
Davide Italiano14e9e8a2016-09-16 21:03:21 +0000241
Davide Italianoec9612d2016-09-07 17:46:16 +0000242 LoopAnalysisManager LAM;
243 FunctionAnalysisManager FAM;
244 CGSCCAnalysisManager CGAM;
245 ModuleAnalysisManager MAM;
246
247 // Register the AA manager first so that our version is the one used.
248 FAM.registerPass([&] { return std::move(AA); });
249
250 // Register all the basic analyses with the managers.
251 PB.registerModuleAnalyses(MAM);
252 PB.registerCGSCCAnalyses(CGAM);
253 PB.registerFunctionAnalyses(FAM);
254 PB.registerLoopAnalyses(LAM);
255 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
256
257 ModulePassManager MPM;
258
259 // Always verify the input.
260 MPM.addPass(VerifierPass());
261
262 // Now, add all the passes we've been requested to.
Fedor Sergeevbd6b2132018-10-17 10:36:23 +0000263 if (auto Err = PB.parsePassPipeline(MPM, PipelineDesc))
264 report_fatal_error("unable to parse pass pipeline description '" +
265 PipelineDesc + "': " + toString(std::move(Err)));
Davide Italianoec9612d2016-09-07 17:46:16 +0000266
267 if (!DisableVerify)
268 MPM.addPass(VerifierPass());
269 MPM.run(Mod, MAM);
270}
271
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800272static void runOldPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
Peter Collingbournef7691d82017-03-22 18:22:59 +0000273 bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
274 const ModuleSummaryIndex *ImportSummary) {
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000275 legacy::PassManager passes;
276 passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
277
278 PassManagerBuilder PMB;
279 PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()));
280 PMB.Inliner = createFunctionInliningPass();
Peter Collingbournef7691d82017-03-22 18:22:59 +0000281 PMB.ExportSummary = ExportSummary;
282 PMB.ImportSummary = ImportSummary;
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000283 // Unconditionally verify input since it is not verified before this
284 // point and has unknown origin.
285 PMB.VerifyInput = true;
Davide Italiano24c29b12016-09-07 01:08:31 +0000286 PMB.VerifyOutput = !Conf.DisableVerify;
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000287 PMB.LoopVectorize = true;
288 PMB.SLPVectorize = true;
Davide Italiano24c29b12016-09-07 01:08:31 +0000289 PMB.OptLevel = Conf.OptLevel;
Dehao Chen27978002016-12-16 16:48:46 +0000290 PMB.PGOSampleUse = Conf.SampleProfile;
Rong Xudb29a3a2019-03-04 20:21:27 +0000291 PMB.EnablePGOCSInstrGen = Conf.RunCSIRInstr;
292 if (!Conf.RunCSIRInstr && !Conf.CSIRProfile.empty()) {
293 PMB.EnablePGOCSInstrUse = true;
294 PMB.PGOInstrUse = Conf.CSIRProfile;
295 }
Davide Italiano8812f282016-11-24 00:23:09 +0000296 if (IsThinLTO)
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000297 PMB.populateThinLTOPassManager(passes);
298 else
299 PMB.populateLTOPassManager(passes);
Davide Italiano24c29b12016-09-07 01:08:31 +0000300 passes.run(Mod);
Davide Italiano1e9d3d32016-08-31 17:02:44 +0000301}
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000302
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800303bool opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
Peter Collingbournef7691d82017-03-22 18:22:59 +0000304 bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
305 const ModuleSummaryIndex *ImportSummary) {
Davide Italiano0dd200e2017-01-24 00:58:24 +0000306 // FIXME: Plumb the combined index into the new pass manager.
307 if (!Conf.OptPipeline.empty())
Davide Italiano14e9e8a2016-09-16 21:03:21 +0000308 runNewPMCustomPasses(Mod, TM, Conf.OptPipeline, Conf.AAPipeline,
309 Conf.DisableVerify);
Tim Shen4e912aa2017-06-01 23:13:44 +0000310 else if (Conf.UseNewPM)
Teresa Johnson28023db2018-07-19 14:51:32 +0000311 runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary,
312 ImportSummary);
Davide Italiano0dd200e2017-01-24 00:58:24 +0000313 else
Peter Collingbournef7691d82017-03-22 18:22:59 +0000314 runOldPMPasses(Conf, Mod, TM, IsThinLTO, ExportSummary, ImportSummary);
Davide Italiano24c29b12016-09-07 01:08:31 +0000315 return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000316}
317
Teresa Johnsonc8e0bb32019-12-12 11:59:36 -0800318static cl::opt<bool> EmbedBitcode(
319 "lto-embed-bitcode", cl::init(false),
320 cl::desc("Embed LLVM bitcode in object files produced by LTO"));
321
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800322static void EmitBitcodeSection(Module &M, const Config &Conf) {
Teresa Johnsonc8e0bb32019-12-12 11:59:36 -0800323 if (!EmbedBitcode)
324 return;
325 SmallVector<char, 0> Buffer;
326 raw_svector_ostream OS(Buffer);
327 WriteBitcodeToFile(M, OS);
328
329 std::unique_ptr<MemoryBuffer> Buf(
330 new SmallVectorMemoryBuffer(std::move(Buffer)));
331 llvm::EmbedBitcodeInModule(M, Buf->getMemBufferRef(), /*EmbedBitcode*/ true,
332 /*EmbedMarker*/ false, /*CmdArgs*/ nullptr);
333}
334
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800335void codegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
Davide Italiano24c29b12016-09-07 01:08:31 +0000336 unsigned Task, Module &Mod) {
337 if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000338 return;
339
Teresa Johnsonc8e0bb32019-12-12 11:59:36 -0800340 EmitBitcodeSection(Mod, Conf);
341
Peter Collingbournec5a97652018-05-21 20:26:49 +0000342 std::unique_ptr<ToolOutputFile> DwoOut;
Aaron Pucherte1dc4952019-06-15 15:38:51 +0000343 SmallString<1024> DwoFile(Conf.SplitDwarfOutput);
Yunlian Jiangbd200b92018-04-13 05:03:28 +0000344 if (!Conf.DwoDir.empty()) {
Peter Collingbournec5a97652018-05-21 20:26:49 +0000345 std::error_code EC;
346 if (auto EC = llvm::sys::fs::create_directories(Conf.DwoDir))
347 report_fatal_error("Failed to create directory " + Conf.DwoDir + ": " +
348 EC.message());
349
Peter Collingbourne3aa30e82018-05-31 18:25:59 +0000350 DwoFile = Conf.DwoDir;
Peter Collingbournec5a97652018-05-21 20:26:49 +0000351 sys::path::append(DwoFile, std::to_string(Task) + ".dwo");
Jonas Devlieghereb2924d92020-01-29 21:14:15 -0800352 TM->Options.MCOptions.SplitDwarfFile = std::string(DwoFile);
Aaron Pucherte1dc4952019-06-15 15:38:51 +0000353 } else
354 TM->Options.MCOptions.SplitDwarfFile = Conf.SplitDwarfFile;
Peter Collingbourne3aa30e82018-05-31 18:25:59 +0000355
356 if (!DwoFile.empty()) {
357 std::error_code EC;
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000358 DwoOut = std::make_unique<ToolOutputFile>(DwoFile, EC, sys::fs::OF_None);
Peter Collingbournec5a97652018-05-21 20:26:49 +0000359 if (EC)
360 report_fatal_error("Failed to open " + DwoFile + ": " + EC.message());
Yunlian Jiangbd200b92018-04-13 05:03:28 +0000361 }
362
Peter Collingbourne80186a52016-09-23 21:33:43 +0000363 auto Stream = AddStream(Task);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000364 legacy::PassManager CodeGenPasses;
Peter Collingbournec5a97652018-05-21 20:26:49 +0000365 if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,
366 DwoOut ? &DwoOut->os() : nullptr,
Peter Collingbourne9a451142018-05-21 20:16:41 +0000367 Conf.CGFileType))
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000368 report_fatal_error("Failed to setup codegen");
Davide Italiano24c29b12016-09-07 01:08:31 +0000369 CodeGenPasses.run(Mod);
Peter Collingbournec5a97652018-05-21 20:26:49 +0000370
371 if (DwoOut)
372 DwoOut->keep();
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000373}
374
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800375void splitCodeGen(const Config &C, TargetMachine *TM, AddStreamFn AddStream,
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000376 unsigned ParallelCodeGenParallelismLevel,
Davide Italiano24c29b12016-09-07 01:08:31 +0000377 std::unique_ptr<Module> Mod) {
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000378 ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
379 unsigned ThreadCount = 0;
380 const Target *T = &TM->getTarget();
381
382 SplitModule(
Davide Italiano24c29b12016-09-07 01:08:31 +0000383 std::move(Mod), ParallelCodeGenParallelismLevel,
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000384 [&](std::unique_ptr<Module> MPart) {
385 // We want to clone the module in a new context to multi-thread the
386 // codegen. We do it by serializing partition modules to bitcode
387 // (while still on the main thread, in order to avoid data races) and
388 // spinning up new threads which deserialize the partitions into
389 // separate contexts.
390 // FIXME: Provide a more direct way to do this in LLVM.
391 SmallString<0> BC;
392 raw_svector_ostream BCOS(BC);
Rafael Espindola6a86e252018-02-14 19:11:32 +0000393 WriteBitcodeToFile(*MPart, BCOS);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000394
395 // Enqueue the task
396 CodegenThreadPool.async(
397 [&](const SmallString<0> &BC, unsigned ThreadId) {
398 LTOLLVMContext Ctx(C);
Peter Collingbourned9445c42016-11-13 07:00:17 +0000399 Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000400 MemoryBufferRef(StringRef(BC.data(), BC.size()), "ld-temp.o"),
401 Ctx);
402 if (!MOrErr)
403 report_fatal_error("Failed to read bitcode");
404 std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
405
406 std::unique_ptr<TargetMachine> TM =
Evgeniy Stepanovb9f1b012017-05-22 21:11:35 +0000407 createTargetMachine(C, T, *MPartInCtx);
Mehdi Aminiadc0e262016-08-23 21:30:12 +0000408
Peter Collingbourne80186a52016-09-23 21:33:43 +0000409 codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000410 },
411 // Pass BC using std::move to ensure that it get moved rather than
412 // copied into the thread's context.
413 std::move(BC), ThreadCount++);
414 },
415 false);
Peter Collingbournef75609e2016-09-29 03:29:28 +0000416
417 // Because the inner lambda (which runs in a worker thread) captures our local
418 // variables, we need to wait for the worker threads to terminate before we
419 // can leave the function scope.
Peter Collingbourne0d5636e2016-09-29 01:28:36 +0000420 CodegenThreadPool.wait();
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000421}
422
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800423Expected<const Target *> initAndLookupTarget(const Config &C, Module &Mod) {
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000424 if (!C.OverrideTriple.empty())
Davide Italiano24c29b12016-09-07 01:08:31 +0000425 Mod.setTargetTriple(C.OverrideTriple);
426 else if (Mod.getTargetTriple().empty())
427 Mod.setTargetTriple(C.DefaultTriple);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000428
429 std::string Msg;
Davide Italiano24c29b12016-09-07 01:08:31 +0000430 const Target *T = TargetRegistry::lookupTarget(Mod.getTargetTriple(), Msg);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000431 if (!T)
432 return make_error<StringError>(Msg, inconvertibleErrorCode());
433 return T;
434}
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000435}
436
Gabor Horvath31ae0162020-01-28 17:13:12 -0800437Error lto::finalizeOptimizationRemarks(
438 std::unique_ptr<ToolOutputFile> DiagOutputFile) {
Davide Italiano20a895c2017-02-13 14:39:51 +0000439 // Make sure we flush the diagnostic remarks file in case the linker doesn't
440 // call the global destructors before exiting.
441 if (!DiagOutputFile)
Teresa Johnson85cc2982018-05-03 20:24:12 +0000442 return Error::success();
Davide Italiano20a895c2017-02-13 14:39:51 +0000443 DiagOutputFile->keep();
444 DiagOutputFile->os().flush();
Teresa Johnson85cc2982018-05-03 20:24:12 +0000445 return Error::success();
Davide Italiano20a895c2017-02-13 14:39:51 +0000446}
447
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800448Error lto::backend(const Config &C, AddStreamFn AddStream,
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000449 unsigned ParallelCodeGenParallelismLevel,
Peter Collingbournee02b74e2017-01-20 22:18:52 +0000450 std::unique_ptr<Module> Mod,
451 ModuleSummaryIndex &CombinedIndex) {
Davide Italiano24c29b12016-09-07 01:08:31 +0000452 Expected<const Target *> TOrErr = initAndLookupTarget(C, *Mod);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000453 if (!TOrErr)
454 return TOrErr.takeError();
455
Evgeniy Stepanovb9f1b012017-05-22 21:11:35 +0000456 std::unique_ptr<TargetMachine> TM = createTargetMachine(C, *TOrErr, *Mod);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000457
Davide Italiano20a895c2017-02-13 14:39:51 +0000458 if (!C.CodeGenOnly) {
Peter Collingbournef7691d82017-03-22 18:22:59 +0000459 if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false,
Teresa Johnson85cc2982018-05-03 20:24:12 +0000460 /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr))
Gabor Horvath31ae0162020-01-28 17:13:12 -0800461 return Error::success();
Davide Italiano20a895c2017-02-13 14:39:51 +0000462 }
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000463
Mehdi Aminiadc0e262016-08-23 21:30:12 +0000464 if (ParallelCodeGenParallelismLevel == 1) {
Peter Collingbourne80186a52016-09-23 21:33:43 +0000465 codegen(C, TM.get(), AddStream, 0, *Mod);
Mehdi Aminiadc0e262016-08-23 21:30:12 +0000466 } else {
Peter Collingbourne80186a52016-09-23 21:33:43 +0000467 splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel,
Davide Italiano24c29b12016-09-07 01:08:31 +0000468 std::move(Mod));
Mehdi Aminiadc0e262016-08-23 21:30:12 +0000469 }
Gabor Horvath31ae0162020-01-28 17:13:12 -0800470 return Error::success();
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000471}
472
George Rimareaf51722018-01-29 08:03:30 +0000473static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals,
474 const ModuleSummaryIndex &Index) {
Teresa Johnson791c98e2018-02-06 00:43:39 +0000475 std::vector<GlobalValue*> DeadGVs;
Teresa Johnson5a95c472018-02-05 15:44:27 +0000476 for (auto &GV : Mod.global_values())
George Rimarf5de2712018-02-02 12:21:26 +0000477 if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID()))
Teresa Johnson791c98e2018-02-06 00:43:39 +0000478 if (!Index.isGlobalValueLive(GVS)) {
479 DeadGVs.push_back(&GV);
480 convertToDeclaration(GV);
481 }
George Rimar76c5fae2018-02-02 12:17:33 +0000482
Teresa Johnson791c98e2018-02-06 00:43:39 +0000483 // Now that all dead bodies have been dropped, delete the actual objects
484 // themselves when possible.
485 for (GlobalValue *GV : DeadGVs) {
486 GV->removeDeadConstantUsers();
487 // Might reference something defined in native object (i.e. dropped a
488 // non-prevailing IR def, but we need to keep the declaration).
489 if (GV->use_empty())
490 GV->eraseFromParent();
491 }
George Rimareaf51722018-01-29 08:03:30 +0000492}
493
Teresa Johnsond0aad9f2020-01-13 12:23:34 -0800494Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
Peter Collingbournef7691d82017-03-22 18:22:59 +0000495 Module &Mod, const ModuleSummaryIndex &CombinedIndex,
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000496 const FunctionImporter::ImportMapTy &ImportList,
497 const GVSummaryMapTy &DefinedGlobals,
Peter Collingbourne1a0720e2016-12-14 01:17:59 +0000498 MapVector<StringRef, BitcodeModule> &ModuleMap) {
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000499 Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000500 if (!TOrErr)
501 return TOrErr.takeError();
502
Evgeniy Stepanovb9f1b012017-05-22 21:11:35 +0000503 std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000504
Teresa Johnson85cc2982018-05-03 20:24:12 +0000505 // Setup optimization remarks.
Francis Visoiu Mistrih7531a502019-10-28 14:53:31 -0700506 auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
Francis Visoiu Mistrihdd422362019-03-12 21:22:27 +0000507 Mod.getContext(), Conf.RemarksFilename, Conf.RemarksPasses,
Francis Visoiu Mistrih34667512019-06-17 16:06:00 +0000508 Conf.RemarksFormat, Conf.RemarksWithHotness, Task);
Teresa Johnson85cc2982018-05-03 20:24:12 +0000509 if (!DiagFileOrErr)
510 return DiagFileOrErr.takeError();
511 auto DiagnosticOutputFile = std::move(*DiagFileOrErr);
512
Mehdi Aminid310b472016-08-22 06:25:41 +0000513 if (Conf.CodeGenOnly) {
Peter Collingbourne80186a52016-09-23 21:33:43 +0000514 codegen(Conf, TM.get(), AddStream, Task, Mod);
Teresa Johnson85cc2982018-05-03 20:24:12 +0000515 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Mehdi Aminid310b472016-08-22 06:25:41 +0000516 }
517
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000518 if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod))
Teresa Johnson85cc2982018-05-03 20:24:12 +0000519 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000520
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000521 renameModuleForThinLTO(Mod, CombinedIndex);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000522
George Rimareaf51722018-01-29 08:03:30 +0000523 dropDeadSymbols(Mod, DefinedGlobals, CombinedIndex);
524
Pirama Arumuga Nainare61652a2018-11-08 20:10:07 +0000525 thinLTOResolvePrevailingInModule(Mod, DefinedGlobals);
Mehdi Amini8ac7b322016-08-18 00:59:24 +0000526
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000527 if (Conf.PostPromoteModuleHook && !Conf.PostPromoteModuleHook(Task, Mod))
Teresa Johnson85cc2982018-05-03 20:24:12 +0000528 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000529
530 if (!DefinedGlobals.empty())
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000531 thinLTOInternalizeModule(Mod, DefinedGlobals);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000532
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000533 if (Conf.PostInternalizeModuleHook &&
534 !Conf.PostInternalizeModuleHook(Task, Mod))
Teresa Johnson85cc2982018-05-03 20:24:12 +0000535 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000536
537 auto ModuleLoader = [&](StringRef Identifier) {
Mehdi Amini9ec5a612016-08-23 16:53:34 +0000538 assert(Mod.getContext().isODRUniquingDebugTypes() &&
Davide Italiano63e8f442016-09-14 18:48:43 +0000539 "ODR Type uniquing should be enabled on the context");
Peter Collingbourne1a0720e2016-12-14 01:17:59 +0000540 auto I = ModuleMap.find(Identifier);
541 assert(I != ModuleMap.end());
542 return I->second.getLazyModule(Mod.getContext(),
Teresa Johnsona61f5e32016-12-16 21:25:01 +0000543 /*ShouldLazyLoadMetadata=*/true,
544 /*IsImporting*/ true);
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000545 };
546
547 FunctionImporter Importer(CombinedIndex, ModuleLoader);
Peter Collingbourne7f00d0a2016-11-09 17:49:19 +0000548 if (Error Err = Importer.importFunctions(Mod, ImportList).takeError())
549 return Err;
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000550
Mehdi Aminiacc50c42016-08-16 00:44:46 +0000551 if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod))
Teresa Johnson85cc2982018-05-03 20:24:12 +0000552 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000553
Peter Collingbournef7691d82017-03-22 18:22:59 +0000554 if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true,
555 /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex))
Teresa Johnson85cc2982018-05-03 20:24:12 +0000556 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000557
Peter Collingbourne80186a52016-09-23 21:33:43 +0000558 codegen(Conf, TM.get(), AddStream, Task, Mod);
Teresa Johnson85cc2982018-05-03 20:24:12 +0000559 return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
Teresa Johnson9ba95f92016-08-11 14:58:12 +0000560}