]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/lto.rs
46b1241de368f9bfaa992d942f5d669a5ffd74da
[rust.git] / src / librustc_trans / back / lto.rs
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.
4 //
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.
10
11 use super::link;
12 use super::write;
13 use rustc::session::{self, config};
14 use llvm;
15 use llvm::archive_ro::ArchiveRO;
16 use llvm::{ModuleRef, TargetMachineRef, True, False};
17 use rustc::util::common::time;
18 use rustc::util::common::path2cstr;
19 use back::write::{ModuleConfig, with_llvm_pmb};
20
21 use libc;
22 use flate;
23
24 use std::ffi::CString;
25 use std::path::Path;
26
27 pub fn run(sess: &session::Session, llmod: ModuleRef,
28            tm: TargetMachineRef, exported_symbols: &[String],
29            config: &ModuleConfig,
30            temp_no_opt_bc_filename: &Path) {
31     if sess.opts.cg.prefer_dynamic {
32         sess.struct_err("cannot prefer dynamic linking when performing LTO")
33             .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
34                    supported with LTO")
35             .emit();
36         sess.abort_if_errors();
37     }
38
39     // Make sure we actually can run LTO
40     for crate_type in sess.crate_types.borrow().iter() {
41         match *crate_type {
42             config::CrateTypeExecutable |
43             config::CrateTypeCdylib |
44             config::CrateTypeStaticlib => {}
45             _ => {
46                 sess.fatal("lto can only be run for executables and \
47                             static library outputs");
48             }
49         }
50     }
51
52     // For each of our upstream dependencies, find the corresponding rlib and
53     // load the bitcode from the archive. Then merge it into the current LLVM
54     // module that we've got.
55     link::each_linked_rlib(sess, &mut |cnum, path| {
56         // `#![no_builtins]` crates don't participate in LTO.
57         if sess.cstore.is_no_builtins(cnum) {
58             return;
59         }
60
61         let archive = ArchiveRO::open(&path).expect("wanted an rlib");
62         let bytecodes = archive.iter().filter_map(|child| {
63             child.ok().and_then(|c| c.name().map(|name| (name, c)))
64         }).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
65         for (name, data) in bytecodes {
66             let bc_encoded = data.data();
67
68             let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
69                 time(sess.time_passes(), &format!("decode {}", name), || {
70                     // Read the version
71                     let version = extract_bytecode_format_version(bc_encoded);
72
73                     if version == 1 {
74                         // The only version existing so far
75                         let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
76                         let compressed_data = &bc_encoded[
77                             link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET..
78                             (link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as usize)];
79
80                         match flate::inflate_bytes(compressed_data) {
81                             Ok(inflated) => inflated,
82                             Err(_) => {
83                                 sess.fatal(&format!("failed to decompress bc of `{}`",
84                                                    name))
85                             }
86                         }
87                     } else {
88                         sess.fatal(&format!("Unsupported bytecode format version {}",
89                                            version))
90                     }
91                 })
92             } else {
93                 time(sess.time_passes(), &format!("decode {}", name), || {
94                     // the object must be in the old, pre-versioning format, so
95                     // simply inflate everything and let LLVM decide if it can
96                     // make sense of it
97                     match flate::inflate_bytes(bc_encoded) {
98                         Ok(bc) => bc,
99                         Err(_) => {
100                             sess.fatal(&format!("failed to decompress bc of `{}`",
101                                                name))
102                         }
103                     }
104                 })
105             };
106
107             let ptr = bc_decoded.as_ptr();
108             debug!("linking {}", name);
109             time(sess.time_passes(), &format!("ll link {}", name), || unsafe {
110                 if !llvm::LLVMRustLinkInExternalBitcode(llmod,
111                                                         ptr as *const libc::c_char,
112                                                         bc_decoded.len() as libc::size_t) {
113                     write::llvm_err(sess.diagnostic(),
114                                     format!("failed to load bc of `{}`",
115                                             &name[..]));
116                 }
117             });
118         }
119     });
120
121     // Internalize everything but the exported symbols of the current module
122     let cstrs: Vec<CString> = exported_symbols.iter().map(|s| {
123         CString::new(s.clone()).unwrap()
124     }).collect();
125     let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
126     let ptr = arr.as_ptr();
127     unsafe {
128         llvm::LLVMRustRunRestrictionPass(llmod,
129                                          ptr as *const *const libc::c_char,
130                                          arr.len() as libc::size_t);
131     }
132
133     if sess.no_landing_pads() {
134         unsafe {
135             llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
136         }
137     }
138
139     if sess.opts.cg.save_temps {
140         let cstr = path2cstr(temp_no_opt_bc_filename);
141         unsafe {
142             llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
143         }
144     }
145
146     // Now we have one massive module inside of llmod. Time to run the
147     // LTO-specific optimization passes that LLVM provides.
148     //
149     // This code is based off the code found in llvm's LTO code generator:
150     //      tools/lto/LTOCodeGenerator.cpp
151     debug!("running the pass manager");
152     unsafe {
153         let pm = llvm::LLVMCreatePassManager();
154         llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
155         let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
156         assert!(!pass.is_null());
157         llvm::LLVMRustAddPass(pm, pass);
158
159         with_llvm_pmb(llmod, config, &mut |b| {
160             llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
161                 /* Internalize = */ False,
162                 /* RunInliner = */ True);
163         });
164
165         let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
166         assert!(!pass.is_null());
167         llvm::LLVMRustAddPass(pm, pass);
168
169         time(sess.time_passes(), "LTO passes", ||
170              llvm::LLVMRunPassManager(pm, llmod));
171
172         llvm::LLVMDisposePassManager(pm);
173     }
174     debug!("lto done");
175 }
176
177 fn is_versioned_bytecode_format(bc: &[u8]) -> bool {
178     let magic_id_byte_count = link::RLIB_BYTECODE_OBJECT_MAGIC.len();
179     return bc.len() > magic_id_byte_count &&
180            &bc[..magic_id_byte_count] == link::RLIB_BYTECODE_OBJECT_MAGIC;
181 }
182
183 fn extract_bytecode_format_version(bc: &[u8]) -> u32 {
184     let pos = link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET;
185     let byte_data = &bc[pos..pos + 4];
186     let data = unsafe { *(byte_data.as_ptr() as *const u32) };
187     u32::from_le(data)
188 }
189
190 fn extract_compressed_bytecode_size_v1(bc: &[u8]) -> u64 {
191     let pos = link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET;
192     let byte_data = &bc[pos..pos + 8];
193     let data = unsafe { *(byte_data.as_ptr() as *const u64) };
194     u64::from_le(data)
195 }