]> git.lizzy.rs Git - rust.git/blob - src/librustc/back/lto.rs
rand: Use fill() instead of read()
[rust.git] / src / librustc / 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 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 std::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     let crate_types = sess.crate_types.borrow();
31     for crate_type in crate_types.get().iter() {
32         match *crate_type {
33             session::CrateTypeExecutable | session::CrateTypeStaticlib => {}
34             _ => {
35                 sess.fatal("lto can only be run for executables and \
36                             static library outputs");
37             }
38         }
39     }
40
41     // For each of our upstream dependencies, find the corresponding rlib and
42     // load the bitcode from the archive. Then merge it into the current LLVM
43     // module that we've got.
44     let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
45     for (cnum, path) in crates.move_iter() {
46         let name = sess.cstore.get_crate_data(cnum).name.clone();
47         let path = match path {
48             Some(p) => p,
49             None => {
50                 sess.fatal(format!("could not find rlib for: `{}`", name));
51             }
52         };
53
54         let archive = ArchiveRO::open(&path).expect("wanted an rlib");
55         debug!("reading {}", name);
56         let bc = time(sess.time_passes(), format!("read {}.bc", name), (), |_|
57                       archive.read(format!("{}.bc", name)));
58         let bc = bc.expect("missing bytecode in archive!");
59         let bc = time(sess.time_passes(), format!("inflate {}.bc", name), (), |_|
60                       flate::inflate_bytes(bc));
61         let ptr = bc.as_slice().as_ptr();
62         debug!("linking {}", name);
63         time(sess.time_passes(), format!("ll link {}", name), (), |()| unsafe {
64             if !llvm::LLVMRustLinkInExternalBitcode(llmod,
65                                                     ptr as *libc::c_char,
66                                                     bc.len() as libc::size_t) {
67                 link::llvm_err(sess, format!("failed to load bc of `{}`", name));
68             }
69         });
70     }
71
72     // Internalize everything but the reachable symbols of the current module
73     let cstrs = reachable.map(|s| s.to_c_str());
74     let arr = cstrs.map(|c| c.with_ref(|p| p));
75     let ptr = arr.as_ptr();
76     unsafe {
77         llvm::LLVMRustRunRestrictionPass(llmod, ptr as **libc::c_char,
78                                          arr.len() as libc::size_t);
79     }
80
81     if sess.no_landing_pads() {
82         unsafe {
83             llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
84         }
85     }
86
87     // Now we have one massive module inside of llmod. Time to run the
88     // LTO-specific optimization passes that LLVM provides.
89     //
90     // This code is based off the code found in llvm's LTO code generator:
91     //      tools/lto/LTOCodeGenerator.cpp
92     debug!("running the pass manager");
93     unsafe {
94         let pm = llvm::LLVMCreatePassManager();
95         llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
96         "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
97
98         let builder = llvm::LLVMPassManagerBuilderCreate();
99         llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
100             /* Internalize = */ False,
101             /* RunInliner = */ True);
102         llvm::LLVMPassManagerBuilderDispose(builder);
103
104         "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
105
106         time(sess.time_passes(), "LTO pases", (), |()|
107              llvm::LLVMRunPassManager(pm, llmod));
108
109         llvm::LLVMDisposePassManager(pm);
110     }
111     debug!("lto done");
112 }