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?)
This commit is contained in:
commit
4e466e730b
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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()),
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
28
src/test/auxiliary/llvm_pass_plugin.rs
Normal file
28
src/test/auxiliary/llvm_pass_plugin.rs
Normal file
@ -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");
|
||||
}
|
17
src/test/run-pass-fulldeps/llvm-pass-plugin.rs
Normal file
17
src/test/run-pass-fulldeps/llvm-pass-plugin.rs
Normal file
@ -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() { }
|
Loading…
Reference in New Issue
Block a user