1 | //===-- gold-plugin.cpp - Plugin to gold for Link Time Optimization ------===// |
2 | // |
3 | // 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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This is a gold plugin for LLVM. It provides an LLVM implementation of the |
10 | // interface described in http://gcc.gnu.org/wiki/whopr/driver . |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/ADT/Statistic.h" |
15 | #include "llvm/Bitcode/BitcodeReader.h" |
16 | #include "llvm/Bitcode/BitcodeWriter.h" |
17 | #include "llvm/CodeGen/CommandFlags.h" |
18 | #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H |
19 | #include "llvm/Config/llvm-config.h" |
20 | #include "llvm/IR/Constants.h" |
21 | #include "llvm/IR/DiagnosticPrinter.h" |
22 | #include "llvm/LTO/LTO.h" |
23 | #include "llvm/Object/Error.h" |
24 | #include "llvm/Remarks/HotnessThresholdParser.h" |
25 | #include "llvm/Support/CachePruning.h" |
26 | #include "llvm/Support/Caching.h" |
27 | #include "llvm/Support/CommandLine.h" |
28 | #include "llvm/Support/FileSystem.h" |
29 | #include "llvm/Support/ManagedStatic.h" |
30 | #include "llvm/Support/MemoryBuffer.h" |
31 | #include "llvm/Support/Path.h" |
32 | #include "llvm/Support/TargetSelect.h" |
33 | #include "llvm/Support/Threading.h" |
34 | #include "llvm/Support/raw_ostream.h" |
35 | #include "llvm/TargetParser/Host.h" |
36 | #include <list> |
37 | #include <map> |
38 | #include <plugin-api.h> |
39 | #include <string> |
40 | #include <system_error> |
41 | #include <utility> |
42 | #include <vector> |
43 | |
44 | // FIXME: remove this declaration when we stop maintaining Ubuntu Quantal and |
45 | // Precise and Debian Wheezy (binutils 2.23 is required) |
46 | #define LDPO_PIE 3 |
47 | |
48 | #define LDPT_GET_SYMBOLS_V3 28 |
49 | |
50 | // FIXME: Remove when binutils 2.31 (containing gold 1.16) is the minimum |
51 | // required version. |
52 | #define LDPT_GET_WRAP_SYMBOLS 32 |
53 | |
54 | using namespace llvm; |
55 | using namespace lto; |
56 | |
57 | static codegen::RegisterCodeGenFlags CodeGenFlags; |
58 | |
59 | // FIXME: Remove when binutils 2.31 (containing gold 1.16) is the minimum |
60 | // required version. |
61 | typedef enum ld_plugin_status (*ld_plugin_get_wrap_symbols)( |
62 | uint64_t *num_symbols, const char ***wrap_symbol_list); |
63 | |
64 | static ld_plugin_status discard_message(int level, const char *format, ...) { |
65 | // Die loudly. Recent versions of Gold pass ld_plugin_message as the first |
66 | // callback in the transfer vector. This should never be called. |
67 | abort(); |
68 | } |
69 | |
70 | static ld_plugin_release_input_file release_input_file = nullptr; |
71 | static ld_plugin_get_input_file get_input_file = nullptr; |
72 | static ld_plugin_message message = discard_message; |
73 | static ld_plugin_get_wrap_symbols get_wrap_symbols = nullptr; |
74 | |
75 | namespace { |
76 | struct claimed_file { |
77 | void *handle; |
78 | void *leader_handle; |
79 | std::vector<ld_plugin_symbol> syms; |
80 | off_t filesize; |
81 | std::string name; |
82 | }; |
83 | |
84 | /// RAII wrapper to manage opening and releasing of a ld_plugin_input_file. |
85 | struct PluginInputFile { |
86 | void *Handle; |
87 | std::unique_ptr<ld_plugin_input_file> File; |
88 | |
89 | PluginInputFile(void *Handle) : Handle(Handle) { |
90 | File = std::make_unique<ld_plugin_input_file>(); |
91 | if (get_input_file(Handle, File.get()) != LDPS_OK) |
92 | message(LDPL_FATAL, "Failed to get file information" ); |
93 | } |
94 | ~PluginInputFile() { |
95 | // File would have been reset to nullptr if we moved this object |
96 | // to a new owner. |
97 | if (File) |
98 | if (release_input_file(Handle) != LDPS_OK) |
99 | message(LDPL_FATAL, "Failed to release file information" ); |
100 | } |
101 | |
102 | ld_plugin_input_file &file() { return *File; } |
103 | |
104 | PluginInputFile(PluginInputFile &&RHS) = default; |
105 | PluginInputFile &operator=(PluginInputFile &&RHS) = default; |
106 | }; |
107 | |
108 | struct ResolutionInfo { |
109 | bool CanOmitFromDynSym = true; |
110 | bool DefaultVisibility = true; |
111 | bool CanInline = true; |
112 | bool IsUsedInRegularObj = false; |
113 | }; |
114 | |
115 | } |
116 | |
117 | static ld_plugin_add_symbols add_symbols = nullptr; |
118 | static ld_plugin_get_symbols get_symbols = nullptr; |
119 | static ld_plugin_add_input_file add_input_file = nullptr; |
120 | static ld_plugin_set_extra_library_path = nullptr; |
121 | static ld_plugin_get_view get_view = nullptr; |
122 | static bool IsExecutable = false; |
123 | static bool SplitSections = true; |
124 | static std::optional<Reloc::Model> RelocationModel; |
125 | static std::string output_name = "" ; |
126 | static std::list<claimed_file> Modules; |
127 | static DenseMap<int, void *> FDToLeaderHandle; |
128 | static StringMap<ResolutionInfo> ResInfo; |
129 | static std::vector<std::string> Cleanup; |
130 | |
131 | namespace options { |
132 | enum OutputType { |
133 | OT_NORMAL, |
134 | OT_DISABLE, |
135 | OT_BC_ONLY, |
136 | OT_ASM_ONLY, |
137 | OT_SAVE_TEMPS |
138 | }; |
139 | static OutputType TheOutputType = OT_NORMAL; |
140 | static unsigned OptLevel = 2; |
141 | // Currently only affects ThinLTO, where the default is the max cores in the |
142 | // system. See llvm::get_threadpool_strategy() for acceptable values. |
143 | static std::string Parallelism; |
144 | // Default regular LTO codegen parallelism (number of partitions). |
145 | static unsigned ParallelCodeGenParallelismLevel = 1; |
146 | #ifdef NDEBUG |
147 | static bool DisableVerify = true; |
148 | #else |
149 | static bool DisableVerify = false; |
150 | #endif |
151 | static std::string obj_path; |
152 | static std::string ; |
153 | static std::string triple; |
154 | static std::string mcpu; |
155 | // When the thinlto plugin option is specified, only read the function |
156 | // the information from intermediate files and write a combined |
157 | // global index for the ThinLTO backends. |
158 | static bool thinlto = false; |
159 | // If false, all ThinLTO backend compilations through code gen are performed |
160 | // using multiple threads in the gold-plugin, before handing control back to |
161 | // gold. If true, write individual backend index files which reflect |
162 | // the import decisions, and exit afterwards. The assumption is |
163 | // that the build system will launch the backend processes. |
164 | static bool thinlto_index_only = false; |
165 | // If non-empty, holds the name of a file in which to write the list of |
166 | // oject files gold selected for inclusion in the link after symbol |
167 | // resolution (i.e. they had selected symbols). This will only be non-empty |
168 | // in the thinlto_index_only case. It is used to identify files, which may |
169 | // have originally been within archive libraries specified via |
170 | // --start-lib/--end-lib pairs, that should be included in the final |
171 | // native link process (since intervening function importing and inlining |
172 | // may change the symbol resolution detected in the final link and which |
173 | // files to include out of --start-lib/--end-lib libraries as a result). |
174 | static std::string thinlto_linked_objects_file; |
175 | // If true, when generating individual index files for distributed backends, |
176 | // also generate a "${bitcodefile}.imports" file at the same location for each |
177 | // bitcode file, listing the files it imports from in plain text. This is to |
178 | // support distributed build file staging. |
179 | static bool thinlto_emit_imports_files = false; |
180 | // Option to control where files for a distributed backend (the individual |
181 | // index files and optional imports files) are created. |
182 | // If specified, expects a string of the form "oldprefix:newprefix", and |
183 | // instead of generating these files in the same directory path as the |
184 | // corresponding bitcode file, will use a path formed by replacing the |
185 | // bitcode file's path prefix matching oldprefix with newprefix. |
186 | static std::string thinlto_prefix_replace; |
187 | // Option to control the name of modules encoded in the individual index |
188 | // files for a distributed backend. This enables the use of minimized |
189 | // bitcode files for the thin link, assuming the name of the full bitcode |
190 | // file used in the backend differs just in some part of the file suffix. |
191 | // If specified, expects a string of the form "oldsuffix:newsuffix". |
192 | static std::string thinlto_object_suffix_replace; |
193 | // Optional path to a directory for caching ThinLTO objects. |
194 | static std::string cache_dir; |
195 | // Optional pruning policy for ThinLTO caches. |
196 | static std::string cache_policy; |
197 | // Additional options to pass into the code generator. |
198 | // Note: This array will contain all plugin options which are not claimed |
199 | // as plugin exclusive to pass to the code generator. |
200 | static std::vector<const char *> ; |
201 | // Sample profile file path |
202 | static std::string sample_profile; |
203 | // Debug new pass manager |
204 | static bool debug_pass_manager = false; |
205 | // Directory to store the .dwo files. |
206 | static std::string dwo_dir; |
207 | /// Statistics output filename. |
208 | static std::string stats_file; |
209 | // Asserts that LTO link has whole program visibility |
210 | static bool whole_program_visibility = false; |
211 | |
212 | // Optimization remarks filename, accepted passes and hotness options |
213 | static std::string ; |
214 | static std::string ; |
215 | static bool = false; |
216 | static std::optional<uint64_t> = 0; |
217 | static std::string ; |
218 | |
219 | // Context sensitive PGO options. |
220 | static std::string cs_profile_path; |
221 | static bool cs_pgo_gen = false; |
222 | |
223 | static void process_plugin_option(const char *opt_) |
224 | { |
225 | if (opt_ == nullptr) |
226 | return; |
227 | llvm::StringRef opt = opt_; |
228 | |
229 | if (opt.consume_front(Prefix: "mcpu=" )) { |
230 | mcpu = std::string(opt); |
231 | } else if (opt.consume_front(Prefix: "extra-library-path=" )) { |
232 | extra_library_path = std::string(opt); |
233 | } else if (opt.consume_front(Prefix: "mtriple=" )) { |
234 | triple = std::string(opt); |
235 | } else if (opt.consume_front(Prefix: "obj-path=" )) { |
236 | obj_path = std::string(opt); |
237 | } else if (opt == "emit-llvm" ) { |
238 | TheOutputType = OT_BC_ONLY; |
239 | } else if (opt == "save-temps" ) { |
240 | TheOutputType = OT_SAVE_TEMPS; |
241 | } else if (opt == "disable-output" ) { |
242 | TheOutputType = OT_DISABLE; |
243 | } else if (opt == "emit-asm" ) { |
244 | TheOutputType = OT_ASM_ONLY; |
245 | } else if (opt == "thinlto" ) { |
246 | thinlto = true; |
247 | } else if (opt == "thinlto-index-only" ) { |
248 | thinlto_index_only = true; |
249 | } else if (opt.consume_front(Prefix: "thinlto-index-only=" )) { |
250 | thinlto_index_only = true; |
251 | thinlto_linked_objects_file = std::string(opt); |
252 | } else if (opt == "thinlto-emit-imports-files" ) { |
253 | thinlto_emit_imports_files = true; |
254 | } else if (opt.consume_front(Prefix: "thinlto-prefix-replace=" )) { |
255 | thinlto_prefix_replace = std::string(opt); |
256 | if (thinlto_prefix_replace.find(c: ';') == std::string::npos) |
257 | message(LDPL_FATAL, "thinlto-prefix-replace expects 'old;new' format" ); |
258 | } else if (opt.consume_front(Prefix: "thinlto-object-suffix-replace=" )) { |
259 | thinlto_object_suffix_replace = std::string(opt); |
260 | if (thinlto_object_suffix_replace.find(c: ';') == std::string::npos) |
261 | message(LDPL_FATAL, |
262 | "thinlto-object-suffix-replace expects 'old;new' format" ); |
263 | } else if (opt.consume_front(Prefix: "cache-dir=" )) { |
264 | cache_dir = std::string(opt); |
265 | } else if (opt.consume_front(Prefix: "cache-policy=" )) { |
266 | cache_policy = std::string(opt); |
267 | } else if (opt.size() == 2 && opt[0] == 'O') { |
268 | if (opt[1] < '0' || opt[1] > '3') |
269 | message(LDPL_FATAL, "Optimization level must be between 0 and 3" ); |
270 | OptLevel = opt[1] - '0'; |
271 | } else if (opt.consume_front(Prefix: "jobs=" )) { |
272 | Parallelism = std::string(opt); |
273 | if (!get_threadpool_strategy(Num: opt)) |
274 | message(LDPL_FATAL, "Invalid parallelism level: %s" , |
275 | Parallelism.c_str()); |
276 | } else if (opt.consume_front(Prefix: "lto-partitions=" )) { |
277 | if (opt.getAsInteger(Radix: 10, Result&: ParallelCodeGenParallelismLevel)) |
278 | message(LDPL_FATAL, "Invalid codegen partition level: %s" , opt_ + 5); |
279 | } else if (opt == "disable-verify" ) { |
280 | DisableVerify = true; |
281 | } else if (opt.consume_front(Prefix: "sample-profile=" )) { |
282 | sample_profile = std::string(opt); |
283 | } else if (opt == "cs-profile-generate" ) { |
284 | cs_pgo_gen = true; |
285 | } else if (opt.consume_front(Prefix: "cs-profile-path=" )) { |
286 | cs_profile_path = std::string(opt); |
287 | } else if (opt == "new-pass-manager" ) { |
288 | // We always use the new pass manager. |
289 | } else if (opt == "debug-pass-manager" ) { |
290 | debug_pass_manager = true; |
291 | } else if (opt == "whole-program-visibility" ) { |
292 | whole_program_visibility = true; |
293 | } else if (opt.consume_front(Prefix: "dwo_dir=" )) { |
294 | dwo_dir = std::string(opt); |
295 | } else if (opt.consume_front(Prefix: "opt-remarks-filename=" )) { |
296 | RemarksFilename = std::string(opt); |
297 | } else if (opt.consume_front(Prefix: "opt-remarks-passes=" )) { |
298 | RemarksPasses = std::string(opt); |
299 | } else if (opt == "opt-remarks-with-hotness" ) { |
300 | RemarksWithHotness = true; |
301 | } else if (opt.consume_front(Prefix: "opt-remarks-hotness-threshold=" )) { |
302 | auto ResultOrErr = remarks::parseHotnessThresholdOption(Arg: opt); |
303 | if (!ResultOrErr) |
304 | message(LDPL_FATAL, "Invalid remarks hotness threshold: %s" , opt); |
305 | else |
306 | RemarksHotnessThreshold = *ResultOrErr; |
307 | } else if (opt.consume_front(Prefix: "opt-remarks-format=" )) { |
308 | RemarksFormat = std::string(opt); |
309 | } else if (opt.consume_front(Prefix: "stats-file=" )) { |
310 | stats_file = std::string(opt); |
311 | } else { |
312 | // Save this option to pass to the code generator. |
313 | // ParseCommandLineOptions() expects argv[0] to be program name. Lazily |
314 | // add that. |
315 | if (extra.empty()) |
316 | extra.push_back(x: "LLVMgold" ); |
317 | |
318 | extra.push_back(x: opt_); |
319 | } |
320 | } |
321 | } |
322 | |
323 | static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, |
324 | int *claimed); |
325 | static ld_plugin_status all_symbols_read_hook(void); |
326 | static ld_plugin_status cleanup_hook(void); |
327 | |
328 | extern "C" ld_plugin_status onload(ld_plugin_tv *tv); |
329 | ld_plugin_status onload(ld_plugin_tv *tv) { |
330 | InitializeAllTargetInfos(); |
331 | InitializeAllTargets(); |
332 | InitializeAllTargetMCs(); |
333 | InitializeAllAsmParsers(); |
334 | InitializeAllAsmPrinters(); |
335 | |
336 | // We're given a pointer to the first transfer vector. We read through them |
337 | // until we find one where tv_tag == LDPT_NULL. The REGISTER_* tagged values |
338 | // contain pointers to functions that we need to call to register our own |
339 | // hooks. The others are addresses of functions we can use to call into gold |
340 | // for services. |
341 | |
342 | bool registeredClaimFile = false; |
343 | bool RegisteredAllSymbolsRead = false; |
344 | |
345 | for (; tv->tv_tag != LDPT_NULL; ++tv) { |
346 | // Cast tv_tag to int to allow values not in "enum ld_plugin_tag", like, for |
347 | // example, LDPT_GET_SYMBOLS_V3 when building against an older plugin-api.h |
348 | // header. |
349 | switch (static_cast<int>(tv->tv_tag)) { |
350 | case LDPT_OUTPUT_NAME: |
351 | output_name = tv->tv_u.tv_string; |
352 | break; |
353 | case LDPT_LINKER_OUTPUT: |
354 | switch (tv->tv_u.tv_val) { |
355 | case LDPO_REL: // .o |
356 | IsExecutable = false; |
357 | SplitSections = false; |
358 | break; |
359 | case LDPO_DYN: // .so |
360 | IsExecutable = false; |
361 | RelocationModel = Reloc::PIC_; |
362 | break; |
363 | case LDPO_PIE: // position independent executable |
364 | IsExecutable = true; |
365 | RelocationModel = Reloc::PIC_; |
366 | break; |
367 | case LDPO_EXEC: // .exe |
368 | IsExecutable = true; |
369 | RelocationModel = Reloc::Static; |
370 | break; |
371 | default: |
372 | message(LDPL_ERROR, "Unknown output file type %d" , tv->tv_u.tv_val); |
373 | return LDPS_ERR; |
374 | } |
375 | break; |
376 | case LDPT_OPTION: |
377 | options::process_plugin_option(opt_: tv->tv_u.tv_string); |
378 | break; |
379 | case LDPT_REGISTER_CLAIM_FILE_HOOK: { |
380 | ld_plugin_register_claim_file callback; |
381 | callback = tv->tv_u.tv_register_claim_file; |
382 | |
383 | if (callback(claim_file_hook) != LDPS_OK) |
384 | return LDPS_ERR; |
385 | |
386 | registeredClaimFile = true; |
387 | } break; |
388 | case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: { |
389 | ld_plugin_register_all_symbols_read callback; |
390 | callback = tv->tv_u.tv_register_all_symbols_read; |
391 | |
392 | if (callback(all_symbols_read_hook) != LDPS_OK) |
393 | return LDPS_ERR; |
394 | |
395 | RegisteredAllSymbolsRead = true; |
396 | } break; |
397 | case LDPT_REGISTER_CLEANUP_HOOK: { |
398 | ld_plugin_register_cleanup callback; |
399 | callback = tv->tv_u.tv_register_cleanup; |
400 | |
401 | if (callback(cleanup_hook) != LDPS_OK) |
402 | return LDPS_ERR; |
403 | } break; |
404 | case LDPT_GET_INPUT_FILE: |
405 | get_input_file = tv->tv_u.tv_get_input_file; |
406 | break; |
407 | case LDPT_RELEASE_INPUT_FILE: |
408 | release_input_file = tv->tv_u.tv_release_input_file; |
409 | break; |
410 | case LDPT_ADD_SYMBOLS: |
411 | add_symbols = tv->tv_u.tv_add_symbols; |
412 | break; |
413 | case LDPT_GET_SYMBOLS_V2: |
414 | // Do not override get_symbols_v3 with get_symbols_v2. |
415 | if (!get_symbols) |
416 | get_symbols = tv->tv_u.tv_get_symbols; |
417 | break; |
418 | case LDPT_GET_SYMBOLS_V3: |
419 | get_symbols = tv->tv_u.tv_get_symbols; |
420 | break; |
421 | case LDPT_ADD_INPUT_FILE: |
422 | add_input_file = tv->tv_u.tv_add_input_file; |
423 | break; |
424 | case LDPT_SET_EXTRA_LIBRARY_PATH: |
425 | set_extra_library_path = tv->tv_u.tv_set_extra_library_path; |
426 | break; |
427 | case LDPT_GET_VIEW: |
428 | get_view = tv->tv_u.tv_get_view; |
429 | break; |
430 | case LDPT_MESSAGE: |
431 | message = tv->tv_u.tv_message; |
432 | break; |
433 | case LDPT_GET_WRAP_SYMBOLS: |
434 | // FIXME: When binutils 2.31 (containing gold 1.16) is the minimum |
435 | // required version, this should be changed to: |
436 | // get_wrap_symbols = tv->tv_u.tv_get_wrap_symbols; |
437 | get_wrap_symbols = |
438 | (ld_plugin_get_wrap_symbols)tv->tv_u.tv_message; |
439 | break; |
440 | default: |
441 | break; |
442 | } |
443 | } |
444 | |
445 | if (!registeredClaimFile) { |
446 | message(LDPL_ERROR, "register_claim_file not passed to LLVMgold." ); |
447 | return LDPS_ERR; |
448 | } |
449 | if (!add_symbols) { |
450 | message(LDPL_ERROR, "add_symbols not passed to LLVMgold." ); |
451 | return LDPS_ERR; |
452 | } |
453 | |
454 | if (!RegisteredAllSymbolsRead) |
455 | return LDPS_OK; |
456 | |
457 | if (!get_input_file) { |
458 | message(LDPL_ERROR, "get_input_file not passed to LLVMgold." ); |
459 | return LDPS_ERR; |
460 | } |
461 | if (!release_input_file) { |
462 | message(LDPL_ERROR, "release_input_file not passed to LLVMgold." ); |
463 | return LDPS_ERR; |
464 | } |
465 | |
466 | return LDPS_OK; |
467 | } |
468 | |
469 | static void diagnosticHandler(const DiagnosticInfo &DI) { |
470 | std::string ErrStorage; |
471 | { |
472 | raw_string_ostream OS(ErrStorage); |
473 | DiagnosticPrinterRawOStream DP(OS); |
474 | DI.print(DP); |
475 | } |
476 | ld_plugin_level Level; |
477 | switch (DI.getSeverity()) { |
478 | case DS_Error: |
479 | Level = LDPL_FATAL; |
480 | break; |
481 | case DS_Warning: |
482 | Level = LDPL_WARNING; |
483 | break; |
484 | case DS_Note: |
485 | case DS_Remark: |
486 | Level = LDPL_INFO; |
487 | break; |
488 | } |
489 | message(Level, "LLVM gold plugin: %s" , ErrStorage.c_str()); |
490 | } |
491 | |
492 | static void check(Error E, std::string Msg = "LLVM gold plugin" ) { |
493 | handleAllErrors(E: std::move(E), Handlers: [&](ErrorInfoBase &EIB) -> Error { |
494 | message(LDPL_FATAL, "%s: %s" , Msg.c_str(), EIB.message().c_str()); |
495 | return Error::success(); |
496 | }); |
497 | } |
498 | |
499 | template <typename T> static T check(Expected<T> E) { |
500 | if (E) |
501 | return std::move(*E); |
502 | check(E.takeError()); |
503 | return T(); |
504 | } |
505 | |
506 | /// Called by gold to see whether this file is one that our plugin can handle. |
507 | /// We'll try to open it and register all the symbols with add_symbol if |
508 | /// possible. |
509 | static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, |
510 | int *claimed) { |
511 | MemoryBufferRef BufferRef; |
512 | std::unique_ptr<MemoryBuffer> Buffer; |
513 | if (get_view) { |
514 | const void *view; |
515 | if (get_view(file->handle, &view) != LDPS_OK) { |
516 | message(LDPL_ERROR, "Failed to get a view of %s" , file->name); |
517 | return LDPS_ERR; |
518 | } |
519 | BufferRef = |
520 | MemoryBufferRef(StringRef((const char *)view, file->filesize), "" ); |
521 | } else { |
522 | int64_t offset = 0; |
523 | // Gold has found what might be IR part-way inside of a file, such as |
524 | // an .a archive. |
525 | if (file->offset) { |
526 | offset = file->offset; |
527 | } |
528 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
529 | MemoryBuffer::getOpenFileSlice(FD: sys::fs::convertFDToNativeFile(FD: file->fd), |
530 | Filename: file->name, MapSize: file->filesize, Offset: offset); |
531 | if (std::error_code EC = BufferOrErr.getError()) { |
532 | message(LDPL_ERROR, EC.message().c_str()); |
533 | return LDPS_ERR; |
534 | } |
535 | Buffer = std::move(BufferOrErr.get()); |
536 | BufferRef = Buffer->getMemBufferRef(); |
537 | } |
538 | |
539 | *claimed = 1; |
540 | |
541 | Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(Object: BufferRef); |
542 | if (!ObjOrErr) { |
543 | handleAllErrors(E: ObjOrErr.takeError(), Handlers: [&](const ErrorInfoBase &EI) { |
544 | std::error_code EC = EI.convertToErrorCode(); |
545 | if (EC == object::object_error::invalid_file_type || |
546 | EC == object::object_error::bitcode_section_not_found) |
547 | *claimed = 0; |
548 | else |
549 | message(LDPL_FATAL, |
550 | "LLVM gold plugin has failed to create LTO module: %s" , |
551 | EI.message().c_str()); |
552 | }); |
553 | |
554 | return *claimed ? LDPS_ERR : LDPS_OK; |
555 | } |
556 | |
557 | std::unique_ptr<InputFile> Obj = std::move(*ObjOrErr); |
558 | |
559 | Modules.emplace_back(); |
560 | claimed_file &cf = Modules.back(); |
561 | |
562 | cf.handle = file->handle; |
563 | // Keep track of the first handle for each file descriptor, since there are |
564 | // multiple in the case of an archive. This is used later in the case of |
565 | // ThinLTO parallel backends to ensure that each file is only opened and |
566 | // released once. |
567 | auto LeaderHandle = |
568 | FDToLeaderHandle.insert(std::make_pair(file->fd, file->handle)).first; |
569 | cf.leader_handle = LeaderHandle->second; |
570 | // Save the filesize since for parallel ThinLTO backends we can only |
571 | // invoke get_input_file once per archive (only for the leader handle). |
572 | cf.filesize = file->filesize; |
573 | // In the case of an archive library, all but the first member must have a |
574 | // non-zero offset, which we can append to the file name to obtain a |
575 | // unique name. |
576 | cf.name = file->name; |
577 | if (file->offset) |
578 | cf.name += ".llvm." + std::to_string(file->offset) + "." + |
579 | sys::path::filename(path: Obj->getSourceFileName()).str(); |
580 | |
581 | for (auto &Sym : Obj->symbols()) { |
582 | cf.syms.push_back(ld_plugin_symbol()); |
583 | ld_plugin_symbol &sym = cf.syms.back(); |
584 | sym.version = nullptr; |
585 | StringRef Name = Sym.getName(); |
586 | sym.name = strdup(s: Name.str().c_str()); |
587 | |
588 | ResolutionInfo &Res = ResInfo[Name]; |
589 | |
590 | Res.CanOmitFromDynSym &= Sym.canBeOmittedFromSymbolTable(); |
591 | |
592 | sym.visibility = LDPV_DEFAULT; |
593 | GlobalValue::VisibilityTypes Vis = Sym.getVisibility(); |
594 | if (Vis != GlobalValue::DefaultVisibility) |
595 | Res.DefaultVisibility = false; |
596 | switch (Vis) { |
597 | case GlobalValue::DefaultVisibility: |
598 | break; |
599 | case GlobalValue::HiddenVisibility: |
600 | sym.visibility = LDPV_HIDDEN; |
601 | break; |
602 | case GlobalValue::ProtectedVisibility: |
603 | sym.visibility = LDPV_PROTECTED; |
604 | break; |
605 | } |
606 | |
607 | if (Sym.isUndefined()) { |
608 | sym.def = LDPK_UNDEF; |
609 | if (Sym.isWeak()) |
610 | sym.def = LDPK_WEAKUNDEF; |
611 | } else if (Sym.isCommon()) |
612 | sym.def = LDPK_COMMON; |
613 | else if (Sym.isWeak()) |
614 | sym.def = LDPK_WEAKDEF; |
615 | else |
616 | sym.def = LDPK_DEF; |
617 | |
618 | sym.size = 0; |
619 | sym.comdat_key = nullptr; |
620 | int CI = Sym.getComdatIndex(); |
621 | if (CI != -1) { |
622 | // Not setting comdat_key for nodeduplicate ensuress we don't deduplicate. |
623 | std::pair<StringRef, Comdat::SelectionKind> C = Obj->getComdatTable()[CI]; |
624 | if (C.second != Comdat::NoDeduplicate) |
625 | sym.comdat_key = strdup(s: C.first.str().c_str()); |
626 | } |
627 | |
628 | sym.resolution = LDPR_UNKNOWN; |
629 | } |
630 | |
631 | if (!cf.syms.empty()) { |
632 | if (add_symbols(cf.handle, cf.syms.size(), cf.syms.data()) != LDPS_OK) { |
633 | message(LDPL_ERROR, "Unable to add symbols!" ); |
634 | return LDPS_ERR; |
635 | } |
636 | } |
637 | |
638 | // Handle any --wrap options passed to gold, which are than passed |
639 | // along to the plugin. |
640 | if (get_wrap_symbols) { |
641 | const char **wrap_symbols; |
642 | uint64_t count = 0; |
643 | if (get_wrap_symbols(&count, &wrap_symbols) != LDPS_OK) { |
644 | message(LDPL_ERROR, "Unable to get wrap symbols!" ); |
645 | return LDPS_ERR; |
646 | } |
647 | for (uint64_t i = 0; i < count; i++) { |
648 | StringRef Name = wrap_symbols[i]; |
649 | ResolutionInfo &Res = ResInfo[Name]; |
650 | ResolutionInfo &WrapRes = ResInfo["__wrap_" + Name.str()]; |
651 | ResolutionInfo &RealRes = ResInfo["__real_" + Name.str()]; |
652 | // Tell LTO not to inline symbols that will be overwritten. |
653 | Res.CanInline = false; |
654 | RealRes.CanInline = false; |
655 | // Tell LTO not to eliminate symbols that will be used after renaming. |
656 | Res.IsUsedInRegularObj = true; |
657 | WrapRes.IsUsedInRegularObj = true; |
658 | } |
659 | } |
660 | |
661 | return LDPS_OK; |
662 | } |
663 | |
664 | static void freeSymName(ld_plugin_symbol &Sym) { |
665 | free(Sym.name); |
666 | free(Sym.comdat_key); |
667 | Sym.name = nullptr; |
668 | Sym.comdat_key = nullptr; |
669 | } |
670 | |
671 | /// Helper to get a file's symbols and a view into it via gold callbacks. |
672 | static const void *getSymbolsAndView(claimed_file &F) { |
673 | ld_plugin_status status = get_symbols(F.handle, F.syms.size(), F.syms.data()); |
674 | if (status == LDPS_NO_SYMS) |
675 | return nullptr; |
676 | |
677 | if (status != LDPS_OK) |
678 | message(LDPL_FATAL, "Failed to get symbol information" ); |
679 | |
680 | const void *View; |
681 | if (get_view(F.handle, &View) != LDPS_OK) |
682 | message(LDPL_FATAL, "Failed to get a view of file" ); |
683 | |
684 | return View; |
685 | } |
686 | |
687 | /// Parse the thinlto-object-suffix-replace option into the \p OldSuffix and |
688 | /// \p NewSuffix strings, if it was specified. |
689 | static void getThinLTOOldAndNewSuffix(std::string &OldSuffix, |
690 | std::string &NewSuffix) { |
691 | assert(options::thinlto_object_suffix_replace.empty() || |
692 | options::thinlto_object_suffix_replace.find(';') != StringRef::npos); |
693 | StringRef SuffixReplace = options::thinlto_object_suffix_replace; |
694 | auto Split = SuffixReplace.split(Separator: ';'); |
695 | OldSuffix = std::string(Split.first); |
696 | NewSuffix = std::string(Split.second); |
697 | } |
698 | |
699 | /// Given the original \p Path to an output file, replace any filename |
700 | /// suffix matching \p OldSuffix with \p NewSuffix. |
701 | static std::string getThinLTOObjectFileName(StringRef Path, StringRef OldSuffix, |
702 | StringRef NewSuffix) { |
703 | if (Path.consume_back(Suffix: OldSuffix)) |
704 | return (Path + NewSuffix).str(); |
705 | return std::string(Path); |
706 | } |
707 | |
708 | // Returns true if S is valid as a C language identifier. |
709 | static bool isValidCIdentifier(StringRef S) { |
710 | return !S.empty() && (isAlpha(C: S[0]) || S[0] == '_') && |
711 | llvm::all_of(Range: llvm::drop_begin(RangeOrContainer&: S), |
712 | P: [](char C) { return C == '_' || isAlnum(C); }); |
713 | } |
714 | |
715 | static bool isUndefined(ld_plugin_symbol &Sym) { |
716 | return Sym.def == LDPK_UNDEF || Sym.def == LDPK_WEAKUNDEF; |
717 | } |
718 | |
719 | static void addModule(LTO &Lto, claimed_file &F, const void *View, |
720 | StringRef Filename) { |
721 | MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), |
722 | Filename); |
723 | Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(Object: BufferRef); |
724 | |
725 | if (!ObjOrErr) |
726 | message(LDPL_FATAL, "Could not read bitcode from file : %s" , |
727 | toString(ObjOrErr.takeError()).c_str()); |
728 | |
729 | unsigned SymNum = 0; |
730 | std::unique_ptr<InputFile> Input = std::move(ObjOrErr.get()); |
731 | auto InputFileSyms = Input->symbols(); |
732 | assert(InputFileSyms.size() == F.syms.size()); |
733 | std::vector<SymbolResolution> Resols(F.syms.size()); |
734 | for (ld_plugin_symbol &Sym : F.syms) { |
735 | const InputFile::Symbol &InpSym = InputFileSyms[SymNum]; |
736 | SymbolResolution &R = Resols[SymNum++]; |
737 | |
738 | ld_plugin_symbol_resolution Resolution = |
739 | (ld_plugin_symbol_resolution)Sym.resolution; |
740 | |
741 | ResolutionInfo &Res = ResInfo[Sym.name]; |
742 | |
743 | switch (Resolution) { |
744 | case LDPR_UNKNOWN: |
745 | llvm_unreachable("Unexpected resolution" ); |
746 | |
747 | case LDPR_RESOLVED_IR: |
748 | case LDPR_RESOLVED_EXEC: |
749 | case LDPR_PREEMPTED_IR: |
750 | case LDPR_PREEMPTED_REG: |
751 | case LDPR_UNDEF: |
752 | break; |
753 | |
754 | case LDPR_RESOLVED_DYN: |
755 | R.ExportDynamic = true; |
756 | break; |
757 | |
758 | case LDPR_PREVAILING_DEF_IRONLY: |
759 | R.Prevailing = !isUndefined(Sym); |
760 | break; |
761 | |
762 | case LDPR_PREVAILING_DEF: |
763 | R.Prevailing = !isUndefined(Sym); |
764 | R.VisibleToRegularObj = true; |
765 | break; |
766 | |
767 | case LDPR_PREVAILING_DEF_IRONLY_EXP: |
768 | R.Prevailing = !isUndefined(Sym); |
769 | // Identify symbols exported dynamically, and that therefore could be |
770 | // referenced by a shared library not visible to the linker. |
771 | R.ExportDynamic = true; |
772 | if (!Res.CanOmitFromDynSym) |
773 | R.VisibleToRegularObj = true; |
774 | break; |
775 | } |
776 | |
777 | // If the symbol has a C identifier section name, we need to mark |
778 | // it as visible to a regular object so that LTO will keep it around |
779 | // to ensure the linker generates special __start_<secname> and |
780 | // __stop_<secname> symbols which may be used elsewhere. |
781 | if (isValidCIdentifier(InpSym.getSectionName())) |
782 | R.VisibleToRegularObj = true; |
783 | |
784 | if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF && |
785 | (IsExecutable || !Res.DefaultVisibility)) |
786 | R.FinalDefinitionInLinkageUnit = true; |
787 | |
788 | if (!Res.CanInline) |
789 | R.LinkerRedefined = true; |
790 | |
791 | if (Res.IsUsedInRegularObj) |
792 | R.VisibleToRegularObj = true; |
793 | |
794 | freeSymName(Sym); |
795 | } |
796 | |
797 | check(E: Lto.add(Obj: std::move(Input), Res: Resols), |
798 | Msg: std::string("Failed to link module " ) + F.name); |
799 | } |
800 | |
801 | static void recordFile(const std::string &Filename, bool TempOutFile) { |
802 | if (add_input_file(Filename.c_str()) != LDPS_OK) |
803 | message(LDPL_FATAL, |
804 | "Unable to add .o file to the link. File left behind in: %s" , |
805 | Filename.c_str()); |
806 | if (TempOutFile) |
807 | Cleanup.push_back(x: Filename); |
808 | } |
809 | |
810 | /// Return the desired output filename given a base input name, a flag |
811 | /// indicating whether a temp file should be generated, and an optional task id. |
812 | /// The new filename generated is returned in \p NewFilename. |
813 | static int getOutputFileName(StringRef InFilename, bool TempOutFile, |
814 | SmallString<128> &NewFilename, int TaskID) { |
815 | int FD = -1; |
816 | if (TempOutFile) { |
817 | std::error_code EC = |
818 | sys::fs::createTemporaryFile(Prefix: "lto-llvm" , Suffix: "o" , ResultFD&: FD, ResultPath&: NewFilename); |
819 | if (EC) |
820 | message(LDPL_FATAL, "Could not create temporary file: %s" , |
821 | EC.message().c_str()); |
822 | } else { |
823 | NewFilename = InFilename; |
824 | if (TaskID > 0) |
825 | NewFilename += utostr(X: TaskID); |
826 | std::error_code EC = |
827 | sys::fs::openFileForWrite(Name: NewFilename, ResultFD&: FD, Disp: sys::fs::CD_CreateAlways); |
828 | if (EC) |
829 | message(LDPL_FATAL, "Could not open file %s: %s" , NewFilename.c_str(), |
830 | EC.message().c_str()); |
831 | } |
832 | return FD; |
833 | } |
834 | |
835 | /// Parse the thinlto_prefix_replace option into the \p OldPrefix and |
836 | /// \p NewPrefix strings, if it was specified. |
837 | static void getThinLTOOldAndNewPrefix(std::string &OldPrefix, |
838 | std::string &NewPrefix) { |
839 | StringRef PrefixReplace = options::thinlto_prefix_replace; |
840 | assert(PrefixReplace.empty() || PrefixReplace.find(';') != StringRef::npos); |
841 | auto Split = PrefixReplace.split(Separator: ';'); |
842 | OldPrefix = std::string(Split.first); |
843 | NewPrefix = std::string(Split.second); |
844 | } |
845 | |
846 | /// Creates instance of LTO. |
847 | /// OnIndexWrite is callback to let caller know when LTO writes index files. |
848 | /// LinkedObjectsFile is an output stream to write the list of object files for |
849 | /// the final ThinLTO linking. Can be nullptr. |
850 | static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite, |
851 | raw_fd_ostream *LinkedObjectsFile) { |
852 | Config Conf; |
853 | ThinBackend Backend; |
854 | |
855 | Conf.CPU = options::mcpu; |
856 | Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple()); |
857 | |
858 | // Disable the new X86 relax relocations since gold might not support them. |
859 | // FIXME: Check the gold version or add a new option to enable them. |
860 | Conf.Options.MCOptions.X86RelaxRelocations = false; |
861 | |
862 | // Toggle function/data sections. |
863 | if (!codegen::getExplicitFunctionSections()) |
864 | Conf.Options.FunctionSections = SplitSections; |
865 | if (!codegen::getExplicitDataSections()) |
866 | Conf.Options.DataSections = SplitSections; |
867 | |
868 | Conf.MAttrs = codegen::getMAttrs(); |
869 | Conf.RelocModel = RelocationModel; |
870 | Conf.CodeModel = codegen::getExplicitCodeModel(); |
871 | std::optional<CodeGenOptLevel> CGOptLevelOrNone = |
872 | CodeGenOpt::getLevel(OL: options::OptLevel); |
873 | assert(CGOptLevelOrNone && "Invalid optimization level" ); |
874 | Conf.CGOptLevel = *CGOptLevelOrNone; |
875 | Conf.DisableVerify = options::DisableVerify; |
876 | Conf.OptLevel = options::OptLevel; |
877 | Conf.PTO.LoopVectorization = options::OptLevel > 1; |
878 | Conf.PTO.SLPVectorization = options::OptLevel > 1; |
879 | Conf.AlwaysEmitRegularLTOObj = !options::obj_path.empty(); |
880 | |
881 | if (options::thinlto_index_only) { |
882 | std::string OldPrefix, NewPrefix; |
883 | getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix); |
884 | Backend = createWriteIndexesThinBackend( |
885 | OldPrefix, NewPrefix, |
886 | // TODO: Add support for optional native object path in |
887 | // thinlto_prefix_replace option to match lld. |
888 | /*NativeObjectPrefix=*/"" , ShouldEmitImportsFiles: options::thinlto_emit_imports_files, |
889 | LinkedObjectsFile, OnWrite: OnIndexWrite); |
890 | } else { |
891 | Backend = createInProcessThinBackend( |
892 | Parallelism: llvm::heavyweight_hardware_concurrency(Num: options::Parallelism)); |
893 | } |
894 | |
895 | Conf.OverrideTriple = options::triple; |
896 | Conf.DefaultTriple = sys::getDefaultTargetTriple(); |
897 | |
898 | Conf.DiagHandler = diagnosticHandler; |
899 | |
900 | switch (options::TheOutputType) { |
901 | case options::OT_NORMAL: |
902 | break; |
903 | |
904 | case options::OT_DISABLE: |
905 | Conf.PreOptModuleHook = [](size_t Task, const Module &M) { return false; }; |
906 | break; |
907 | |
908 | case options::OT_BC_ONLY: |
909 | Conf.PostInternalizeModuleHook = [](size_t Task, const Module &M) { |
910 | std::error_code EC; |
911 | SmallString<128> TaskFilename; |
912 | getOutputFileName(InFilename: output_name, /* TempOutFile */ false, NewFilename&: TaskFilename, |
913 | TaskID: Task); |
914 | raw_fd_ostream OS(TaskFilename, EC, sys::fs::OpenFlags::OF_None); |
915 | if (EC) |
916 | message(LDPL_FATAL, "Failed to write the output file." ); |
917 | WriteBitcodeToFile(M, Out&: OS, /* ShouldPreserveUseListOrder */ false); |
918 | return false; |
919 | }; |
920 | break; |
921 | |
922 | case options::OT_SAVE_TEMPS: |
923 | check(E: Conf.addSaveTemps(OutputFileName: output_name + "." , |
924 | /* UseInputModulePath */ true)); |
925 | break; |
926 | case options::OT_ASM_ONLY: |
927 | Conf.CGFileType = CodeGenFileType::AssemblyFile; |
928 | Conf.Options.MCOptions.AsmVerbose = true; |
929 | break; |
930 | } |
931 | |
932 | if (!options::sample_profile.empty()) |
933 | Conf.SampleProfile = options::sample_profile; |
934 | |
935 | if (!options::cs_profile_path.empty()) |
936 | Conf.CSIRProfile = options::cs_profile_path; |
937 | Conf.RunCSIRInstr = options::cs_pgo_gen; |
938 | |
939 | Conf.DwoDir = options::dwo_dir; |
940 | |
941 | // Set up optimization remarks handling. |
942 | Conf.RemarksFilename = options::RemarksFilename; |
943 | Conf.RemarksPasses = options::RemarksPasses; |
944 | Conf.RemarksWithHotness = options::RemarksWithHotness; |
945 | Conf.RemarksHotnessThreshold = options::RemarksHotnessThreshold; |
946 | Conf.RemarksFormat = options::RemarksFormat; |
947 | |
948 | // Debug new pass manager if requested |
949 | Conf.DebugPassManager = options::debug_pass_manager; |
950 | |
951 | Conf.HasWholeProgramVisibility = options::whole_program_visibility; |
952 | |
953 | Conf.StatsFile = options::stats_file; |
954 | return std::make_unique<LTO>(args: std::move(Conf), args&: Backend, |
955 | args&: options::ParallelCodeGenParallelismLevel); |
956 | } |
957 | |
958 | // Write empty files that may be expected by a distributed build |
959 | // system when invoked with thinlto_index_only. This is invoked when |
960 | // the linker has decided not to include the given module in the |
961 | // final link. Frequently the distributed build system will want to |
962 | // confirm that all expected outputs are created based on all of the |
963 | // modules provided to the linker. |
964 | // If SkipModule is true then .thinlto.bc should contain just |
965 | // SkipModuleByDistributedBackend flag which requests distributed backend |
966 | // to skip the compilation of the corresponding module and produce an empty |
967 | // object file. |
968 | static void writeEmptyDistributedBuildOutputs(const std::string &ModulePath, |
969 | const std::string &OldPrefix, |
970 | const std::string &NewPrefix, |
971 | bool SkipModule) { |
972 | std::string NewModulePath = |
973 | getThinLTOOutputFile(Path: ModulePath, OldPrefix, NewPrefix); |
974 | std::error_code EC; |
975 | { |
976 | raw_fd_ostream OS(NewModulePath + ".thinlto.bc" , EC, |
977 | sys::fs::OpenFlags::OF_None); |
978 | if (EC) |
979 | message(LDPL_FATAL, "Failed to write '%s': %s" , |
980 | (NewModulePath + ".thinlto.bc" ).c_str(), EC.message().c_str()); |
981 | |
982 | if (SkipModule) { |
983 | ModuleSummaryIndex Index(/*HaveGVs*/ false); |
984 | Index.setSkipModuleByDistributedBackend(); |
985 | writeIndexToFile(Index, Out&: OS, ModuleToSummariesForIndex: nullptr); |
986 | } |
987 | } |
988 | if (options::thinlto_emit_imports_files) { |
989 | raw_fd_ostream OS(NewModulePath + ".imports" , EC, |
990 | sys::fs::OpenFlags::OF_None); |
991 | if (EC) |
992 | message(LDPL_FATAL, "Failed to write '%s': %s" , |
993 | (NewModulePath + ".imports" ).c_str(), EC.message().c_str()); |
994 | } |
995 | } |
996 | |
997 | // Creates and returns output stream with a list of object files for final |
998 | // linking of distributed ThinLTO. |
999 | static std::unique_ptr<raw_fd_ostream> CreateLinkedObjectsFile() { |
1000 | if (options::thinlto_linked_objects_file.empty()) |
1001 | return nullptr; |
1002 | assert(options::thinlto_index_only); |
1003 | std::error_code EC; |
1004 | auto LinkedObjectsFile = std::make_unique<raw_fd_ostream>( |
1005 | args&: options::thinlto_linked_objects_file, args&: EC, args: sys::fs::OpenFlags::OF_None); |
1006 | if (EC) |
1007 | message(LDPL_FATAL, "Failed to create '%s': %s" , |
1008 | options::thinlto_linked_objects_file.c_str(), EC.message().c_str()); |
1009 | return LinkedObjectsFile; |
1010 | } |
1011 | |
1012 | /// Runs LTO and return a list of pairs <FileName, IsTemporary>. |
1013 | static std::vector<std::pair<SmallString<128>, bool>> runLTO() { |
1014 | // Map to own RAII objects that manage the file opening and releasing |
1015 | // interfaces with gold. This is needed only for ThinLTO mode, since |
1016 | // unlike regular LTO, where addModule will result in the opened file |
1017 | // being merged into a new combined module, we need to keep these files open |
1018 | // through Lto->run(). |
1019 | DenseMap<void *, std::unique_ptr<PluginInputFile>> HandleToInputFile; |
1020 | |
1021 | // Owns string objects and tells if index file was already created. |
1022 | StringMap<bool> ObjectToIndexFileState; |
1023 | |
1024 | std::unique_ptr<raw_fd_ostream> LinkedObjects = CreateLinkedObjectsFile(); |
1025 | std::unique_ptr<LTO> Lto = createLTO( |
1026 | OnIndexWrite: [&ObjectToIndexFileState](const std::string &Identifier) { |
1027 | ObjectToIndexFileState[Identifier] = true; |
1028 | }, |
1029 | LinkedObjectsFile: LinkedObjects.get()); |
1030 | |
1031 | std::string OldPrefix, NewPrefix; |
1032 | if (options::thinlto_index_only) |
1033 | getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix); |
1034 | |
1035 | std::string OldSuffix, NewSuffix; |
1036 | getThinLTOOldAndNewSuffix(OldSuffix, NewSuffix); |
1037 | |
1038 | for (claimed_file &F : Modules) { |
1039 | if (options::thinlto && !HandleToInputFile.count(Val: F.leader_handle)) |
1040 | HandleToInputFile.insert(KV: std::make_pair( |
1041 | x&: F.leader_handle, y: std::make_unique<PluginInputFile>(args&: F.handle))); |
1042 | // In case we are thin linking with a minimized bitcode file, ensure |
1043 | // the module paths encoded in the index reflect where the backends |
1044 | // will locate the full bitcode files for compiling/importing. |
1045 | std::string Identifier = |
1046 | getThinLTOObjectFileName(Path: F.name, OldSuffix, NewSuffix); |
1047 | auto ObjFilename = ObjectToIndexFileState.insert(KV: {Identifier, false}); |
1048 | assert(ObjFilename.second); |
1049 | if (const void *View = getSymbolsAndView(F)) |
1050 | addModule(Lto&: *Lto, F, View, Filename: ObjFilename.first->first()); |
1051 | else if (options::thinlto_index_only) { |
1052 | ObjFilename.first->second = true; |
1053 | writeEmptyDistributedBuildOutputs(ModulePath: Identifier, OldPrefix, NewPrefix, |
1054 | /* SkipModule */ true); |
1055 | } |
1056 | } |
1057 | |
1058 | SmallString<128> Filename; |
1059 | // Note that getOutputFileName will append a unique ID for each task |
1060 | if (!options::obj_path.empty()) |
1061 | Filename = options::obj_path; |
1062 | else if (options::TheOutputType == options::OT_SAVE_TEMPS) |
1063 | Filename = output_name + ".lto.o" ; |
1064 | else if (options::TheOutputType == options::OT_ASM_ONLY) |
1065 | Filename = output_name; |
1066 | bool SaveTemps = !Filename.empty(); |
1067 | |
1068 | size_t MaxTasks = Lto->getMaxTasks(); |
1069 | std::vector<std::pair<SmallString<128>, bool>> Files(MaxTasks); |
1070 | |
1071 | auto AddStream = |
1072 | [&](size_t Task, |
1073 | const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> { |
1074 | Files[Task].second = !SaveTemps; |
1075 | int FD = getOutputFileName(InFilename: Filename, /* TempOutFile */ !SaveTemps, |
1076 | NewFilename&: Files[Task].first, TaskID: Task); |
1077 | return std::make_unique<CachedFileStream>( |
1078 | args: std::make_unique<llvm::raw_fd_ostream>(args&: FD, args: true)); |
1079 | }; |
1080 | |
1081 | auto AddBuffer = [&](size_t Task, const Twine &moduleName, |
1082 | std::unique_ptr<MemoryBuffer> MB) { |
1083 | *AddStream(Task, moduleName)->OS << MB->getBuffer(); |
1084 | }; |
1085 | |
1086 | FileCache Cache; |
1087 | if (!options::cache_dir.empty()) |
1088 | Cache = check(E: localCache(CacheNameRef: "ThinLTO" , TempFilePrefixRef: "Thin" , CacheDirectoryPathRef: options::cache_dir, AddBuffer)); |
1089 | |
1090 | check(E: Lto->run(AddStream, Cache)); |
1091 | |
1092 | // Write empty output files that may be expected by the distributed build |
1093 | // system. |
1094 | if (options::thinlto_index_only) |
1095 | for (auto &Identifier : ObjectToIndexFileState) |
1096 | if (!Identifier.getValue()) |
1097 | writeEmptyDistributedBuildOutputs(ModulePath: std::string(Identifier.getKey()), |
1098 | OldPrefix, NewPrefix, |
1099 | /* SkipModule */ false); |
1100 | |
1101 | return Files; |
1102 | } |
1103 | |
1104 | /// gold informs us that all symbols have been read. At this point, we use |
1105 | /// get_symbols to see if any of our definitions have been overridden by a |
1106 | /// native object file. Then, perform optimization and codegen. |
1107 | static ld_plugin_status allSymbolsReadHook() { |
1108 | if (Modules.empty()) |
1109 | return LDPS_OK; |
1110 | |
1111 | if (unsigned NumOpts = options::extra.size()) |
1112 | cl::ParseCommandLineOptions(argc: NumOpts, argv: &options::extra[0]); |
1113 | |
1114 | std::vector<std::pair<SmallString<128>, bool>> Files = runLTO(); |
1115 | |
1116 | if (options::TheOutputType == options::OT_DISABLE || |
1117 | options::TheOutputType == options::OT_BC_ONLY || |
1118 | options::TheOutputType == options::OT_ASM_ONLY) |
1119 | return LDPS_OK; |
1120 | |
1121 | if (options::thinlto_index_only) { |
1122 | llvm_shutdown(); |
1123 | cleanup_hook(); |
1124 | exit(status: 0); |
1125 | } |
1126 | |
1127 | for (const auto &F : Files) |
1128 | if (!F.first.empty()) |
1129 | recordFile(Filename: std::string(F.first.str()), TempOutFile: F.second); |
1130 | |
1131 | if (!options::extra_library_path.empty() && |
1132 | set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK) |
1133 | message(LDPL_FATAL, "Unable to set the extra library path." ); |
1134 | |
1135 | return LDPS_OK; |
1136 | } |
1137 | |
1138 | static ld_plugin_status all_symbols_read_hook(void) { |
1139 | ld_plugin_status Ret = allSymbolsReadHook(); |
1140 | llvm_shutdown(); |
1141 | |
1142 | if (options::TheOutputType == options::OT_BC_ONLY || |
1143 | options::TheOutputType == options::OT_ASM_ONLY || |
1144 | options::TheOutputType == options::OT_DISABLE) { |
1145 | if (options::TheOutputType == options::OT_DISABLE) { |
1146 | // Remove the output file here since ld.bfd creates the output file |
1147 | // early. |
1148 | std::error_code EC = sys::fs::remove(path: output_name); |
1149 | if (EC) |
1150 | message(LDPL_ERROR, "Failed to delete '%s': %s" , output_name.c_str(), |
1151 | EC.message().c_str()); |
1152 | } |
1153 | exit(status: 0); |
1154 | } |
1155 | |
1156 | return Ret; |
1157 | } |
1158 | |
1159 | static ld_plugin_status cleanup_hook(void) { |
1160 | for (std::string &Name : Cleanup) { |
1161 | std::error_code EC = sys::fs::remove(path: Name); |
1162 | if (EC) |
1163 | message(LDPL_ERROR, "Failed to delete '%s': %s" , Name.c_str(), |
1164 | EC.message().c_str()); |
1165 | } |
1166 | |
1167 | // Prune cache |
1168 | if (!options::cache_dir.empty()) { |
1169 | CachePruningPolicy policy = check(E: parseCachePruningPolicy(PolicyStr: options::cache_policy)); |
1170 | pruneCache(Path: options::cache_dir, Policy: policy); |
1171 | } |
1172 | |
1173 | return LDPS_OK; |
1174 | } |
1175 | |