use llvm::{ModuleRef, TargetMachineRef, True, False};
use rustc::metadata::cstore;
use rustc::util::common::time;
+use back::write::{ModuleConfig, with_llvm_pmb};
use libc;
use flate;
use std::ffi::CString;
pub fn run(sess: &session::Session, llmod: ModuleRef,
- tm: TargetMachineRef, reachable: &[String]) {
+ tm: TargetMachineRef, reachable: &[String],
+ config: &ModuleConfig) {
if sess.opts.cg.prefer_dynamic {
sess.err("cannot prefer dynamic linking when performing LTO");
sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
- let opt = match sess.opts.optimize {
- config::No => 0,
- config::Less => 1,
- config::Default => 2,
- config::Aggressive => 3,
- };
-
- let builder = llvm::LLVMPassManagerBuilderCreate();
- llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
- llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
- /* Internalize = */ False,
- /* RunInliner = */ True);
- llvm::LLVMPassManagerBuilderDispose(builder);
+ with_llvm_pmb(llmod, config, &mut |b| {
+ llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
+ /* Internalize = */ False,
+ /* RunInliner = */ True);
+ });
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
/// Module-specific configuration for `optimize_and_codegen`.
#[derive(Clone)]
-struct ModuleConfig {
+pub struct ModuleConfig {
/// LLVM TargetMachine to use for codegen.
tm: TargetMachineRef,
/// Names of additional optimization passes to run.
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
- match config.opt_level {
- Some(opt_level) => {
- // Create the two optimizing pass managers. These mirror what clang
- // does, and are by populated by LLVM's default PassManagerBuilder.
- // Each manager has a different set of passes, but they also share
- // some common passes.
- let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
- let mpm = llvm::LLVMCreatePassManager();
-
- // If we're verifying or linting, add them to the function pass
- // manager.
- let addpass = |pass: &str| {
- let pass = CString::new(pass).unwrap();
- llvm::LLVMRustAddPass(fpm, pass.as_ptr())
- };
+ if config.opt_level.is_some() {
+ // Create the two optimizing pass managers. These mirror what clang
+ // does, and are by populated by LLVM's default PassManagerBuilder.
+ // Each manager has a different set of passes, but they also share
+ // some common passes.
+ let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
+ let mpm = llvm::LLVMCreatePassManager();
+
+ // If we're verifying or linting, add them to the function pass
+ // manager.
+ let addpass = |pass: &str| {
+ let pass = CString::new(pass).unwrap();
+ llvm::LLVMRustAddPass(fpm, pass.as_ptr())
+ };
- if !config.no_verify { assert!(addpass("verify")); }
- if !config.no_prepopulate_passes {
- llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
- llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
- populate_llvm_passes(fpm, mpm, llmod, opt_level, &config);
- }
+ if !config.no_verify { assert!(addpass("verify")); }
+ if !config.no_prepopulate_passes {
+ llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+ llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+ with_llvm_pmb(llmod, &config, &mut |b| {
+ llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
+ llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
+ })
+ }
- for pass in &config.passes {
- if !addpass(pass) {
- cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
- pass));
- }
+ for pass in &config.passes {
+ if !addpass(pass) {
+ cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
+ pass));
}
+ }
- for pass in &cgcx.plugin_passes {
- if !addpass(pass) {
- cgcx.handler.err(&format!("a plugin asked for LLVM pass \
- `{}` but LLVM does not \
- recognize it", pass));
- }
+ for pass in &cgcx.plugin_passes {
+ if !addpass(pass) {
+ cgcx.handler.err(&format!("a plugin asked for LLVM pass \
+ `{}` but LLVM does not \
+ recognize it", pass));
}
+ }
- cgcx.handler.abort_if_errors();
+ cgcx.handler.abort_if_errors();
- // Finally, run the actual optimization passes
- time(config.time_passes, "llvm function passes", (), |()|
- llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
- time(config.time_passes, "llvm module passes", (), |()|
- llvm::LLVMRunPassManager(mpm, llmod));
+ // Finally, run the actual optimization passes
+ time(config.time_passes, "llvm function passes", (), |()|
+ llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
+ time(config.time_passes, "llvm module passes", (), |()|
+ llvm::LLVMRunPassManager(mpm, llmod));
- // Deallocate managers that we're now done with
- llvm::LLVMDisposePassManager(fpm);
- llvm::LLVMDisposePassManager(mpm);
+ // Deallocate managers that we're now done with
+ llvm::LLVMDisposePassManager(fpm);
+ llvm::LLVMDisposePassManager(mpm);
- match cgcx.lto_ctxt {
- Some((sess, reachable)) if sess.lto() => {
- time(sess.time_passes(), "all lto passes", (), |()|
- lto::run(sess, llmod, tm, reachable));
+ match cgcx.lto_ctxt {
+ Some((sess, reachable)) if sess.lto() => {
+ time(sess.time_passes(), "all lto passes", (), |()|
+ lto::run(sess, llmod, tm, reachable, &config));
- if config.emit_lto_bc {
- let name = format!("{}.lto.bc", name_extra);
- let out = output_names.with_extension(&name);
- let out = path2cstr(&out);
- llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
- }
- },
- _ => {},
- }
- },
- None => {},
+ if config.emit_lto_bc {
+ let name = format!("{}.lto.bc", name_extra);
+ let out = output_names.with_extension(&name);
+ let out = path2cstr(&out);
+ llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
+ }
+ },
+ _ => {},
+ }
}
// A codegen-specific pass manager is used to generate object
llvm_args.as_ptr());
}
-unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
- mpm: llvm::PassManagerRef,
- llmod: ModuleRef,
- opt: llvm::CodeGenOptLevel,
- config: &ModuleConfig) {
+pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
+ config: &ModuleConfig,
+ f: &mut FnMut(llvm::PassManagerBuilderRef)) {
// Create the PassManagerBuilder for LLVM. We configure it with
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
+ let opt = config.opt_level.unwrap_or(llvm::CodeGenLevelNone);
llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
config.merge_functions,
}
}
- // Use the builder to populate the function/module pass managers.
- llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
- llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
+ f(builder);
llvm::LLVMPassManagerBuilderDispose(builder);
}