(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, llmodModuleRef,
  22             tmTargetMachineRef, 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 cstrsVec<::std::c_str::CString> = reachable.iter().map(|s| s.to_c_str()).collect();
  76      let arrVec<*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  }