1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
12 use back::symbol_export;
13 use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
15 use errors::{FatalError, Handler};
16 use llvm::archive_ro::ArchiveRO;
17 use llvm::{ModuleRef, TargetMachineRef, True, False};
19 use rustc::hir::def_id::LOCAL_CRATE;
20 use rustc::middle::exported_symbols::SymbolExportLevel;
21 use rustc::session::config;
22 use rustc::util::common::time;
23 use time_graph::Timeline;
24 use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource};
28 use std::ffi::CString;
33 pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
35 config::CrateTypeExecutable |
36 config::CrateTypeStaticlib |
37 config::CrateTypeCdylib => true,
39 config::CrateTypeDylib |
40 config::CrateTypeRlib |
41 config::CrateTypeProcMacro => false,
45 pub(crate) enum LtoModuleTranslation {
47 module: Option<ModuleTranslation>,
48 _serialized_bitcode: Vec<SerializedModule>,
54 impl LtoModuleTranslation {
55 pub fn name(&self) -> &str {
57 LtoModuleTranslation::Fat { .. } => "everything",
58 LtoModuleTranslation::Thin(ref m) => m.name(),
62 /// Optimize this module within the given codegen context.
64 /// This function is unsafe as it'll return a `ModuleTranslation` still
65 /// points to LLVM data structures owned by this `LtoModuleTranslation`.
66 /// It's intended that the module returned is immediately code generated and
67 /// dropped, and then this LTO module is dropped.
68 pub(crate) unsafe fn optimize(&mut self,
69 cgcx: &CodegenContext,
70 timeline: &mut Timeline)
71 -> Result<ModuleTranslation, FatalError>
74 LtoModuleTranslation::Fat { ref mut module, .. } => {
75 let trans = module.take().unwrap();
76 let config = cgcx.config(trans.kind);
77 let llmod = trans.llvm().unwrap().llmod;
78 let tm = trans.llvm().unwrap().tm;
79 run_pass_manager(cgcx, tm, llmod, config, false);
80 timeline.record("fat-done");
83 LtoModuleTranslation::Thin(ref mut thin) => thin.optimize(cgcx, timeline),
87 /// A "guage" of how costly it is to optimize this module, used to sort
88 /// biggest modules first.
89 pub fn cost(&self) -> u64 {
91 // Only one module with fat LTO, so the cost doesn't matter.
92 LtoModuleTranslation::Fat { .. } => 0,
93 LtoModuleTranslation::Thin(ref m) => m.cost(),
103 pub(crate) fn run(cgcx: &CodegenContext,
104 modules: Vec<ModuleTranslation>,
106 timeline: &mut Timeline)
107 -> Result<Vec<LtoModuleTranslation>, FatalError>
109 let diag_handler = cgcx.create_diag_handler();
110 let export_threshold = match mode {
111 LTOMode::WholeCrateGraph => {
112 symbol_export::crates_export_threshold(&cgcx.crate_types)
114 LTOMode::JustThisCrate => {
115 SymbolExportLevel::Rust
119 let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
120 if level.is_below_threshold(export_threshold) {
121 let mut bytes = Vec::with_capacity(name.len() + 1);
122 bytes.extend(name.bytes());
123 Some(CString::new(bytes).unwrap())
129 let mut symbol_white_list = cgcx.exported_symbols[&LOCAL_CRATE]
131 .filter_map(symbol_filter)
132 .collect::<Vec<CString>>();
133 timeline.record("whitelist");
134 info!("{} symbols to preserve in this crate", symbol_white_list.len());
136 // If we're performing LTO for the entire crate graph, then for each of our
137 // upstream dependencies, find the corresponding rlib and load the bitcode
140 // We save off all the bytecode and LLVM module ids for later processing
141 // with either fat or thin LTO
142 let mut upstream_modules = Vec::new();
143 if let LTOMode::WholeCrateGraph = mode {
144 if cgcx.opts.cg.prefer_dynamic {
145 diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
146 .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
149 return Err(FatalError)
152 // Make sure we actually can run LTO
153 for crate_type in cgcx.crate_types.iter() {
154 if !crate_type_allows_lto(*crate_type) {
155 let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \
156 static library outputs");
161 for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
162 symbol_white_list.extend(
163 cgcx.exported_symbols[&cnum]
165 .filter_map(symbol_filter));
167 let archive = ArchiveRO::open(&path).expect("wanted an rlib");
168 let bytecodes = archive.iter().filter_map(|child| {
169 child.ok().and_then(|c| c.name().map(|name| (name, c)))
170 }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION));
171 for (name, data) in bytecodes {
172 info!("adding bytecode {}", name);
173 let bc_encoded = data.data();
175 let (bc, id) = time(cgcx.time_passes, &format!("decode {}", name), || {
176 match DecodedBytecode::new(bc_encoded) {
177 Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
178 Err(e) => Err(diag_handler.fatal(&e)),
181 let bc = SerializedModule::FromRlib(bc);
182 upstream_modules.push((bc, CString::new(id).unwrap()));
184 timeline.record(&format!("load: {}", path.display()));
188 let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
190 LTOMode::WholeCrateGraph if !cgcx.thinlto => {
191 fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
194 thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
199 fn fat_lto(cgcx: &CodegenContext,
200 diag_handler: &Handler,
201 mut modules: Vec<ModuleTranslation>,
202 mut serialized_modules: Vec<(SerializedModule, CString)>,
203 symbol_white_list: &[*const libc::c_char],
204 timeline: &mut Timeline)
205 -> Result<Vec<LtoModuleTranslation>, FatalError>
207 info!("going for a fat lto");
209 // Find the "costliest" module and merge everything into that codegen unit.
210 // All the other modules will be serialized and reparsed into the new
211 // context, so this hopefully avoids serializing and parsing the largest
214 // Additionally use a regular module as the base here to ensure that various
215 // file copy operations in the backend work correctly. The only other kind
216 // of module here should be an allocator one, and if your crate is smaller
217 // than the allocator module then the size doesn't really matter anyway.
218 let (_, costliest_module) = modules.iter()
220 .filter(|&(_, module)| module.kind == ModuleKind::Regular)
223 llvm::LLVMRustModuleCost(module.llvm().unwrap().llmod)
228 .expect("must be trans'ing at least one module");
229 let module = modules.remove(costliest_module);
230 let llmod = module.llvm().expect("can't lto pre-translated modules").llmod;
231 info!("using {:?} as a base module", module.llmod_id);
233 // For all other modules we translated we'll need to link them into our own
234 // bitcode. All modules were translated in their own LLVM context, however,
235 // and we want to move everything to the same LLVM context. Currently the
236 // way we know of to do that is to serialize them to a string and them parse
237 // them later. Not great but hey, that's why it's "fat" LTO, right?
238 for module in modules {
239 let llvm = module.llvm().expect("can't lto pre-translated modules");
240 let buffer = ModuleBuffer::new(llvm.llmod);
241 let llmod_id = CString::new(&module.llmod_id[..]).unwrap();
242 serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
245 // For all serialized bitcode files we parse them and link them in as we did
246 // above, this is all mostly handled in C++. Like above, though, we don't
247 // know much about the memory management here so we err on the side of being
248 // save and persist everything with the original module.
249 let mut serialized_bitcode = Vec::new();
250 for (bc_decoded, name) in serialized_modules {
251 info!("linking {:?}", name);
252 time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe {
253 let data = bc_decoded.data();
254 if llvm::LLVMRustLinkInExternalBitcode(llmod,
255 data.as_ptr() as *const libc::c_char,
256 data.len() as libc::size_t) {
259 let msg = format!("failed to load bc of {:?}", name);
260 Err(write::llvm_err(&diag_handler, msg))
263 timeline.record(&format!("link {:?}", name));
264 serialized_bitcode.push(bc_decoded);
266 cgcx.save_temp_bitcode(&module, "lto.input");
268 // Internalize everything that *isn't* in our whitelist to help strip out
269 // more modules and such
271 let ptr = symbol_white_list.as_ptr();
272 llvm::LLVMRustRunRestrictionPass(llmod,
273 ptr as *const *const libc::c_char,
274 symbol_white_list.len() as libc::size_t);
275 cgcx.save_temp_bitcode(&module, "lto.after-restriction");
278 if cgcx.no_landing_pads {
280 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
282 cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
284 timeline.record("passes");
286 Ok(vec![LtoModuleTranslation::Fat {
287 module: Some(module),
288 _serialized_bitcode: serialized_bitcode,
292 /// Prepare "thin" LTO to get run on these modules.
294 /// The general structure of ThinLTO is quite different from the structure of
295 /// "fat" LTO above. With "fat" LTO all LLVM modules in question are merged into
296 /// one giant LLVM module, and then we run more optimization passes over this
297 /// big module after internalizing most symbols. Thin LTO, on the other hand,
298 /// avoid this large bottleneck through more targeted optimization.
300 /// At a high level Thin LTO looks like:
302 /// 1. Prepare a "summary" of each LLVM module in question which describes
303 /// the values inside, cost of the values, etc.
304 /// 2. Merge the summaries of all modules in question into one "index"
305 /// 3. Perform some global analysis on this index
306 /// 4. For each module, use the index and analysis calculated previously to
307 /// perform local transformations on the module, for example inlining
308 /// small functions from other modules.
309 /// 5. Run thin-specific optimization passes over each module, and then code
310 /// generate everything at the end.
312 /// The summary for each module is intended to be quite cheap, and the global
313 /// index is relatively quite cheap to create as well. As a result, the goal of
314 /// ThinLTO is to reduce the bottleneck on LTO and enable LTO to be used in more
315 /// situations. For example one cheap optimization is that we can parallelize
316 /// all codegen modules, easily making use of all the cores on a machine.
318 /// With all that in mind, the function here is designed at specifically just
319 /// calculating the *index* for ThinLTO. This index will then be shared amongst
320 /// all of the `LtoModuleTranslation` units returned below and destroyed once
321 /// they all go out of scope.
322 fn thin_lto(diag_handler: &Handler,
323 modules: Vec<ModuleTranslation>,
324 serialized_modules: Vec<(SerializedModule, CString)>,
325 symbol_white_list: &[*const libc::c_char],
326 timeline: &mut Timeline)
327 -> Result<Vec<LtoModuleTranslation>, FatalError>
330 info!("going for that thin, thin LTO");
332 let mut thin_buffers = Vec::new();
333 let mut module_names = Vec::new();
334 let mut thin_modules = Vec::new();
336 // FIXME: right now, like with fat LTO, we serialize all in-memory
337 // modules before working with them and ThinLTO. We really
338 // shouldn't do this, however, and instead figure out how to
339 // extract a summary from an in-memory module and then merge that
340 // into the global index. It turns out that this loop is by far
341 // the most expensive portion of this small bit of global
343 for (i, module) in modules.iter().enumerate() {
344 info!("local module: {} - {}", i, module.llmod_id);
345 let llvm = module.llvm().expect("can't lto pretranslated module");
346 let name = CString::new(module.llmod_id.clone()).unwrap();
347 let buffer = ThinBuffer::new(llvm.llmod);
348 thin_modules.push(llvm::ThinLTOModule {
349 identifier: name.as_ptr(),
350 data: buffer.data().as_ptr(),
351 len: buffer.data().len(),
353 thin_buffers.push(buffer);
354 module_names.push(name);
355 timeline.record(&module.llmod_id);
358 // FIXME: All upstream crates are deserialized internally in the
359 // function below to extract their summary and modules. Note that
360 // unlike the loop above we *must* decode and/or read something
361 // here as these are all just serialized files on disk. An
362 // improvement, however, to make here would be to store the
363 // module summary separately from the actual module itself. Right
364 // now this is store in one large bitcode file, and the entire
365 // file is deflate-compressed. We could try to bypass some of the
366 // decompression by storing the index uncompressed and only
367 // lazily decompressing the bytecode if necessary.
369 // Note that truly taking advantage of this optimization will
370 // likely be further down the road. We'd have to implement
371 // incremental ThinLTO first where we could actually avoid
372 // looking at upstream modules entirely sometimes (the contents,
373 // we must always unconditionally look at the index).
374 let mut serialized = Vec::new();
375 for (module, name) in serialized_modules {
376 info!("foreign module {:?}", name);
377 thin_modules.push(llvm::ThinLTOModule {
378 identifier: name.as_ptr(),
379 data: module.data().as_ptr(),
380 len: module.data().len(),
382 serialized.push(module);
383 module_names.push(name);
386 // Delegate to the C++ bindings to create some data here. Once this is a
387 // tried-and-true interface we may wish to try to upstream some of this
388 // to LLVM itself, right now we reimplement a lot of what they do
390 let data = llvm::LLVMRustCreateThinLTOData(
391 thin_modules.as_ptr(),
392 thin_modules.len() as u32,
393 symbol_white_list.as_ptr(),
394 symbol_white_list.len() as u32,
397 let msg = format!("failed to prepare thin LTO context");
398 return Err(write::llvm_err(&diag_handler, msg))
400 let data = ThinData(data);
401 info!("thin LTO data created");
402 timeline.record("data");
404 // Throw our data in an `Arc` as we'll be sharing it across threads. We
405 // also put all memory referenced by the C++ data (buffers, ids, etc)
406 // into the arc as well. After this we'll create a thin module
407 // translation per module in this data.
408 let shared = Arc::new(ThinShared {
411 serialized_modules: serialized,
414 Ok((0..shared.module_names.len()).map(|i| {
415 LtoModuleTranslation::Thin(ThinModule {
416 shared: shared.clone(),
423 fn run_pass_manager(cgcx: &CodegenContext,
424 tm: TargetMachineRef,
426 config: &ModuleConfig,
428 // Now we have one massive module inside of llmod. Time to run the
429 // LTO-specific optimization passes that LLVM provides.
431 // This code is based off the code found in llvm's LTO code generator:
432 // tools/lto/LTOCodeGenerator.cpp
433 debug!("running the pass manager");
435 let pm = llvm::LLVMCreatePassManager();
436 llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
437 let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
438 assert!(!pass.is_null());
439 llvm::LLVMRustAddPass(pm, pass);
441 // When optimizing for LTO we don't actually pass in `-O0`, but we force
442 // it to always happen at least with `-O1`.
444 // With ThinLTO we mess around a lot with symbol visibility in a way
445 // that will actually cause linking failures if we optimize at O0 which
446 // notable is lacking in dead code elimination. To ensure we at least
447 // get some optimizations and correctly link we forcibly switch to `-O1`
448 // to get dead code elimination.
450 // Note that in general this shouldn't matter too much as you typically
451 // only turn on ThinLTO when you're compiling with optimizations
453 let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
454 let opt_level = match opt_level {
455 llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
458 with_llvm_pmb(llmod, config, opt_level, &mut |b| {
460 if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
461 panic!("this version of LLVM does not support ThinLTO");
464 llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
465 /* Internalize = */ False,
466 /* RunInliner = */ True);
470 let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
471 assert!(!pass.is_null());
472 llvm::LLVMRustAddPass(pm, pass);
474 time(cgcx.time_passes, "LTO passes", ||
475 llvm::LLVMRunPassManager(pm, llmod));
477 llvm::LLVMDisposePassManager(pm);
482 pub enum SerializedModule {
487 impl SerializedModule {
488 fn data(&self) -> &[u8] {
490 SerializedModule::Local(ref m) => m.data(),
491 SerializedModule::FromRlib(ref m) => m,
496 pub struct ModuleBuffer(*mut llvm::ModuleBuffer);
498 unsafe impl Send for ModuleBuffer {}
499 unsafe impl Sync for ModuleBuffer {}
502 pub fn new(m: ModuleRef) -> ModuleBuffer {
503 ModuleBuffer(unsafe {
504 llvm::LLVMRustModuleBufferCreate(m)
508 pub fn data(&self) -> &[u8] {
510 let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
511 let len = llvm::LLVMRustModuleBufferLen(self.0);
512 slice::from_raw_parts(ptr, len)
517 impl Drop for ModuleBuffer {
519 unsafe { llvm::LLVMRustModuleBufferFree(self.0); }
523 pub struct ThinModule {
524 shared: Arc<ThinShared>,
530 thin_buffers: Vec<ThinBuffer>,
531 serialized_modules: Vec<SerializedModule>,
532 module_names: Vec<CString>,
535 struct ThinData(*mut llvm::ThinLTOData);
537 unsafe impl Send for ThinData {}
538 unsafe impl Sync for ThinData {}
540 impl Drop for ThinData {
543 llvm::LLVMRustFreeThinLTOData(self.0);
548 pub struct ThinBuffer(*mut llvm::ThinLTOBuffer);
550 unsafe impl Send for ThinBuffer {}
551 unsafe impl Sync for ThinBuffer {}
554 pub fn new(m: ModuleRef) -> ThinBuffer {
556 let buffer = llvm::LLVMRustThinLTOBufferCreate(m);
561 pub fn data(&self) -> &[u8] {
563 let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
564 let len = llvm::LLVMRustThinLTOBufferLen(self.0);
565 slice::from_raw_parts(ptr, len)
570 impl Drop for ThinBuffer {
573 llvm::LLVMRustThinLTOBufferFree(self.0);
579 fn name(&self) -> &str {
580 self.shared.module_names[self.idx].to_str().unwrap()
583 fn cost(&self) -> u64 {
584 // Yes, that's correct, we're using the size of the bytecode as an
585 // indicator for how costly this codegen unit is.
586 self.data().len() as u64
589 fn data(&self) -> &[u8] {
590 let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
591 a.unwrap_or_else(|| {
592 let len = self.shared.thin_buffers.len();
593 self.shared.serialized_modules[self.idx - len].data()
597 unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline)
598 -> Result<ModuleTranslation, FatalError>
600 let diag_handler = cgcx.create_diag_handler();
601 let tm = (cgcx.tm_factory)().map_err(|e| {
602 write::llvm_err(&diag_handler, e)
605 // Right now the implementation we've got only works over serialized
606 // modules, so we create a fresh new LLVM context and parse the module
607 // into that context. One day, however, we may do this for upstream
608 // crates but for locally translated modules we may be able to reuse
609 // that LLVM Context and Module.
610 let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
611 let llmod = llvm::LLVMRustParseBitcodeForThinLTO(
613 self.data().as_ptr(),
615 self.shared.module_names[self.idx].as_ptr(),
618 let msg = format!("failed to parse bitcode for thin LTO module");
619 return Err(write::llvm_err(&diag_handler, msg));
621 let mtrans = ModuleTranslation {
622 source: ModuleSource::Translated(ModuleLlvm {
627 llmod_id: self.name().to_string(),
628 name: self.name().to_string(),
629 kind: ModuleKind::Regular,
631 cgcx.save_temp_bitcode(&mtrans, "thin-lto-input");
633 // Before we do much else find the "main" `DICompileUnit` that we'll be
634 // using below. If we find more than one though then rustc has changed
635 // in a way we're not ready for, so generate an ICE by returning
637 let mut cu1 = ptr::null_mut();
638 let mut cu2 = ptr::null_mut();
639 llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
641 let msg = format!("multiple source DICompileUnits found");
642 return Err(write::llvm_err(&diag_handler, msg))
645 // Like with "fat" LTO, get some better optimizations if landing pads
646 // are disabled by removing all landing pads.
647 if cgcx.no_landing_pads {
648 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
649 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-nounwind");
650 timeline.record("nounwind");
653 // Up next comes the per-module local analyses that we do for Thin LTO.
654 // Each of these functions is basically copied from the LLVM
655 // implementation and then tailored to suit this implementation. Ideally
656 // each of these would be supported by upstream LLVM but that's perhaps
657 // a patch for another day!
659 // You can find some more comments about these functions in the LLVM
660 // bindings we've got (currently `PassWrapper.cpp`)
661 if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
662 let msg = format!("failed to prepare thin LTO module");
663 return Err(write::llvm_err(&diag_handler, msg))
665 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rename");
666 timeline.record("rename");
667 if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
668 let msg = format!("failed to prepare thin LTO module");
669 return Err(write::llvm_err(&diag_handler, msg))
671 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-resolve");
672 timeline.record("resolve");
673 if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
674 let msg = format!("failed to prepare thin LTO module");
675 return Err(write::llvm_err(&diag_handler, msg))
677 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-internalize");
678 timeline.record("internalize");
679 if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
680 let msg = format!("failed to prepare thin LTO module");
681 return Err(write::llvm_err(&diag_handler, msg))
683 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-import");
684 timeline.record("import");
686 // Ok now this is a bit unfortunate. This is also something you won't
687 // find upstream in LLVM's ThinLTO passes! This is a hack for now to
688 // work around bugs in LLVM.
690 // First discovered in #45511 it was found that as part of ThinLTO
691 // importing passes LLVM will import `DICompileUnit` metadata
692 // information across modules. This means that we'll be working with one
693 // LLVM module that has multiple `DICompileUnit` instances in it (a
694 // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
695 // bugs in LLVM's backend which generates invalid DWARF in a situation
698 // https://bugs.llvm.org/show_bug.cgi?id=35212
699 // https://bugs.llvm.org/show_bug.cgi?id=35562
701 // While the first bug there is fixed the second ended up causing #46346
702 // which was basically a resurgence of #45511 after LLVM's bug 35212 was
705 // This function below is a huge hack around tihs problem. The function
706 // below is defined in `PassWrapper.cpp` and will basically "merge"
707 // all `DICompileUnit` instances in a module. Basically it'll take all
708 // the objects, rewrite all pointers of `DISubprogram` to point to the
709 // first `DICompileUnit`, and then delete all the other units.
711 // This is probably mangling to the debug info slightly (but hopefully
712 // not too much) but for now at least gets LLVM to emit valid DWARF (or
713 // so it appears). Hopefully we can remove this once upstream bugs are
715 llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
716 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-patch");
717 timeline.record("patch");
719 // Alright now that we've done everything related to the ThinLTO
720 // analysis it's time to run some optimizations! Here we use the same
721 // `run_pass_manager` as the "fat" LTO above except that we tell it to
722 // populate a thin-specific pass manager, which presumably LLVM treats a
723 // little differently.
724 info!("running thin lto passes over {}", mtrans.name);
725 let config = cgcx.config(mtrans.kind);
726 run_pass_manager(cgcx, tm, llmod, config, true);
727 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-pm");
728 timeline.record("thin-done");
730 // FIXME: this is a hack around a bug in LLVM right now. Discovered in
731 // #46910 it was found out that on 32-bit MSVC LLVM will hit a codegen
732 // error if there's an available_externally function in the LLVM module.
733 // Typically we don't actually use these functions but ThinLTO makes
734 // heavy use of them when inlining across modules.
736 // Tracked upstream at https://bugs.llvm.org/show_bug.cgi?id=35736 this
737 // function call (and its definition on the C++ side of things)
738 // shouldn't be necessary eventually and we can safetly delete these few
740 llvm::LLVMRustThinLTORemoveAvailableExternally(llmod);
741 cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rm-ae");
742 timeline.record("no-ae");