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.
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.
11 use back::archive::ArchiveRO;
14 use lib::llvm::{ModuleRef, TargetMachineRef, llvm, True, False};
16 use util::common::time;
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();
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() {
33 session::CrateTypeExecutable | session::CrateTypeStaticlib => {}
35 sess.fatal("lto can only be run for executables and \
36 static library outputs");
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 {
50 sess.fatal(format!("could not find rlib for: `{}`", name));
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,
66 bc.len() as libc::size_t) {
67 link::llvm_err(sess, format!("failed to load bc of `{}`", name));
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();
77 llvm::LLVMRustRunRestrictionPass(llmod, ptr as **libc::c_char,
78 arr.len() as libc::size_t);
81 if sess.no_landing_pads() {
83 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
87 // Now we have one massive module inside of llmod. Time to run the
88 // LTO-specific optimization passes that LLVM provides.
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");
94 let pm = llvm::LLVMCreatePassManager();
95 llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
96 "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
98 let builder = llvm::LLVMPassManagerBuilderCreate();
99 llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
100 /* Internalize = */ False,
101 /* RunInliner = */ True);
102 llvm::LLVMPassManagerBuilderDispose(builder);
104 "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
106 time(sess.time_passes(), "LTO pases", (), |()|
107 llvm::LLVMRunPassManager(pm, llmod));
109 llvm::LLVMDisposePassManager(pm);