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