1//===-lto.cpp - LLVM Link Time Optimizer ----------------------------------===//
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 file implements the Link Time Optimization library. This library is
10// intended to be used by linker to optimize code at link time.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm-c/lto.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Bitcode/BitcodeReader.h"
19#include "llvm/CodeGen/CommandFlags.h"
20#include "llvm/IR/DiagnosticInfo.h"
21#include "llvm/IR/DiagnosticPrinter.h"
22#include "llvm/IR/LLVMContext.h"
23#include "llvm/LTO/LTO.h"
24#include "llvm/LTO/legacy/LTOCodeGenerator.h"
25#include "llvm/LTO/legacy/LTOModule.h"
26#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/LibraryOptionsContext.h"
29#include "llvm/Support/MemoryBuffer.h"
30#include "llvm/Support/Signals.h"
31#include "llvm/Support/TargetSelect.h"
32#include "llvm/Support/raw_ostream.h"
33
34using namespace llvm;
35
36static codegen::RegisterCodeGenFlags CGF;
37
38// extra command-line flags needed for LTOCodeGenerator
39static cl::opt<char>
40 OptLevel("O",
41 cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
42 "(default = '-O2')"),
43 cl::Prefix, cl::init(Val: '2'));
44
45static cl::opt<bool> EnableFreestanding(
46 "lto-freestanding", cl::init(Val: false),
47 cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"));
48
49static cl::opt<std::string> ThinLTOCacheDir(
50 "legacy-thinlto-cache-dir",
51 cl::desc("Experimental option, enable ThinLTO caching. Note: the cache "
52 "currently does not take the mcmodel setting into account, so you "
53 "might get false hits if different mcmodels are used in different "
54 "builds using the same cache directory."));
55
56static cl::opt<int> ThinLTOCachePruningInterval(
57 "legacy-thinlto-cache-pruning-interval", cl::init(Val: 1200),
58 cl::desc("Set ThinLTO cache pruning interval (seconds)."));
59
60static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
61 "legacy-thinlto-cache-max-size-bytes",
62 cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."));
63
64static cl::opt<int> ThinLTOCacheMaxSizeFiles(
65 "legacy-thinlto-cache-max-size-files", cl::init(Val: 1000000),
66 cl::desc("Set ThinLTO cache pruning directory maximum number of files."));
67
68static cl::opt<unsigned> ThinLTOCacheEntryExpiration(
69 "legacy-thinlto-cache-entry-expiration", cl::init(Val: 604800) /* 1w */,
70 cl::desc("Set ThinLTO cache entry expiration time (seconds)."));
71
72#ifdef NDEBUG
73static bool VerifyByDefault = false;
74#else
75static bool VerifyByDefault = true;
76#endif
77
78static cl::opt<bool> DisableVerify(
79 "disable-llvm-verifier", cl::init(Val: !VerifyByDefault),
80 cl::desc("Don't run the LLVM verifier during the optimization pipeline"));
81
82// Holds most recent error string.
83// *** Not thread safe ***
84static std::string sLastErrorString;
85
86// Holds the initialization state of the LTO module.
87// *** Not thread safe ***
88static bool initialized = false;
89
90// Represent the state of parsing command line debug options.
91static enum class OptParsingState {
92 NotParsed, // Initial state.
93 Early, // After lto_set_debug_options is called.
94 Done // After maybeParseOptions is called.
95} optionParsingState = OptParsingState::NotParsed;
96
97static LLVMContext *LTOContext = nullptr;
98
99// Records -mllvm arguments parsed through the legacy debug-option APIs.
100static std::vector<std::string> ThinLTOMllvmArgs;
101
102struct LTOToolDiagnosticHandler : public DiagnosticHandler {
103 bool handleDiagnostics(const DiagnosticInfo &DI) override {
104 if (DI.getSeverity() != DS_Error) {
105 DiagnosticPrinterRawOStream DP(errs());
106 DI.print(DP);
107 errs() << '\n';
108 return true;
109 }
110 sLastErrorString = "";
111 {
112 raw_string_ostream Stream(sLastErrorString);
113 DiagnosticPrinterRawOStream DP(Stream);
114 DI.print(DP);
115 }
116 return true;
117 }
118};
119
120static SmallVector<const char *> RuntimeLibcallSymbols;
121
122// Initialize the configured targets if they have not been initialized.
123static void lto_initialize() {
124 if (!initialized) {
125#ifdef _WIN32
126 // Dialog box on crash disabling doesn't work across DLL boundaries, so do
127 // it here.
128 llvm::sys::DisableSystemDialogsOnCrash();
129#endif
130
131 InitializeAllTargetInfos();
132 InitializeAllTargets();
133 InitializeAllTargetMCs();
134 InitializeAllAsmParsers();
135 InitializeAllAsmPrinters();
136 InitializeAllDisassemblers();
137
138 static LLVMContext Context;
139 LTOContext = &Context;
140 LTOContext->setDiagnosticHandler(
141 DH: std::make_unique<LTOToolDiagnosticHandler>(), RespectFilters: true);
142 RuntimeLibcallSymbols = lto::LTO::getRuntimeLibcallSymbols(TT: Triple());
143 initialized = true;
144 }
145}
146
147namespace {
148
149static void handleLibLTODiagnostic(lto_codegen_diagnostic_severity_t Severity,
150 const char *Msg, void *) {
151 sLastErrorString = Msg;
152}
153
154// This derived class owns the native object file. This helps implement the
155// libLTO API semantics, which require that the code generator owns the object
156// file.
157struct LibLTOCodeGenerator : LTOCodeGenerator {
158 LibLTOCodeGenerator() : LTOCodeGenerator(*LTOContext) { init(); }
159 LibLTOCodeGenerator(std::unique_ptr<LLVMContext> Context)
160 : LTOCodeGenerator(*Context), OwnedContext(std::move(Context)) {
161 OwnedContext->getLibraryOptions().assign(Other: LTOContext->getLibraryOptions());
162 init();
163 }
164
165 // Reset the module first in case MergedModule is created in OwnedContext.
166 // Module must be destructed before its context gets destructed.
167 ~LibLTOCodeGenerator() { resetMergedModule(); }
168
169 void init() { setDiagnosticHandler(handleLibLTODiagnostic, nullptr); }
170
171 std::unique_ptr<MemoryBuffer> NativeObjectFile;
172 std::unique_ptr<LLVMContext> OwnedContext;
173};
174
175}
176
177DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LibLTOCodeGenerator, lto_code_gen_t)
178DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThinLTOCodeGenerator, thinlto_code_gen_t)
179DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LTOModule, lto_module_t)
180
181// Convert the subtarget features into a string to pass to LTOCodeGenerator.
182static void lto_add_attrs(lto_code_gen_t cg) {
183 LTOCodeGenerator *CG = unwrap(P: cg);
184 CG->setAttrs(codegen::getMAttrs());
185
186 if (OptLevel < '0' || OptLevel > '3')
187 report_fatal_error(reason: "Optimization level must be between 0 and 3");
188 CG->setOptLevel(OptLevel - '0');
189 CG->setFreestanding(EnableFreestanding);
190 CG->setDisableVerify(DisableVerify);
191}
192
193extern const char* lto_get_version() {
194 return LTOCodeGenerator::getVersionString();
195}
196
197const char* lto_get_error_message() {
198 return sLastErrorString.c_str();
199}
200
201bool lto_module_is_object_file(const char* path) {
202 return LTOModule::isBitcodeFile(path: StringRef(path));
203}
204
205bool lto_module_is_object_file_for_target(const char* path,
206 const char* target_triplet_prefix) {
207 ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFile(Filename: path);
208 if (!Buffer)
209 return false;
210 return LTOModule::isBitcodeForTarget(memBuffer: Buffer->get(),
211 triplePrefix: StringRef(target_triplet_prefix));
212}
213
214bool lto_module_has_objc_category(const void *mem, size_t length) {
215 std::unique_ptr<MemoryBuffer> Buffer(LTOModule::makeBuffer(mem, length));
216 if (!Buffer)
217 return false;
218 LLVMContext Ctx;
219 ErrorOr<bool> Result = expectedToErrorOrAndEmitErrors(
220 Ctx, Val: llvm::isBitcodeContainingObjCCategory(Buffer: *Buffer));
221 return Result && *Result;
222}
223
224bool lto_module_is_object_file_in_memory(const void* mem, size_t length) {
225 return LTOModule::isBitcodeFile(mem, length);
226}
227
228bool
229lto_module_is_object_file_in_memory_for_target(const void* mem,
230 size_t length,
231 const char* target_triplet_prefix) {
232 std::unique_ptr<MemoryBuffer> buffer(LTOModule::makeBuffer(mem, length));
233 if (!buffer)
234 return false;
235 return LTOModule::isBitcodeForTarget(memBuffer: buffer.get(),
236 triplePrefix: StringRef(target_triplet_prefix));
237}
238
239lto_module_t lto_module_create(const char* path) {
240 lto_initialize();
241 llvm::TargetOptions Options =
242 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
243 ErrorOr<std::unique_ptr<LTOModule>> M =
244 LTOModule::createFromFile(Context&: *LTOContext, path: StringRef(path), options: Options);
245 if (!M)
246 return nullptr;
247 return wrap(P: M->release());
248}
249
250lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) {
251 lto_initialize();
252 llvm::TargetOptions Options =
253 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
254 ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromOpenFile(
255 Context&: *LTOContext, fd, path: StringRef(path), size, options: Options);
256 if (!M)
257 return nullptr;
258 return wrap(P: M->release());
259}
260
261lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path,
262 size_t file_size,
263 size_t map_size,
264 off_t offset) {
265 lto_initialize();
266 llvm::TargetOptions Options =
267 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
268 ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromOpenFileSlice(
269 Context&: *LTOContext, fd, path: StringRef(path), map_size, offset, options: Options);
270 if (!M)
271 return nullptr;
272 return wrap(P: M->release());
273}
274
275lto_module_t lto_module_create_from_memory(const void* mem, size_t length) {
276 lto_initialize();
277 llvm::TargetOptions Options =
278 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
279 ErrorOr<std::unique_ptr<LTOModule>> M =
280 LTOModule::createFromBuffer(Context&: *LTOContext, mem, length, options: Options);
281 if (!M)
282 return nullptr;
283 return wrap(P: M->release());
284}
285
286lto_module_t lto_module_create_from_memory_with_path(const void* mem,
287 size_t length,
288 const char *path) {
289 lto_initialize();
290 llvm::TargetOptions Options =
291 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
292 ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromBuffer(
293 Context&: *LTOContext, mem, length, options: Options, path: StringRef(path));
294 if (!M)
295 return nullptr;
296 return wrap(P: M->release());
297}
298
299lto_module_t lto_module_create_in_local_context(const void *mem, size_t length,
300 const char *path) {
301 lto_initialize();
302 llvm::TargetOptions Options =
303 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
304
305 // Create a local context. Ownership will be transferred to LTOModule.
306 std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
307 Context->setDiagnosticHandler(DH: std::make_unique<LTOToolDiagnosticHandler>(),
308 RespectFilters: true);
309
310 ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createInLocalContext(
311 Context: std::move(Context), mem, length, options: Options, path: StringRef(path));
312 if (!M)
313 return nullptr;
314 return wrap(P: M->release());
315}
316
317lto_module_t lto_module_create_in_codegen_context(const void *mem,
318 size_t length,
319 const char *path,
320 lto_code_gen_t cg) {
321 lto_initialize();
322 llvm::TargetOptions Options =
323 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
324 ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromBuffer(
325 Context&: unwrap(P: cg)->getContext(), mem, length, options: Options, path: StringRef(path));
326 if (!M)
327 return nullptr;
328 return wrap(P: M->release());
329}
330
331void lto_module_dispose(lto_module_t mod) { delete unwrap(P: mod); }
332
333const char* lto_module_get_target_triple(lto_module_t mod) {
334 return unwrap(P: mod)->getTargetTriple().str().c_str();
335}
336
337void lto_module_set_target_triple(lto_module_t mod, const char *triple) {
338 return unwrap(P: mod)->setTargetTriple(Triple(StringRef(triple)));
339}
340
341unsigned int lto_module_get_num_symbols(lto_module_t mod) {
342 return unwrap(P: mod)->getSymbolCount();
343}
344
345const char* lto_module_get_symbol_name(lto_module_t mod, unsigned int index) {
346 return unwrap(P: mod)->getSymbolName(index).data();
347}
348
349lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod,
350 unsigned int index) {
351 return unwrap(P: mod)->getSymbolAttributes(index);
352}
353
354unsigned int lto_module_get_num_asm_undef_symbols(lto_module_t mod) {
355 return unwrap(P: mod)->getAsmUndefSymbolCount();
356}
357
358const char *lto_module_get_asm_undef_symbol_name(lto_module_t mod,
359 unsigned int index) {
360 return unwrap(P: mod)->getAsmUndefSymbolName(index).data();
361}
362
363const char* lto_module_get_linkeropts(lto_module_t mod) {
364 return unwrap(P: mod)->getLinkerOpts().data();
365}
366
367lto_bool_t lto_module_get_macho_cputype(lto_module_t mod,
368 unsigned int *out_cputype,
369 unsigned int *out_cpusubtype) {
370 LTOModule *M = unwrap(P: mod);
371 Expected<uint32_t> CPUType = M->getMachOCPUType();
372 if (!CPUType) {
373 sLastErrorString = toString(E: CPUType.takeError());
374 return true;
375 }
376 *out_cputype = *CPUType;
377
378 Expected<uint32_t> CPUSubType = M->getMachOCPUSubType();
379 if (!CPUSubType) {
380 sLastErrorString = toString(E: CPUSubType.takeError());
381 return true;
382 }
383 *out_cpusubtype = *CPUSubType;
384
385 return false;
386}
387
388void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg,
389 lto_diagnostic_handler_t diag_handler,
390 void *ctxt) {
391 unwrap(P: cg)->setDiagnosticHandler(diag_handler, ctxt);
392}
393
394static lto_code_gen_t createCodeGen(bool InLocalContext) {
395 lto_initialize();
396
397 TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
398
399 LibLTOCodeGenerator *CodeGen =
400 InLocalContext ? new LibLTOCodeGenerator(std::make_unique<LLVMContext>())
401 : new LibLTOCodeGenerator();
402 CodeGen->setTargetOptions(Options);
403 return wrap(P: CodeGen);
404}
405
406lto_code_gen_t lto_codegen_create(void) {
407 return createCodeGen(/* InLocalContext */ false);
408}
409
410lto_code_gen_t lto_codegen_create_in_local_context(void) {
411 return createCodeGen(/* InLocalContext */ true);
412}
413
414void lto_codegen_dispose(lto_code_gen_t cg) { delete unwrap(P: cg); }
415
416bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) {
417 return !unwrap(P: cg)->addModule(unwrap(P: mod));
418}
419
420void lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod) {
421 unwrap(P: cg)->setModule(std::unique_ptr<LTOModule>(unwrap(P: mod)));
422}
423
424bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) {
425 unwrap(P: cg)->setDebugInfo(debug);
426 return false;
427}
428
429bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) {
430 switch (model) {
431 case LTO_CODEGEN_PIC_MODEL_STATIC:
432 unwrap(P: cg)->setCodePICModel(Reloc::Static);
433 return false;
434 case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
435 unwrap(P: cg)->setCodePICModel(Reloc::PIC_);
436 return false;
437 case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
438 unwrap(P: cg)->setCodePICModel(Reloc::DynamicNoPIC);
439 return false;
440 case LTO_CODEGEN_PIC_MODEL_DEFAULT:
441 unwrap(P: cg)->setCodePICModel(std::nullopt);
442 return false;
443 }
444 sLastErrorString = "Unknown PIC model";
445 return true;
446}
447
448void lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu) {
449 return unwrap(P: cg)->setCpu(cpu);
450}
451
452void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char *path) {
453 // In here only for backwards compatibility. We use MC now.
454}
455
456void lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args,
457 int nargs) {
458 // In here only for backwards compatibility. We use MC now.
459}
460
461void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg,
462 const char *symbol) {
463 unwrap(P: cg)->addMustPreserveSymbol(Sym: symbol);
464}
465
466static void maybeParseOptions(lto_code_gen_t cg) {
467 if (optionParsingState != OptParsingState::Done) {
468 // Parse options if any were set by the lto_codegen_debug_options* function.
469 LibLTOCodeGenerator *CG = unwrap(P: cg);
470 CG->parseCodeGenDebugOptions();
471 // Later code generators in a local context copy the options from
472 // LTOContext.
473 if (CG->OwnedContext)
474 LTOContext->getLibraryOptions().assign(
475 Other: CG->getContext().getLibraryOptions());
476 lto_add_attrs(cg);
477 optionParsingState = OptParsingState::Done;
478 }
479}
480
481bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
482 maybeParseOptions(cg);
483 return !unwrap(P: cg)->writeMergedModules(Path: path);
484}
485
486const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) {
487 maybeParseOptions(cg);
488 LibLTOCodeGenerator *CG = unwrap(P: cg);
489 CG->NativeObjectFile = CG->compile();
490 if (!CG->NativeObjectFile)
491 return nullptr;
492 *length = CG->NativeObjectFile->getBufferSize();
493 return CG->NativeObjectFile->getBufferStart();
494}
495
496bool lto_codegen_optimize(lto_code_gen_t cg) {
497 maybeParseOptions(cg);
498 return !unwrap(P: cg)->optimize();
499}
500
501const void *lto_codegen_compile_optimized(lto_code_gen_t cg, size_t *length) {
502 maybeParseOptions(cg);
503 LibLTOCodeGenerator *CG = unwrap(P: cg);
504 CG->NativeObjectFile = CG->compileOptimized();
505 if (!CG->NativeObjectFile)
506 return nullptr;
507 *length = CG->NativeObjectFile->getBufferSize();
508 return CG->NativeObjectFile->getBufferStart();
509}
510
511bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
512 maybeParseOptions(cg);
513 return !unwrap(P: cg)->compile_to_file(Name: name);
514}
515
516static void parseDebugOptions(ArrayRef<const char *> Options) {
517 lto_initialize();
518 std::vector<const char *> CodegenArgv(1, "libLTO");
519 append_range(C&: CodegenArgv, R&: Options);
520 cl::parseCommandLineOptions(Context&: LTOContext->getLibraryOptions(), Args: CodegenArgv);
521}
522
523void lto_set_debug_options(const char *const *options, int number) {
524 assert(optionParsingState == OptParsingState::NotParsed &&
525 "option processing already happened");
526 parseDebugOptions(Options: ArrayRef(options, number));
527 optionParsingState = OptParsingState::Early;
528}
529
530void lto_codegen_debug_options(lto_code_gen_t cg, const char *opt) {
531 assert(optionParsingState != OptParsingState::Early &&
532 "early option processing already happened");
533 SmallVector<StringRef, 4> Options;
534 for (std::pair<StringRef, StringRef> o = getToken(Source: opt); !o.first.empty();
535 o = getToken(Source: o.second))
536 Options.push_back(Elt: o.first);
537
538 unwrap(P: cg)->setCodeGenDebugOptions(Options);
539}
540
541void lto_codegen_debug_options_array(lto_code_gen_t cg,
542 const char *const *options, int number) {
543 assert(optionParsingState != OptParsingState::Early &&
544 "early option processing already happened");
545 SmallVector<StringRef, 4> Options(ArrayRef(options, number));
546 unwrap(P: cg)->setCodeGenDebugOptions(ArrayRef(Options));
547}
548
549unsigned int lto_api_version() { return LTO_API_VERSION; }
550
551void lto_codegen_set_should_internalize(lto_code_gen_t cg,
552 bool ShouldInternalize) {
553 unwrap(P: cg)->setShouldInternalize(ShouldInternalize);
554}
555
556void lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
557 lto_bool_t ShouldEmbedUselists) {
558 unwrap(P: cg)->setShouldEmbedUselists(ShouldEmbedUselists);
559}
560
561lto_bool_t lto_module_has_ctor_dtor(lto_module_t mod) {
562 return unwrap(P: mod)->hasCtorDtor();
563}
564
565// ThinLTO API below
566
567thinlto_code_gen_t thinlto_create_codegen(void) {
568 lto_initialize();
569 ThinLTOCodeGenerator *CodeGen =
570 new ThinLTOCodeGenerator(LTOContext->getLibraryOptions());
571 CodeGen->setMllvmArgs(ThinLTOMllvmArgs);
572 CodeGen->setTargetOptions(
573 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple()));
574 CodeGen->setFreestanding(EnableFreestanding);
575
576 if (OptLevel.getNumOccurrences()) {
577 if (OptLevel < '0' || OptLevel > '3')
578 report_fatal_error(reason: "Optimization level must be between 0 and 3");
579 CodeGen->setOptLevel(OptLevel - '0');
580 std::optional<CodeGenOptLevel> CGOptLevelOrNone =
581 CodeGenOpt::getLevel(OL: OptLevel - '0');
582 assert(CGOptLevelOrNone);
583 CodeGen->setCodeGenOptLevel(*CGOptLevelOrNone);
584 }
585 if (!ThinLTOCacheDir.empty()) {
586 auto Err = llvm::sys::fs::create_directories(path: ThinLTOCacheDir);
587 if (Err)
588 report_fatal_error(reason: Twine("Unable to create thinLTO cache directory: ") +
589 Err.message());
590 bool result;
591 Err = llvm::sys::fs::is_directory(path: ThinLTOCacheDir, result);
592 if (Err || !result)
593 report_fatal_error(reason: Twine("Unable to get status of thinLTO cache path or "
594 "path is not a directory: ") +
595 Err.message());
596 CodeGen->setCacheDir(ThinLTOCacheDir);
597
598 CodeGen->setCachePruningInterval(ThinLTOCachePruningInterval);
599 CodeGen->setCacheEntryExpiration(ThinLTOCacheEntryExpiration);
600 CodeGen->setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);
601 CodeGen->setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);
602 }
603
604 return wrap(P: CodeGen);
605}
606
607void thinlto_codegen_dispose(thinlto_code_gen_t cg) { delete unwrap(P: cg); }
608
609void thinlto_codegen_add_module(thinlto_code_gen_t cg, const char *Identifier,
610 const char *Data, int Length) {
611 unwrap(P: cg)->addModule(Identifier, Data: StringRef(Data, Length));
612}
613
614void thinlto_codegen_process(thinlto_code_gen_t cg) { unwrap(P: cg)->run(); }
615
616unsigned int thinlto_module_get_num_objects(thinlto_code_gen_t cg) {
617 return unwrap(P: cg)->getProducedBinaries().size();
618}
619LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg,
620 unsigned int index) {
621 assert(index < unwrap(cg)->getProducedBinaries().size() && "Index overflow");
622 auto &MemBuffer = unwrap(P: cg)->getProducedBinaries()[index];
623 return LTOObjectBuffer{.Buffer: MemBuffer->getBufferStart(),
624 .Size: MemBuffer->getBufferSize()};
625}
626
627unsigned int thinlto_module_get_num_object_files(thinlto_code_gen_t cg) {
628 return unwrap(P: cg)->getProducedBinaryFiles().size();
629}
630const char *thinlto_module_get_object_file(thinlto_code_gen_t cg,
631 unsigned int index) {
632 assert(index < unwrap(cg)->getProducedBinaryFiles().size() &&
633 "Index overflow");
634 return unwrap(P: cg)->getProducedBinaryFiles()[index].c_str();
635}
636
637void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg,
638 lto_bool_t disable) {
639 unwrap(P: cg)->disableCodeGen(Disable: disable);
640}
641
642void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg,
643 lto_bool_t CodeGenOnly) {
644 unwrap(P: cg)->setCodeGenOnly(CodeGenOnly);
645}
646
647void thinlto_debug_options(const char *const *options, int number) {
648 // If options were requested, parse and retain them.
649 if (number && options) {
650 parseDebugOptions(Options: ArrayRef(options, number));
651 ThinLTOMllvmArgs.assign(first: options, last: options + number);
652 }
653}
654
655lto_bool_t lto_module_is_thinlto(lto_module_t mod) {
656 return unwrap(P: mod)->isThinLTO();
657}
658
659void thinlto_codegen_add_must_preserve_symbol(thinlto_code_gen_t cg,
660 const char *Name, int Length) {
661 unwrap(P: cg)->preserveSymbol(Name: StringRef(Name, Length));
662}
663
664void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg,
665 const char *Name, int Length) {
666 unwrap(P: cg)->crossReferenceSymbol(Name: StringRef(Name, Length));
667}
668
669void thinlto_codegen_set_cpu(thinlto_code_gen_t cg, const char *cpu) {
670 return unwrap(P: cg)->setCpu(cpu);
671}
672
673void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg,
674 const char *cache_dir) {
675 return unwrap(P: cg)->setCacheDir(cache_dir);
676}
677
678void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg,
679 int interval) {
680 return unwrap(P: cg)->setCachePruningInterval(interval);
681}
682
683void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
684 unsigned expiration) {
685 return unwrap(P: cg)->setCacheEntryExpiration(expiration);
686}
687
688void thinlto_codegen_set_final_cache_size_relative_to_available_space(
689 thinlto_code_gen_t cg, unsigned Percentage) {
690 return unwrap(P: cg)->setMaxCacheSizeRelativeToAvailableSpace(Percentage);
691}
692
693void thinlto_codegen_set_cache_size_bytes(
694 thinlto_code_gen_t cg, unsigned MaxSizeBytes) {
695 return unwrap(P: cg)->setCacheMaxSizeBytes(MaxSizeBytes);
696}
697
698void thinlto_codegen_set_cache_size_megabytes(
699 thinlto_code_gen_t cg, unsigned MaxSizeMegabytes) {
700 uint64_t MaxSizeBytes = MaxSizeMegabytes;
701 MaxSizeBytes *= 1024 * 1024;
702 return unwrap(P: cg)->setCacheMaxSizeBytes(MaxSizeBytes);
703}
704
705void thinlto_codegen_set_cache_size_files(
706 thinlto_code_gen_t cg, unsigned MaxSizeFiles) {
707 return unwrap(P: cg)->setCacheMaxSizeFiles(MaxSizeFiles);
708}
709
710void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg,
711 const char *save_temps_dir) {
712 return unwrap(P: cg)->setSaveTempsDir(save_temps_dir);
713}
714
715void thinlto_set_generated_objects_dir(thinlto_code_gen_t cg,
716 const char *save_temps_dir) {
717 unwrap(P: cg)->setGeneratedObjectsDirectory(save_temps_dir);
718}
719
720lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg,
721 lto_codegen_model model) {
722 switch (model) {
723 case LTO_CODEGEN_PIC_MODEL_STATIC:
724 unwrap(P: cg)->setCodePICModel(Reloc::Static);
725 return false;
726 case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
727 unwrap(P: cg)->setCodePICModel(Reloc::PIC_);
728 return false;
729 case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
730 unwrap(P: cg)->setCodePICModel(Reloc::DynamicNoPIC);
731 return false;
732 case LTO_CODEGEN_PIC_MODEL_DEFAULT:
733 unwrap(P: cg)->setCodePICModel(std::nullopt);
734 return false;
735 }
736 sLastErrorString = "Unknown PIC model";
737 return true;
738}
739
740DEFINE_SIMPLE_CONVERSION_FUNCTIONS(lto::InputFile, lto_input_t)
741
742lto_input_t lto_input_create(const void *buffer, size_t buffer_size, const char *path) {
743 return wrap(P: LTOModule::createInputFile(buffer, buffer_size, path, out_error&: sLastErrorString));
744}
745
746void lto_input_dispose(lto_input_t input) {
747 delete unwrap(P: input);
748}
749
750extern unsigned lto_input_get_num_dependent_libraries(lto_input_t input) {
751 return LTOModule::getDependentLibraryCount(input: unwrap(P: input));
752}
753
754extern const char *lto_input_get_dependent_library(lto_input_t input,
755 size_t index,
756 size_t *size) {
757 return LTOModule::getDependentLibrary(input: unwrap(P: input), index, size);
758}
759
760extern const char *const *lto_runtime_lib_symbols_list(size_t *size) {
761 *size = RuntimeLibcallSymbols.size();
762 return RuntimeLibcallSymbols.data();
763}
764
765extern const char *const *
766lto_runtime_lib_symbols_list_for_triple(const char *TS, size_t *size) {
767 static StringMap<SmallVector<const char *>> RTLibcallSymMap;
768 Triple TT(TS);
769 auto [It, Inserted] = RTLibcallSymMap.try_emplace(Key: TT.normalize());
770 if (Inserted)
771 It->second = lto::LTO::getRuntimeLibcallSymbols(TT);
772 *size = It->second.size();
773 return It->second.data();
774}
775