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