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