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