]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/lto.rs
Fix checking for missing stability annotations
[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 back::link;
12 use back::write;
13 use back::symbol_export;
14 use rustc::session::config;
15 use errors::FatalError;
16 use llvm;
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};
23
24 use libc;
25 use flate2::read::DeflateDecoder;
26
27 use std::io::Read;
28 use std::ffi::CString;
29 use std::path::Path;
30
31 pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
32     match crate_type {
33         config::CrateTypeExecutable |
34         config::CrateTypeStaticlib  |
35         config::CrateTypeCdylib     => true,
36
37         config::CrateTypeDylib     |
38         config::CrateTypeRlib      |
39         config::CrateTypeProcMacro => false,
40     }
41 }
42
43 pub fn run(cgcx: &CodegenContext,
44            llmod: ModuleRef,
45            tm: TargetMachineRef,
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 \
52                    supported with LTO")
53             .emit();
54         return Err(FatalError)
55     }
56
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");
62             return Err(e)
63         }
64     }
65
66     let export_threshold =
67         symbol_export::crates_export_threshold(&cgcx.crate_types);
68
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())
74         } else {
75             None
76         }
77     };
78
79     let mut symbol_white_list: Vec<CString> = cgcx.exported_symbols
80         .exported_symbols(LOCAL_CRATE)
81         .iter()
82         .filter_map(symbol_filter)
83         .collect();
84
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)
91                                  .iter()
92                                  .filter_map(symbol_filter));
93
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();
100
101             let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
102                 time(cgcx.time_passes, &format!("decode {}", name), || {
103                     // Read the version
104                     let version = extract_bytecode_format_version(bc_encoded);
105
106                     if version == 1 {
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)];
112
113                         let mut inflated = Vec::new();
114                         let res = DeflateDecoder::new(compressed_data)
115                             .read_to_end(&mut inflated);
116                         if res.is_err() {
117                             let msg = format!("failed to decompress bc of `{}`",
118                                               name);
119                             Err(handler.fatal(&msg))
120                         } else {
121                             Ok(inflated)
122                         }
123                     } else {
124                         Err(handler.fatal(&format!("Unsupported bytecode format version {}",
125                                                    version)))
126                     }
127                 })?
128             } else {
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
132                     // make sense of it
133                     let mut inflated = Vec::new();
134                     let res = DeflateDecoder::new(bc_encoded)
135                         .read_to_end(&mut inflated);
136                     if res.is_err() {
137                         let msg = format!("failed to decompress bc of `{}`",
138                                           name);
139                         Err(handler.fatal(&msg))
140                     } else {
141                         Ok(inflated)
142                     }
143                 })?
144             };
145
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) {
152                     Ok(())
153                 } else {
154                     let msg = format!("failed to load bc of `{}`", name);
155                     Err(write::llvm_err(handler, msg))
156                 }
157             })?;
158         }
159     }
160
161     // Internalize everything but the exported symbols of the current module
162     let arr: Vec<*const libc::c_char> = symbol_white_list.iter()
163                                                          .map(|c| c.as_ptr())
164                                                          .collect();
165     let ptr = arr.as_ptr();
166     unsafe {
167         llvm::LLVMRustRunRestrictionPass(llmod,
168                                          ptr as *const *const libc::c_char,
169                                          arr.len() as libc::size_t);
170     }
171
172     if cgcx.no_landing_pads {
173         unsafe {
174             llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
175         }
176     }
177
178     if cgcx.opts.cg.save_temps {
179         let cstr = path2cstr(temp_no_opt_bc_filename);
180         unsafe {
181             llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
182         }
183     }
184
185     // Now we have one massive module inside of llmod. Time to run the
186     // LTO-specific optimization passes that LLVM provides.
187     //
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");
191     unsafe {
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);
197
198         with_llvm_pmb(llmod, config, &mut |b| {
199             llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
200                 /* Internalize = */ False,
201                 /* RunInliner = */ True);
202         });
203
204         let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
205         assert!(!pass.is_null());
206         llvm::LLVMRustAddPass(pm, pass);
207
208         time(cgcx.time_passes, "LTO passes", ||
209              llvm::LLVMRunPassManager(pm, llmod));
210
211         llvm::LLVMDisposePassManager(pm);
212     }
213     debug!("lto done");
214     Ok(())
215 }
216
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;
221 }
222
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) };
227     u32::from_le(data)
228 }
229
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) };
234     u64::from_le(data)
235 }