(index<- ) ./librustc/back/lto.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Wed Apr 9 17:27:02 2014
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 back::archive::ArchiveRO;
12 use back::link;
13 use driver::session;
14 use lib::llvm::{ModuleRef, TargetMachineRef, llvm, True, False};
15 use metadata::cstore;
16 use util::common::time;
17
18 use libc;
19 use flate;
20
21 pub fn run(sess: &session::Session, llmod: ModuleRef,
22 tm: TargetMachineRef, reachable: &[~str]) {
23 if sess.opts.cg.prefer_dynamic {
24 sess.err("cannot prefer dynamic linking when performing LTO");
25 sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
26 sess.abort_if_errors();
27 }
28
29 // Make sure we actually can run LTO
30 for crate_type in sess.crate_types.borrow().iter() {
31 match *crate_type {
32 session::CrateTypeExecutable | session::CrateTypeStaticlib => {}
33 _ => {
34 sess.fatal("lto can only be run for executables and \
35 static library outputs");
36 }
37 }
38 }
39
40 // For each of our upstream dependencies, find the corresponding rlib and
41 // load the bitcode from the archive. Then merge it into the current LLVM
42 // module that we've got.
43 let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
44 for (cnum, path) in crates.move_iter() {
45 let name = sess.cstore.get_crate_data(cnum).name.clone();
46 let path = match path {
47 Some(p) => p,
48 None => {
49 sess.fatal(format!("could not find rlib for: `{}`", name));
50 }
51 };
52
53 let archive = ArchiveRO::open(&path).expect("wanted an rlib");
54 debug!("reading {}", name);
55 let bc = time(sess.time_passes(), format!("read {}.bc.deflate", name), (), |_|
56 archive.read(format!("{}.bc.deflate", name)));
57 let bc = bc.expect("missing compressed bytecode in archive!");
58 let bc = time(sess.time_passes(), format!("inflate {}.bc", name), (), |_|
59 match flate::inflate_bytes(bc) {
60 Some(bc) => bc,
61 None => sess.fatal(format!("failed to decompress bc of `{}`", name))
62 });
63 let ptr = bc.as_slice().as_ptr();
64 debug!("linking {}", name);
65 time(sess.time_passes(), format!("ll link {}", name), (), |()| unsafe {
66 if !llvm::LLVMRustLinkInExternalBitcode(llmod,
67 ptr as *libc::c_char,
68 bc.len() as libc::size_t) {
69 link::llvm_err(sess, format!("failed to load bc of `{}`", name));
70 }
71 });
72 }
73
74 // Internalize everything but the reachable symbols of the current module
75 let cstrs: Vec<::std::c_str::CString> = reachable.iter().map(|s| s.to_c_str()).collect();
76 let arr: Vec<*i8> = cstrs.iter().map(|c| c.with_ref(|p| p)).collect();
77 let ptr = arr.as_ptr();
78 unsafe {
79 llvm::LLVMRustRunRestrictionPass(llmod, ptr as **libc::c_char,
80 arr.len() as libc::size_t);
81 }
82
83 if sess.no_landing_pads() {
84 unsafe {
85 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
86 }
87 }
88
89 // Now we have one massive module inside of llmod. Time to run the
90 // LTO-specific optimization passes that LLVM provides.
91 //
92 // This code is based off the code found in llvm's LTO code generator:
93 // tools/lto/LTOCodeGenerator.cpp
94 debug!("running the pass manager");
95 unsafe {
96 let pm = llvm::LLVMCreatePassManager();
97 llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
98 "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
99
100 let builder = llvm::LLVMPassManagerBuilderCreate();
101 llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
102 /* Internalize = */ False,
103 /* RunInliner = */ True);
104 llvm::LLVMPassManagerBuilderDispose(builder);
105
106 "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
107
108 time(sess.time_passes(), "LTO pases", (), |()|
109 llvm::LLVMRunPassManager(pm, llmod));
110
111 llvm::LLVMDisposePassManager(pm);
112 }
113 debug!("lto done");
114 }