use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
use time_graph::{self, TimeGraph, Timeline};
-use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
+use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic, BasicBlock};
use llvm_util;
use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, // ModuleLlvm,
CachedModuleCodegen};
use syntax_pos::symbol::Symbol;
use type_::Type;
use context::{is_pie_binary, get_reloc_model};
-use common::{C_bytes_in_context, val_ty};
+use interfaces::{Backend, CommonWriteMethods};
+use common;
use jobserver::{Client, Acquired};
use rustc_demangle;
+use value::Value;
+use std::marker::PhantomData;
use std::any::Any;
use std::ffi::{CString, CStr};
use std::thread;
use libc::{c_uint, c_void, c_char, size_t};
-pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
+pub const RELOC_MODEL_ARGS : [(&str, llvm::RelocMode); 7] = [
("pic", llvm::RelocMode::PIC),
("static", llvm::RelocMode::Static),
("default", llvm::RelocMode::Default),
("large", llvm::CodeModel::Large),
];
-pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [
+pub const TLS_MODEL_ARGS : [(&str, llvm::ThreadLocalMode); 4] = [
("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
("initial-exec", llvm::ThreadLocalMode::InitialExec),
const PRE_THIN_LTO_BC_EXT: &str = "pre-thin-lto.bc";
-pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
+pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
match llvm::last_error() {
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
None => handler.fatal(&msg),
file_type: llvm::FileType) -> Result<(), FatalError> {
unsafe {
let output_c = path2cstr(output);
- let result = llvm::LLVMRustWriteOutputFile(
- target, pm, m, output_c.as_ptr(), file_type);
+ let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type);
if result.into_result().is_err() {
let msg = format!("could not write output to {}", output.display());
- Err(llvm_err(handler, msg))
+ Err(llvm_err(handler, &msg))
} else {
Ok(())
}
find_features: bool,
) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
- llvm_err(sess.diagnostic(), err).raise()
+ llvm_err(sess.diagnostic(), &err).raise()
})
}
/// Additional resources used by optimize_and_codegen (not module specific)
#[derive(Clone)]
-pub struct CodegenContext {
+pub struct CodegenContext<'ll> {
// Resources needed when running LTO
pub time_passes: bool,
pub lto: Lto,
time_graph: Option<TimeGraph>,
// The assembler command if no_integrated_as option is enabled, None otherwise
assembler_cmd: Option<Arc<AssemblerCommand>>,
+ // This field is used to give a lifetime parameter to the struct so that it can implement
+ // the Backend trait.
+ phantom: PhantomData<&'ll ()>
}
-impl CodegenContext {
+impl CodegenContext<'ll> {
pub fn create_diag_handler(&self) -> Handler {
Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
}
}
}
+impl<'ll> Backend for CodegenContext<'ll> {
+ type Value = &'ll Value;
+ type BasicBlock = &'ll BasicBlock;
+ type Type = &'ll Type;
+ type Context = &'ll llvm::Context;
+}
+
+impl CommonWriteMethods for CodegenContext<'ll> {
+ fn val_ty(&self, v: &'ll Value) -> &'ll Type {
+ common::val_ty(v)
+ }
+
+ fn c_bytes_in_context(&self, llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
+ common::c_bytes_in_context(llcx, bytes)
+ }
+
+ fn c_struct_in_context(
+ &self,
+ llcx: &'a llvm::Context,
+ elts: &[&'a Value],
+ packed: bool,
+ ) -> &'a Value {
+ common::c_struct_in_context(llcx, elts, packed)
+ }
+}
+
+
pub struct DiagnosticHandlers<'a> {
- data: *mut (&'a CodegenContext, &'a Handler),
+ data: *mut (&'a CodegenContext<'a>, &'a Handler),
llcx: &'a llvm::Context,
}
impl<'a> DiagnosticHandlers<'a> {
- pub fn new(cgcx: &'a CodegenContext,
+ pub fn new(cgcx: &'a CodegenContext<'a>,
handler: &'a Handler,
llcx: &'a llvm::Context) -> Self {
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext,
msg: &'b str,
cookie: c_uint) {
- cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string());
+ cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned());
}
unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic,
for pass in &config.passes {
if !addpass(pass) {
- diag_handler.warn(&format!("unknown pass `{}`, ignoring",
- pass));
+ diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass));
}
if pass == "name-anon-globals" {
have_name_anon_globals_pass = true;
for pass in &cgcx.plugin_passes {
if !addpass(pass) {
diag_handler.err(&format!("a plugin asked for LLVM pass \
- `{}` but LLVM does not \
- recognize it", pass));
+ `{}` but LLVM does not \
+ recognize it", pass));
}
if pass == "name-anon-globals" {
have_name_anon_globals_pass = true;
// As described above, this will probably cause an error in LLVM
if config.no_prepopulate_passes {
diag_handler.err("The current compilation is going to use thin LTO buffers \
- without running LLVM's NameAnonGlobals pass. \
- This will likely cause errors in LLVM. Consider adding \
- -C passes=name-anon-globals to the compiler command line.");
+ without running LLVM's NameAnonGlobals pass. \
+ This will likely cause errors in LLVM. Consider adding \
+ -C passes=name-anon-globals to the compiler command line.");
} else {
bug!("We are using thin LTO buffers without running the NameAnonGlobals pass. \
- This will likely cause errors in LLVM and should never happen.");
+ This will likely cause errors in LLVM and should never happen.");
}
}
}
// escape the closure itself, and the manager should only be
// used once.
unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine,
- llmod: &'ll llvm::Module,
- no_builtins: bool,
- f: F) -> R
+ llmod: &'ll llvm::Module,
+ no_builtins: bool,
+ f: F) -> R
where F: FnOnce(&'ll mut PassManager<'ll>) -> R,
{
let cpm = llvm::LLVMCreatePassManager();
};
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &path,
- llvm::FileType::AssemblyFile)
+ llvm::FileType::AssemblyFile)
})?;
timeline.record("asm");
}
if write_obj {
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
- llvm::FileType::ObjectFile)
+ llvm::FileType::ObjectFile)
})?;
timeline.record("obj");
} else if asm_to_obj {
llcx: &llvm::Context,
llmod: &llvm::Module,
bitcode: Option<&[u8]>) {
- let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[]));
+ let llconst = cgcx.c_bytes_in_context(llcx, bitcode.unwrap_or(&[]));
let llglobal = llvm::LLVMAddGlobal(
llmod,
- val_ty(llconst),
+ cgcx.val_ty(llconst),
"rustc.embedded.module\0".as_ptr() as *const _,
);
llvm::LLVMSetInitializer(llglobal, llconst);
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
- let llconst = C_bytes_in_context(llcx, &[]);
+ let llconst = cgcx.c_bytes_in_context(llcx, &[]);
let llglobal = llvm::LLVMAddGlobal(
llmod,
- val_ty(llconst),
+ cgcx.val_ty(llconst),
"rustc.embedded.cmdline\0".as_ptr() as *const _,
);
llvm::LLVMSetInitializer(llglobal, llconst);
}
pub fn start_async_codegen(tcx: TyCtxt,
- time_graph: Option<TimeGraph>,
- metadata: EncodedMetadata,
- coordinator_receive: Receiver<Box<dyn Any + Send>>,
- total_cgus: usize)
- -> OngoingCodegen {
+ time_graph: Option<TimeGraph>,
+ metadata: EncodedMetadata,
+ coordinator_receive: Receiver<Box<dyn Any + Send>>,
+ total_cgus: usize)
+ -> OngoingCodegen {
let sess = tcx.sess;
let crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_hash = tcx.crate_hash(LOCAL_CRATE);
}
if let Some((id, product)) =
- copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+ copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files)
+ {
work_products.insert(id, product);
}
}
module.name,
source_file,
obj_out.display());
- match link_or_copy(&source_file, &obj_out) {
- Ok(_) => { }
- Err(err) => {
- let diag_handler = cgcx.create_diag_handler();
- diag_handler.err(&format!("unable to copy {} to {}: {}",
- source_file.display(),
- obj_out.display(),
- err));
- }
+ if let Err(err) = link_or_copy(&source_file, &obj_out) {
+ let diag_handler = cgcx.create_diag_handler();
+ diag_handler.err(&format!("unable to copy {} to {}: {}",
+ source_file.display(),
+ obj_out.display(),
+ err));
}
}
let (name, mut cmd) = get_linker(sess, &linker, flavor);
cmd.args(&sess.target.target.options.asm_args);
- Some(Arc::new(AssemblerCommand {
- name,
- cmd,
- }))
+
+ Some(Arc::new(AssemblerCommand { name, cmd }))
} else {
None
};
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
debuginfo: tcx.sess.opts.debuginfo,
assembler_cmd,
+ phantom: PhantomData
};
// This is the "main loop" of parallel work happening for parallel codegen.
const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]);
-fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
+fn spawn_work(cgcx: CodegenContext<'static>, work: WorkItem) {
let depth = time_depth();
thread::spawn(move || {
handler.struct_err(&format!("linking with `{}` failed: {}",
pname.display(),
prog.status))
- .note(&format!("{:?}", &cmd))
- .note(str::from_utf8(¬e[..]).unwrap())
- .emit();
+ .note(&format!("{:?}", &cmd))
+ .note(str::from_utf8(¬e[..]).unwrap())
+ .emit();
handler.abort_if_errors();
}
},
}
pub(crate) fn submit_pre_codegened_module_to_llvm(&self,
- tcx: TyCtxt,
- module: ModuleCodegen) {
+ tcx: TyCtxt,
+ module: ModuleCodegen) {
self.wait_for_signal_to_codegen_item();
self.check_for_errors(tcx.sess);