about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-04-09 15:54:18 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-04-10 00:24:43 +0530
commit4e466e730b18645e73c2e4a841f6e675c82ceb22 (patch)
tree37467bb5a28494a2a7c37b6cd9a7bd0b8891d59c
parent2dffe789791f2be95683b47a34f7a4c7f1014047 (diff)
parent0cb937944664f7a52895c87f9007fcdface78a7e (diff)
downloadrust-4e466e730b18645e73c2e4a841f6e675c82ceb22.tar.gz
rust-4e466e730b18645e73c2e4a841f6e675c82ceb22.zip
Rollup merge of #24207 - kmcallister:llvm-plugin, r=brson
 r? @brson

I'm using this to integrate rustc with [american-fuzzy-lop](http://lcamtuf.coredump.cx/afl/). Building with afl instrumentation is no different from loading any other plugin library.

I'd like this PR to include a `run-make` test with a custom LLVM pass; however I'm not sure it's worth the trouble of building C++ code and linking LLVM from the test suite (are there existing tests that do this?)
-rw-r--r--src/librustc/plugin/registry.rs14
-rw-r--r--src/librustc/session/mod.rs2
-rw-r--r--src/librustc_driver/driver.rs4
-rw-r--r--src/librustc_trans/back/write.rs15
-rw-r--r--src/test/auxiliary/llvm_pass_plugin.rs28
-rw-r--r--src/test/run-pass-fulldeps/llvm-pass-plugin.rs17
6 files changed, 79 insertions, 1 deletions
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<LintId>>,
+
+    #[doc(hidden)]
+    pub llvm_passes: Vec<String>,
 }
 
 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<lint::LintStore>,
     pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
+    pub plugin_llvm_passes: RefCell<Vec<String>>,
     pub crate_types: RefCell<Vec<config::CrateType>>,
     pub crate_metadata: RefCell<Vec<String>>,
     pub features: RefCell<feature_gate::Features>,
@@ -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<String>,
     // 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() { }