]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/lto.rs
auto merge of #19628 : jbranchaud/rust/add-string-as-string-doctest, r=steveklabnik
[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::{mod, config};
14 use llvm;
15 use llvm::archive_ro::ArchiveRO;
16 use llvm::{ModuleRef, TargetMachineRef, True, False};
17 use rustc::metadata::cstore;
18 use rustc::util::common::time;
19
20 use libc;
21 use flate;
22
23 use std::iter;
24 use std::mem;
25 use std::num::Int;
26
27 pub fn run(sess: &session::Session, llmod: ModuleRef,
28            tm: TargetMachineRef, reachable: &[String]) {
29     if sess.opts.cg.prefer_dynamic {
30         sess.err("cannot prefer dynamic linking when performing LTO");
31         sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
32         sess.abort_if_errors();
33     }
34
35     // Make sure we actually can run LTO
36     for crate_type in sess.crate_types.borrow().iter() {
37         match *crate_type {
38             config::CrateTypeExecutable | config::CrateTypeStaticlib => {}
39             _ => {
40                 sess.fatal("lto can only be run for executables and \
41                             static library outputs");
42             }
43         }
44     }
45
46     // For each of our upstream dependencies, find the corresponding rlib and
47     // load the bitcode from the archive. Then merge it into the current LLVM
48     // module that we've got.
49     let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
50     for (cnum, path) in crates.into_iter() {
51         let name = sess.cstore.get_crate_data(cnum).name.clone();
52         let path = match path {
53             Some(p) => p,
54             None => {
55                 sess.fatal(format!("could not find rlib for: `{}`",
56                                    name).as_slice());
57             }
58         };
59
60         let archive = ArchiveRO::open(&path).expect("wanted an rlib");
61         let file = path.filename_str().unwrap();
62         let file = file.slice(3, file.len() - 5); // chop off lib/.rlib
63         debug!("reading {}", file);
64         for i in iter::count(0u, 1) {
65             let bc_encoded = time(sess.time_passes(),
66                                   format!("check for {}.{}.bytecode.deflate", name, i).as_slice(),
67                                   (),
68                                   |_| {
69                                       archive.read(format!("{}.{}.bytecode.deflate",
70                                                            file, i).as_slice())
71                                   });
72             let bc_encoded = match bc_encoded {
73                 Some(data) => data,
74                 None => {
75                     if i == 0 {
76                         // No bitcode was found at all.
77                         sess.fatal(format!("missing compressed bytecode in {}",
78                                            path.display()).as_slice());
79                     }
80                     // No more bitcode files to read.
81                     break;
82                 },
83             };
84             let bc_extractor = if is_versioned_bytecode_format(bc_encoded) {
85                 |_| {
86                     // Read the version
87                     let version = extract_bytecode_format_version(bc_encoded);
88
89                     if version == 1 {
90                         // The only version existing so far
91                         let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
92                         let compressed_data = bc_encoded[
93                             link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET..
94                             link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as uint];
95
96                         match flate::inflate_bytes(compressed_data) {
97                             Some(inflated) => inflated,
98                             None => {
99                                 sess.fatal(format!("failed to decompress bc of `{}`",
100                                                    name).as_slice())
101                             }
102                         }
103                     } else {
104                         sess.fatal(format!("Unsupported bytecode format version {}",
105                                            version).as_slice())
106                     }
107                 }
108             } else {
109                 // the object must be in the old, pre-versioning format, so simply
110                 // inflate everything and let LLVM decide if it can make sense of it
111                 |_| {
112                     match flate::inflate_bytes(bc_encoded) {
113                         Some(bc) => bc,
114                         None => {
115                             sess.fatal(format!("failed to decompress bc of `{}`",
116                                                name).as_slice())
117                         }
118                     }
119                 }
120             };
121
122             let bc_decoded = time(sess.time_passes(),
123                                   format!("decode {}.{}.bc", file, i).as_slice(),
124                                   (),
125                                   bc_extractor);
126
127             let ptr = bc_decoded.as_slice().as_ptr();
128             debug!("linking {}, part {}", name, i);
129             time(sess.time_passes(),
130                  format!("ll link {}.{}", name, i).as_slice(),
131                  (),
132                  |()| unsafe {
133                 if !llvm::LLVMRustLinkInExternalBitcode(llmod,
134                                                         ptr as *const libc::c_char,
135                                                         bc_decoded.len() as libc::size_t) {
136                     write::llvm_err(sess.diagnostic().handler(),
137                                     format!("failed to load bc of `{}`",
138                                             name.as_slice()));
139                 }
140             });
141         }
142     }
143
144     // Internalize everything but the reachable symbols of the current module
145     let cstrs: Vec<::std::c_str::CString> =
146         reachable.iter().map(|s| s.to_c_str()).collect();
147     let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect();
148     let ptr = arr.as_ptr();
149     unsafe {
150         llvm::LLVMRustRunRestrictionPass(llmod,
151                                          ptr as *const *const libc::c_char,
152                                          arr.len() as libc::size_t);
153     }
154
155     if sess.no_landing_pads() {
156         unsafe {
157             llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
158         }
159     }
160
161     // Now we have one massive module inside of llmod. Time to run the
162     // LTO-specific optimization passes that LLVM provides.
163     //
164     // This code is based off the code found in llvm's LTO code generator:
165     //      tools/lto/LTOCodeGenerator.cpp
166     debug!("running the pass manager");
167     unsafe {
168         let pm = llvm::LLVMCreatePassManager();
169         llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
170         "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
171
172         let builder = llvm::LLVMPassManagerBuilderCreate();
173         llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
174             /* Internalize = */ False,
175             /* RunInliner = */ True);
176         llvm::LLVMPassManagerBuilderDispose(builder);
177
178         "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
179
180         time(sess.time_passes(), "LTO passes", (), |()|
181              llvm::LLVMRunPassManager(pm, llmod));
182
183         llvm::LLVMDisposePassManager(pm);
184     }
185     debug!("lto done");
186 }
187
188 fn is_versioned_bytecode_format(bc: &[u8]) -> bool {
189     let magic_id_byte_count = link::RLIB_BYTECODE_OBJECT_MAGIC.len();
190     return bc.len() > magic_id_byte_count &&
191            bc[..magic_id_byte_count] == link::RLIB_BYTECODE_OBJECT_MAGIC;
192 }
193
194 fn extract_bytecode_format_version(bc: &[u8]) -> u32 {
195     return read_from_le_bytes::<u32>(bc, link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET);
196 }
197
198 fn extract_compressed_bytecode_size_v1(bc: &[u8]) -> u64 {
199     return read_from_le_bytes::<u64>(bc, link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET);
200 }
201
202 fn read_from_le_bytes<T: Int>(bytes: &[u8], position_in_bytes: uint) -> T {
203     let byte_data = bytes[position_in_bytes..
204                           position_in_bytes + mem::size_of::<T>()];
205     let data = unsafe {
206         *(byte_data.as_ptr() as *const T)
207     };
208
209     Int::from_le(data)
210 }
211