diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index a73ed04ac0a..322b5d3a8cf 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -22,6 +22,7 @@ use syntax::ptr::P; use syntax::ast; use std::collections::HashMap; +use std::borrow::ToOwned; /// Structure used to register plugins. /// @@ -50,6 +51,9 @@ pub struct Registry<'a> { #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, + + #[doc(hidden)] + pub llvm_passes: Vec, } impl<'a> Registry<'a> { @@ -62,6 +66,7 @@ impl<'a> Registry<'a> { syntax_exts: vec!(), lint_passes: vec!(), lint_groups: HashMap::new(), + llvm_passes: vec!(), } } @@ -116,4 +121,13 @@ impl<'a> Registry<'a> { pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); } + + /// Register an LLVM pass. + /// + /// Registration with LLVM itself is handled through static C++ objects with + /// constructors. This method simply adds a name to the list of passes to + /// execute. + pub fn register_llvm_pass(&mut self, name: &str) { + self.llvm_passes.push(name.to_owned()); + } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 452840310aa..148f484b0ed 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -52,6 +52,7 @@ pub struct Session { pub working_dir: PathBuf, pub lint_store: RefCell, pub lints: RefCell>>, + pub plugin_llvm_passes: RefCell>, pub crate_types: RefCell>, pub crate_metadata: RefCell>, pub features: RefCell, @@ -391,6 +392,7 @@ pub fn build_session_(sopts: config::Options, working_dir: env::current_dir().unwrap(), lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), + plugin_llvm_passes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), crate_metadata: RefCell::new(Vec::new()), features: RefCell::new(feature_gate::Features::new()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index fe05b489229..e310798b20a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -438,7 +438,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, } }); - let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry; + let Registry { syntax_exts, lint_passes, lint_groups, llvm_passes, .. } = registry; { let mut ls = sess.lint_store.borrow_mut(); @@ -449,6 +449,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, for (name, to) in lint_groups { ls.register_group(Some(sess), true, name, to); } + + *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; } // Lint plugins are registered; now we can process command line flags. diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index cc588a365f6..de21d626514 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -319,6 +319,8 @@ struct CodegenContext<'a> { lto_ctxt: Option<(&'a Session, &'a [String])>, // Handler to use for diagnostics produced during codegen. handler: &'a Handler, + // LLVM passes added by plugins. + plugin_passes: Vec, // LLVM optimizations for which we want to print remarks. remark: Passes, } @@ -328,6 +330,7 @@ impl<'a> CodegenContext<'a> { CodegenContext { lto_ctxt: Some((sess, reachable)), handler: sess.diagnostic().handler(), + plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), } } @@ -461,6 +464,16 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + for pass in &cgcx.plugin_passes { + let pass = CString::new(pass.clone()).unwrap(); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \ + does not recognize it", pass)); + } + } + + cgcx.handler.abort_if_errors(); + // Finally, run the actual optimization passes time(config.time_passes, "llvm function passes", (), |()| llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); @@ -907,6 +920,7 @@ fn run_work_multithreaded(sess: &Session, for i in 0..num_workers { let work_items_arc = work_items_arc.clone(); let diag_emitter = diag_emitter.clone(); + let plugin_passes = sess.plugin_llvm_passes.borrow().clone(); let remark = sess.opts.cg.remark.clone(); let (tx, rx) = channel(); @@ -921,6 +935,7 @@ fn run_work_multithreaded(sess: &Session, let cgcx = CodegenContext { lto_ctxt: None, handler: &diag_handler, + plugin_passes: plugin_passes, remark: remark, }; diff --git a/src/test/auxiliary/llvm_pass_plugin.rs b/src/test/auxiliary/llvm_pass_plugin.rs new file mode 100644 index 00000000000..d61f47fd7ef --- /dev/null +++ b/src/test/auxiliary/llvm_pass_plugin.rs @@ -0,0 +1,28 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host + +#![feature(plugin_registrar)] +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + // This pass is built in to LLVM. + // + // Normally, we would name a pass that was registered through + // C++ static object constructors in the same .so file as the + // plugin registrar. + reg.register_llvm_pass("inline"); +} diff --git a/src/test/run-pass-fulldeps/llvm-pass-plugin.rs b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs new file mode 100644 index 00000000000..5dfef636f9f --- /dev/null +++ b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:llvm_pass_plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![plugin(llvm_pass_plugin)] + +pub fn main() { }