xref: /llvm-project-15.0.7/llvm/tools/lto/lto.cpp (revision fcef3e46)
1 //===-lto.cpp - LLVM Link Time Optimizer ----------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Link Time Optimization library. This library is
11 // intended to be used by linker to optimize code at link time.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm-c/lto.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/CodeGen/CommandFlags.h"
18 #include "llvm/IR/DiagnosticInfo.h"
19 #include "llvm/IR/DiagnosticPrinter.h"
20 #include "llvm/IR/LLVMContext.h"
21 #include "llvm/LTO/LTOCodeGenerator.h"
22 #include "llvm/LTO/LTOModule.h"
23 #include "llvm/LTO/ThinLTOCodeGenerator.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/Signals.h"
26 #include "llvm/Support/TargetSelect.h"
27 #include "llvm/Support/raw_ostream.h"
28 
29 // extra command-line flags needed for LTOCodeGenerator
30 static cl::opt<char>
31 OptLevel("O",
32          cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
33                   "(default = '-O2')"),
34          cl::Prefix,
35          cl::ZeroOrMore,
36          cl::init('2'));
37 
38 static cl::opt<bool>
39 DisableInline("disable-inlining", cl::init(false),
40   cl::desc("Do not run the inliner pass"));
41 
42 static cl::opt<bool>
43 DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
44   cl::desc("Do not run the GVN load PRE pass"));
45 
46 static cl::opt<bool>
47 DisableLTOVectorization("disable-lto-vectorization", cl::init(false),
48   cl::desc("Do not run loop or slp vectorization during LTO"));
49 
50 #ifdef NDEBUG
51 static bool VerifyByDefault = false;
52 #else
53 static bool VerifyByDefault = true;
54 #endif
55 
56 static cl::opt<bool> DisableVerify(
57     "disable-llvm-verifier", cl::init(!VerifyByDefault),
58     cl::desc("Don't run the LLVM verifier during the optimization pipeline"));
59 
60 // Holds most recent error string.
61 // *** Not thread safe ***
62 static std::string sLastErrorString;
63 
64 // Holds the initialization state of the LTO module.
65 // *** Not thread safe ***
66 static bool initialized = false;
67 
68 // Holds the command-line option parsing state of the LTO module.
69 static bool parsedOptions = false;
70 
71 static LLVMContext *LTOContext = nullptr;
72 
73 static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
74   if (DI.getSeverity() != DS_Error) {
75     DiagnosticPrinterRawOStream DP(errs());
76     DI.print(DP);
77     errs() << '\n';
78     return;
79   }
80   sLastErrorString = "";
81   {
82     raw_string_ostream Stream(sLastErrorString);
83     DiagnosticPrinterRawOStream DP(Stream);
84     DI.print(DP);
85   }
86 }
87 
88 // Initialize the configured targets if they have not been initialized.
89 static void lto_initialize() {
90   if (!initialized) {
91 #ifdef LLVM_ON_WIN32
92     // Dialog box on crash disabling doesn't work across DLL boundaries, so do
93     // it here.
94     llvm::sys::DisableSystemDialogsOnCrash();
95 #endif
96 
97     InitializeAllTargetInfos();
98     InitializeAllTargets();
99     InitializeAllTargetMCs();
100     InitializeAllAsmParsers();
101     InitializeAllAsmPrinters();
102     InitializeAllDisassemblers();
103 
104     LTOContext = &getGlobalContext();
105     LTOContext->setDiagnosticHandler(diagnosticHandler, nullptr, true);
106     initialized = true;
107   }
108 }
109 
110 namespace {
111 
112 static void handleLibLTODiagnostic(lto_codegen_diagnostic_severity_t Severity,
113                                    const char *Msg, void *) {
114   sLastErrorString = Msg;
115 }
116 
117 // This derived class owns the native object file. This helps implement the
118 // libLTO API semantics, which require that the code generator owns the object
119 // file.
120 struct LibLTOCodeGenerator : LTOCodeGenerator {
121   LibLTOCodeGenerator() : LTOCodeGenerator(*LTOContext) {
122     setDiagnosticHandler(handleLibLTODiagnostic, nullptr); }
123   LibLTOCodeGenerator(std::unique_ptr<LLVMContext> Context)
124       : LTOCodeGenerator(*Context), OwnedContext(std::move(Context)) {
125     setDiagnosticHandler(handleLibLTODiagnostic, nullptr); }
126 
127   // Reset the module first in case MergedModule is created in OwnedContext.
128   // Module must be destructed before its context gets destructed.
129   ~LibLTOCodeGenerator() { resetMergedModule(); }
130 
131   std::unique_ptr<MemoryBuffer> NativeObjectFile;
132   std::unique_ptr<LLVMContext> OwnedContext;
133 };
134 
135 }
136 
137 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LibLTOCodeGenerator, lto_code_gen_t)
138 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThinLTOCodeGenerator, thinlto_code_gen_t)
139 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LTOModule, lto_module_t)
140 
141 // Convert the subtarget features into a string to pass to LTOCodeGenerator.
142 static void lto_add_attrs(lto_code_gen_t cg) {
143   LTOCodeGenerator *CG = unwrap(cg);
144   if (MAttrs.size()) {
145     std::string attrs;
146     for (unsigned i = 0; i < MAttrs.size(); ++i) {
147       if (i > 0)
148         attrs.append(",");
149       attrs.append(MAttrs[i]);
150     }
151 
152     CG->setAttr(attrs.c_str());
153   }
154 
155   if (OptLevel < '0' || OptLevel > '3')
156     report_fatal_error("Optimization level must be between 0 and 3");
157   CG->setOptLevel(OptLevel - '0');
158 }
159 
160 extern const char* lto_get_version() {
161   return LTOCodeGenerator::getVersionString();
162 }
163 
164 const char* lto_get_error_message() {
165   return sLastErrorString.c_str();
166 }
167 
168 bool lto_module_is_object_file(const char* path) {
169   return LTOModule::isBitcodeFile(path);
170 }
171 
172 bool lto_module_is_object_file_for_target(const char* path,
173                                           const char* target_triplet_prefix) {
174   ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFile(path);
175   if (!Buffer)
176     return false;
177   return LTOModule::isBitcodeForTarget(Buffer->get(), target_triplet_prefix);
178 }
179 
180 bool lto_module_is_object_file_in_memory(const void* mem, size_t length) {
181   return LTOModule::isBitcodeFile(mem, length);
182 }
183 
184 bool
185 lto_module_is_object_file_in_memory_for_target(const void* mem,
186                                             size_t length,
187                                             const char* target_triplet_prefix) {
188   std::unique_ptr<MemoryBuffer> buffer(LTOModule::makeBuffer(mem, length));
189   if (!buffer)
190     return false;
191   return LTOModule::isBitcodeForTarget(buffer.get(), target_triplet_prefix);
192 }
193 
194 lto_module_t lto_module_create(const char* path) {
195   lto_initialize();
196   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
197   ErrorOr<std::unique_ptr<LTOModule>> M =
198       LTOModule::createFromFile(*LTOContext, path, Options);
199   if (!M)
200     return nullptr;
201   return wrap(M->release());
202 }
203 
204 lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) {
205   lto_initialize();
206   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
207   ErrorOr<std::unique_ptr<LTOModule>> M =
208       LTOModule::createFromOpenFile(*LTOContext, fd, path, size, Options);
209   if (!M)
210     return nullptr;
211   return wrap(M->release());
212 }
213 
214 lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path,
215                                                  size_t file_size,
216                                                  size_t map_size,
217                                                  off_t offset) {
218   lto_initialize();
219   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
220   ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromOpenFileSlice(
221       *LTOContext, fd, path, map_size, offset, Options);
222   if (!M)
223     return nullptr;
224   return wrap(M->release());
225 }
226 
227 lto_module_t lto_module_create_from_memory(const void* mem, size_t length) {
228   lto_initialize();
229   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
230   ErrorOr<std::unique_ptr<LTOModule>> M =
231       LTOModule::createFromBuffer(*LTOContext, mem, length, Options);
232   if (!M)
233     return nullptr;
234   return wrap(M->release());
235 }
236 
237 lto_module_t lto_module_create_from_memory_with_path(const void* mem,
238                                                      size_t length,
239                                                      const char *path) {
240   lto_initialize();
241   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
242   ErrorOr<std::unique_ptr<LTOModule>> M =
243       LTOModule::createFromBuffer(*LTOContext, mem, length, Options, path);
244   if (!M)
245     return nullptr;
246   return wrap(M->release());
247 }
248 
249 lto_module_t lto_module_create_in_local_context(const void *mem, size_t length,
250                                                 const char *path) {
251   lto_initialize();
252   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
253 
254   // Create a local context. Ownership will be transfered to LTOModule.
255   std::unique_ptr<LLVMContext> Context = llvm::make_unique<LLVMContext>();
256   Context->setDiagnosticHandler(diagnosticHandler, nullptr, true);
257 
258   ErrorOr<std::unique_ptr<LTOModule>> M =
259       LTOModule::createInLocalContext(std::move(Context), mem, length, Options,
260                                       path);
261   if (!M)
262     return nullptr;
263   return wrap(M->release());
264 }
265 
266 lto_module_t lto_module_create_in_codegen_context(const void *mem,
267                                                   size_t length,
268                                                   const char *path,
269                                                   lto_code_gen_t cg) {
270   lto_initialize();
271   llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
272   ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromBuffer(
273       unwrap(cg)->getContext(), mem, length, Options, path);
274   return wrap(M->release());
275 }
276 
277 void lto_module_dispose(lto_module_t mod) { delete unwrap(mod); }
278 
279 const char* lto_module_get_target_triple(lto_module_t mod) {
280   return unwrap(mod)->getTargetTriple().c_str();
281 }
282 
283 void lto_module_set_target_triple(lto_module_t mod, const char *triple) {
284   return unwrap(mod)->setTargetTriple(triple);
285 }
286 
287 unsigned int lto_module_get_num_symbols(lto_module_t mod) {
288   return unwrap(mod)->getSymbolCount();
289 }
290 
291 const char* lto_module_get_symbol_name(lto_module_t mod, unsigned int index) {
292   return unwrap(mod)->getSymbolName(index);
293 }
294 
295 lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod,
296                                                       unsigned int index) {
297   return unwrap(mod)->getSymbolAttributes(index);
298 }
299 
300 const char* lto_module_get_linkeropts(lto_module_t mod) {
301   return unwrap(mod)->getLinkerOpts();
302 }
303 
304 void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg,
305                                         lto_diagnostic_handler_t diag_handler,
306                                         void *ctxt) {
307   unwrap(cg)->setDiagnosticHandler(diag_handler, ctxt);
308 }
309 
310 static lto_code_gen_t createCodeGen(bool InLocalContext) {
311   lto_initialize();
312 
313   TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
314 
315   LibLTOCodeGenerator *CodeGen =
316       InLocalContext ? new LibLTOCodeGenerator(make_unique<LLVMContext>())
317                      : new LibLTOCodeGenerator();
318   CodeGen->setTargetOptions(Options);
319   return wrap(CodeGen);
320 }
321 
322 lto_code_gen_t lto_codegen_create(void) {
323   return createCodeGen(/* InLocalContext */ false);
324 }
325 
326 lto_code_gen_t lto_codegen_create_in_local_context(void) {
327   return createCodeGen(/* InLocalContext */ true);
328 }
329 
330 void lto_codegen_dispose(lto_code_gen_t cg) { delete unwrap(cg); }
331 
332 bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) {
333   return !unwrap(cg)->addModule(unwrap(mod));
334 }
335 
336 void lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod) {
337   unwrap(cg)->setModule(std::unique_ptr<LTOModule>(unwrap(mod)));
338 }
339 
340 bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) {
341   unwrap(cg)->setDebugInfo(debug);
342   return false;
343 }
344 
345 bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) {
346   switch (model) {
347   case LTO_CODEGEN_PIC_MODEL_STATIC:
348     unwrap(cg)->setCodePICModel(Reloc::Static);
349     return false;
350   case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
351     unwrap(cg)->setCodePICModel(Reloc::PIC_);
352     return false;
353   case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
354     unwrap(cg)->setCodePICModel(Reloc::DynamicNoPIC);
355     return false;
356   case LTO_CODEGEN_PIC_MODEL_DEFAULT:
357     unwrap(cg)->setCodePICModel(Reloc::Default);
358     return false;
359   }
360   sLastErrorString = "Unknown PIC model";
361   return true;
362 }
363 
364 void lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu) {
365   return unwrap(cg)->setCpu(cpu);
366 }
367 
368 void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char *path) {
369   // In here only for backwards compatibility. We use MC now.
370 }
371 
372 void lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args,
373                                     int nargs) {
374   // In here only for backwards compatibility. We use MC now.
375 }
376 
377 void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg,
378                                           const char *symbol) {
379   unwrap(cg)->addMustPreserveSymbol(symbol);
380 }
381 
382 static void maybeParseOptions(lto_code_gen_t cg) {
383   if (!parsedOptions) {
384     unwrap(cg)->parseCodeGenDebugOptions();
385     lto_add_attrs(cg);
386     parsedOptions = true;
387   }
388 }
389 
390 bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
391   maybeParseOptions(cg);
392   return !unwrap(cg)->writeMergedModules(path);
393 }
394 
395 const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) {
396   maybeParseOptions(cg);
397   LibLTOCodeGenerator *CG = unwrap(cg);
398   CG->NativeObjectFile =
399       CG->compile(DisableVerify, DisableInline, DisableGVNLoadPRE,
400                   DisableLTOVectorization);
401   if (!CG->NativeObjectFile)
402     return nullptr;
403   *length = CG->NativeObjectFile->getBufferSize();
404   return CG->NativeObjectFile->getBufferStart();
405 }
406 
407 bool lto_codegen_optimize(lto_code_gen_t cg) {
408   maybeParseOptions(cg);
409   return !unwrap(cg)->optimize(DisableVerify, DisableInline, DisableGVNLoadPRE,
410                                DisableLTOVectorization);
411 }
412 
413 const void *lto_codegen_compile_optimized(lto_code_gen_t cg, size_t *length) {
414   maybeParseOptions(cg);
415   LibLTOCodeGenerator *CG = unwrap(cg);
416   CG->NativeObjectFile = CG->compileOptimized();
417   if (!CG->NativeObjectFile)
418     return nullptr;
419   *length = CG->NativeObjectFile->getBufferSize();
420   return CG->NativeObjectFile->getBufferStart();
421 }
422 
423 bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
424   maybeParseOptions(cg);
425   return !unwrap(cg)->compile_to_file(
426       name, DisableVerify, DisableInline, DisableGVNLoadPRE,
427       DisableLTOVectorization);
428 }
429 
430 void lto_codegen_debug_options(lto_code_gen_t cg, const char *opt) {
431   unwrap(cg)->setCodeGenDebugOptions(opt);
432 }
433 
434 unsigned int lto_api_version() { return LTO_API_VERSION; }
435 
436 void lto_codegen_set_should_internalize(lto_code_gen_t cg,
437                                         bool ShouldInternalize) {
438   unwrap(cg)->setShouldInternalize(ShouldInternalize);
439 }
440 
441 void lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
442                                            lto_bool_t ShouldEmbedUselists) {
443   unwrap(cg)->setShouldEmbedUselists(ShouldEmbedUselists);
444 }
445 
446 // ThinLTO API below
447 
448 thinlto_code_gen_t thinlto_create_codegen(void) {
449   lto_initialize();
450   ThinLTOCodeGenerator *CodeGen = new ThinLTOCodeGenerator();
451   CodeGen->setTargetOptions(InitTargetOptionsFromCodeGenFlags());
452 
453   return wrap(CodeGen);
454 }
455 
456 void thinlto_codegen_dispose(thinlto_code_gen_t cg) { delete unwrap(cg); }
457 
458 void thinlto_codegen_add_module(thinlto_code_gen_t cg, const char *Identifier,
459                                 const char *Data, int Length) {
460   unwrap(cg)->addModule(Identifier, StringRef(Data, Length));
461 }
462 
463 void thinlto_codegen_process(thinlto_code_gen_t cg) { unwrap(cg)->run(); }
464 
465 unsigned int thinlto_module_get_num_objects(thinlto_code_gen_t cg) {
466   return unwrap(cg)->getProducedBinaries().size();
467 }
468 LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg,
469                                           unsigned int index) {
470   assert(index < unwrap(cg)->getProducedBinaries().size() && "Index overflow");
471   auto &MemBuffer = unwrap(cg)->getProducedBinaries()[index];
472   return LTOObjectBuffer{MemBuffer->getBufferStart(),
473                          MemBuffer->getBufferSize()};
474 }
475 
476 void thinlto_debug_options(const char *const *options, int number) {
477   // if options were requested, set them
478   if (number && options) {
479     std::vector<const char *> CodegenArgv(1, "libLTO");
480     for (auto Arg : ArrayRef<const char *>(options, number))
481       CodegenArgv.push_back(Arg);
482     cl::ParseCommandLineOptions(CodegenArgv.size(), CodegenArgv.data());
483   }
484 }
485 
486 bool lto_module_is_thinlto(lto_module_t mod) {
487   return unwrap(mod)->isThinLTO();
488 }
489 
490 void thinlto_codegen_add_must_preserve_symbol(thinlto_code_gen_t cg,
491                                               const char *Name, int Length) {
492   unwrap(cg)->preserveSymbol(StringRef(Name, Length));
493 }
494 
495 void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg,
496                                                  const char *Name, int Length) {
497   unwrap(cg)->crossReferenceSymbol(StringRef(Name, Length));
498 }
499 
500 void thinlto_codegen_set_cpu(thinlto_code_gen_t cg, const char *cpu) {
501   return unwrap(cg)->setCpu(cpu);
502 }
503 
504 void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg,
505                                    const char *cache_dir) {
506   return unwrap(cg)->setCacheDir(cache_dir);
507 }
508 
509 void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg,
510                                                 int interval) {
511   return unwrap(cg)->setCachePruningInterval(interval);
512 }
513 
514 void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
515                                                 unsigned expiration) {
516   return unwrap(cg)->setCacheEntryExpiration(expiration);
517 }
518 
519 void thinlto_codegen_set_final_cache_size_relative_to_available_space(
520     thinlto_code_gen_t cg, unsigned Percentage) {
521   return unwrap(cg)->setMaxCacheSizeRelativeToAvailableSpace(Percentage);
522 }
523 
524 void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg,
525                                        const char *save_temps_dir) {
526   return unwrap(cg)->setSaveTempsDir(save_temps_dir);
527 }
528 
529 lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg,
530                                          lto_codegen_model model) {
531   switch (model) {
532   case LTO_CODEGEN_PIC_MODEL_STATIC:
533     unwrap(cg)->setCodePICModel(Reloc::Static);
534     return false;
535   case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
536     unwrap(cg)->setCodePICModel(Reloc::PIC_);
537     return false;
538   case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
539     unwrap(cg)->setCodePICModel(Reloc::DynamicNoPIC);
540     return false;
541   case LTO_CODEGEN_PIC_MODEL_DEFAULT:
542     unwrap(cg)->setCodePICModel(Reloc::Default);
543     return false;
544   }
545   sLastErrorString = "Unknown PIC model";
546   return true;
547 }
548