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.
13 use back::symbol_export;
14 use rustc::session::config;
15 use errors::FatalError;
17 use llvm::archive_ro::ArchiveRO;
18 use llvm::{ModuleRef, TargetMachineRef, True, False};
19 use rustc::util::common::time;
20 use rustc::util::common::path2cstr;
21 use rustc::hir::def_id::LOCAL_CRATE;
22 use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
25 use flate2::read::DeflateDecoder;
28 use std::ffi::CString;
31 pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
33 config::CrateTypeExecutable |
34 config::CrateTypeStaticlib |
35 config::CrateTypeCdylib => true,
37 config::CrateTypeDylib |
38 config::CrateTypeRlib |
39 config::CrateTypeProcMacro => false,
43 pub fn run(cgcx: &CodegenContext,
46 config: &ModuleConfig,
47 temp_no_opt_bc_filename: &Path) -> Result<(), FatalError> {
48 let handler = cgcx.handler;
49 if cgcx.opts.cg.prefer_dynamic {
50 handler.struct_err("cannot prefer dynamic linking when performing LTO")
51 .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
54 return Err(FatalError)
57 // Make sure we actually can run LTO
58 for crate_type in cgcx.crate_types.iter() {
59 if !crate_type_allows_lto(*crate_type) {
60 let e = handler.fatal("lto can only be run for executables, cdylibs and \
61 static library outputs");
66 let export_threshold =
67 symbol_export::crates_export_threshold(&cgcx.crate_types);
69 let symbol_filter = &|&(ref name, level): &(String, _)| {
70 if symbol_export::is_below_threshold(level, export_threshold) {
71 let mut bytes = Vec::with_capacity(name.len() + 1);
72 bytes.extend(name.bytes());
73 Some(CString::new(bytes).unwrap())
79 let mut symbol_white_list: Vec<CString> = cgcx.exported_symbols
80 .exported_symbols(LOCAL_CRATE)
82 .filter_map(symbol_filter)
85 // For each of our upstream dependencies, find the corresponding rlib and
86 // load the bitcode from the archive. Then merge it into the current LLVM
87 // module that we've got.
88 for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
89 symbol_white_list.extend(
90 cgcx.exported_symbols.exported_symbols(cnum)
92 .filter_map(symbol_filter));
94 let archive = ArchiveRO::open(&path).expect("wanted an rlib");
95 let bytecodes = archive.iter().filter_map(|child| {
96 child.ok().and_then(|c| c.name().map(|name| (name, c)))
97 }).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
98 for (name, data) in bytecodes {
99 let bc_encoded = data.data();
101 let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
102 time(cgcx.time_passes, &format!("decode {}", name), || {
104 let version = extract_bytecode_format_version(bc_encoded);
107 // The only version existing so far
108 let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
109 let compressed_data = &bc_encoded[
110 link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET..
111 (link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as usize)];
113 let mut inflated = Vec::new();
114 let res = DeflateDecoder::new(compressed_data)
115 .read_to_end(&mut inflated);
117 let msg = format!("failed to decompress bc of `{}`",
119 Err(handler.fatal(&msg))
124 Err(handler.fatal(&format!("Unsupported bytecode format version {}",
129 time(cgcx.time_passes, &format!("decode {}", name), || {
130 // the object must be in the old, pre-versioning format, so
131 // simply inflate everything and let LLVM decide if it can
133 let mut inflated = Vec::new();
134 let res = DeflateDecoder::new(bc_encoded)
135 .read_to_end(&mut inflated);
137 let msg = format!("failed to decompress bc of `{}`",
139 Err(handler.fatal(&msg))
146 let ptr = bc_decoded.as_ptr();
147 debug!("linking {}", name);
148 time(cgcx.time_passes, &format!("ll link {}", name), || unsafe {
149 if llvm::LLVMRustLinkInExternalBitcode(llmod,
150 ptr as *const libc::c_char,
151 bc_decoded.len() as libc::size_t) {
154 let msg = format!("failed to load bc of `{}`", name);
155 Err(write::llvm_err(handler, msg))
161 // Internalize everything but the exported symbols of the current module
162 let arr: Vec<*const libc::c_char> = symbol_white_list.iter()
165 let ptr = arr.as_ptr();
167 llvm::LLVMRustRunRestrictionPass(llmod,
168 ptr as *const *const libc::c_char,
169 arr.len() as libc::size_t);
172 if cgcx.no_landing_pads {
174 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
178 if cgcx.opts.cg.save_temps {
179 let cstr = path2cstr(temp_no_opt_bc_filename);
181 llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
185 // Now we have one massive module inside of llmod. Time to run the
186 // LTO-specific optimization passes that LLVM provides.
188 // This code is based off the code found in llvm's LTO code generator:
189 // tools/lto/LTOCodeGenerator.cpp
190 debug!("running the pass manager");
192 let pm = llvm::LLVMCreatePassManager();
193 llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
194 let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
195 assert!(!pass.is_null());
196 llvm::LLVMRustAddPass(pm, pass);
198 with_llvm_pmb(llmod, config, &mut |b| {
199 llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
200 /* Internalize = */ False,
201 /* RunInliner = */ True);
204 let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
205 assert!(!pass.is_null());
206 llvm::LLVMRustAddPass(pm, pass);
208 time(cgcx.time_passes, "LTO passes", ||
209 llvm::LLVMRunPassManager(pm, llmod));
211 llvm::LLVMDisposePassManager(pm);
217 fn is_versioned_bytecode_format(bc: &[u8]) -> bool {
218 let magic_id_byte_count = link::RLIB_BYTECODE_OBJECT_MAGIC.len();
219 return bc.len() > magic_id_byte_count &&
220 &bc[..magic_id_byte_count] == link::RLIB_BYTECODE_OBJECT_MAGIC;
223 fn extract_bytecode_format_version(bc: &[u8]) -> u32 {
224 let pos = link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET;
225 let byte_data = &bc[pos..pos + 4];
226 let data = unsafe { *(byte_data.as_ptr() as *const u32) };
230 fn extract_compressed_bytecode_size_v1(bc: &[u8]) -> u64 {
231 let pos = link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET;
232 let byte_data = &bc[pos..pos + 8];
233 let data = unsafe { *(byte_data.as_ptr() as *const u64) };