]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/back/lto.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.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::metadata::cstore;
18 use rustc::util::common::time;
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 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 {
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));
57 }
58 };
59
60 let archive = ArchiveRO::open(&path).expect("wanted an rlib");
61 let bytecodes = archive.iter().filter_map(|child| {
62 child.name().map(|name| (name, child))
63 }).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
64 for (name, data) in bytecodes {
65 let bc_encoded = data.data();
66
67 let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
68 time(sess.time_passes(), &format!("decode {}", name), (), |_| {
69 // Read the version
70 let version = extract_bytecode_format_version(bc_encoded);
71
72 if version == 1 {
73 // The only version existing so far
74 let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
75 let compressed_data = &bc_encoded[
76 link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET..
77 (link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as usize)];
78
79 match flate::inflate_bytes(compressed_data) {
80 Ok(inflated) => inflated,
81 Err(_) => {
82 sess.fatal(&format!("failed to decompress bc of `{}`",
83 name))
84 }
85 }
86 } else {
87 sess.fatal(&format!("Unsupported bytecode format version {}",
88 version))
89 }
90 })
91 } else {
92 time(sess.time_passes(), &format!("decode {}", name), (), |_| {
93 // the object must be in the old, pre-versioning format, so simply
94 // inflate everything and let LLVM decide if it can make sense of it
95 match flate::inflate_bytes(bc_encoded) {
96 Ok(bc) => bc,
97 Err(_) => {
98 sess.fatal(&format!("failed to decompress bc of `{}`",
99 name))
100 }
101 }
102 })
103 };
104
105 let ptr = bc_decoded.as_ptr();
106 debug!("linking {}", name);
107 time(sess.time_passes(), &format!("ll link {}", name), (),
108 |()| unsafe {
109 if !llvm::LLVMRustLinkInExternalBitcode(llmod,
110 ptr as *const libc::c_char,
111 bc_decoded.len() as libc::size_t) {
112 write::llvm_err(sess.diagnostic().handler(),
113 format!("failed to load bc of `{}`",
114 &name[..]));
115 }
116 });
117 }
118 }
119
120 // Internalize everything but the reachable symbols of the current module
121 let cstrs: Vec<CString> = reachable.iter().map(|s| {
122 CString::new(s.clone()).unwrap()
123 }).collect();
124 let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
125 let ptr = arr.as_ptr();
126 unsafe {
127 llvm::LLVMRustRunRestrictionPass(llmod,
128 ptr as *const *const libc::c_char,
129 arr.len() as libc::size_t);
130 }
131
132 if sess.no_landing_pads() {
133 unsafe {
134 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
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 }