diff --git a/src/base.rs b/src/base.rs index eed66a28806..a3865b34524 100644 --- a/src/base.rs +++ b/src/base.rs @@ -2,61 +2,7 @@ use rustc::ty::adjustment::PointerCast; use crate::prelude::*; -struct PrintOnPanic String>(F); -impl String> Drop for PrintOnPanic { - fn drop(&mut self) { - if ::std::thread::panicking() { - println!("{}", (self.0)()); - } - } -} - -pub fn trans_mono_item<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( - cx: &mut crate::CodegenCx<'a, 'clif, 'tcx, B>, - mono_item: MonoItem<'tcx>, - linkage: Linkage, -) { - let tcx = cx.tcx; - match mono_item { - MonoItem::Fn(inst) => { - let _inst_guard = - PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).as_str())); - debug_assert!(!inst.substs.needs_infer()); - let _mir_guard = PrintOnPanic(|| { - match inst.def { - InstanceDef::Item(_) - | InstanceDef::DropGlue(_, _) - | InstanceDef::Virtual(_, _) - if inst.def_id().krate == LOCAL_CRATE => - { - let mut mir = ::std::io::Cursor::new(Vec::new()); - crate::rustc_mir::util::write_mir_pretty( - tcx, - Some(inst.def_id()), - &mut mir, - ) - .unwrap(); - String::from_utf8(mir.into_inner()).unwrap() - } - _ => { - // FIXME fix write_mir_pretty for these instances - format!("{:#?}", tcx.instance_mir(inst.def)) - } - } - }); - - trans_fn(cx, inst, linkage); - } - MonoItem::Static(def_id) => { - crate::constant::codegen_static(&mut cx.ccx, def_id); - } - MonoItem::GlobalAsm(node_id) => tcx - .sess - .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)), - } -} - -fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( +pub fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( cx: &mut crate::CodegenCx<'a, 'clif, 'tcx, B>, instance: Instance<'tcx>, linkage: Linkage, diff --git a/src/driver.rs b/src/driver.rs new file mode 100644 index 00000000000..6ec558705bc --- /dev/null +++ b/src/driver.rs @@ -0,0 +1,273 @@ +use std::any::Any; +use std::ffi::CString; +use std::fs::File; +use std::os::raw::{c_char, c_int}; + +use rustc::middle::cstore::EncodedMetadata; +use rustc::mir::mono::{Linkage as RLinkage, Visibility}; +use rustc::session::config::{DebugInfo, OutputType}; +use rustc_codegen_ssa::back::linker::LinkerInfo; +use rustc_codegen_ssa::CrateInfo; +use rustc_mir::monomorphize::partitioning::CodegenUnitExt; + +use cranelift_faerie::*; + +use crate::prelude::*; + +pub fn codegen_crate<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + metadata: EncodedMetadata, + _need_metadata_module: bool, +) -> Box { + env_logger::init(); + if !tcx.sess.crate_types.get().contains(&CrateType::Executable) + && std::env::var("SHOULD_RUN").is_ok() + { + tcx.sess + .err("Can't JIT run non executable (SHOULD_RUN env var is set)"); + } + + tcx.sess.abort_if_errors(); + + let mut log = if cfg!(debug_assertions) { + Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap()) + } else { + None + }; + + if std::env::var("SHOULD_RUN").is_ok() { + let mut jit_module: Module = + Module::new(SimpleJITBuilder::new(cranelift_module::default_libcall_names())); + assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); + + let sig = Signature { + params: vec![ + AbiParam::new(jit_module.target_config().pointer_type()), + AbiParam::new(jit_module.target_config().pointer_type()), + ], + returns: vec![AbiParam::new( + jit_module.target_config().pointer_type(), /*isize*/ + )], + call_conv: CallConv::SystemV, + }; + let main_func_id = jit_module + .declare_function("main", Linkage::Import, &sig) + .unwrap(); + + codegen_cgus(tcx, &mut jit_module, &mut None, &mut log); + crate::allocator::codegen(tcx.sess, &mut jit_module); + jit_module.finalize_definitions(); + + tcx.sess.abort_if_errors(); + + let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); + + println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set"); + + let f: extern "C" fn(c_int, *const *const c_char) -> c_int = + unsafe { ::std::mem::transmute(finalized_main) }; + + let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new()); + let args = args + .split(" ") + .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())) + .map(|arg| CString::new(arg).unwrap()) + .collect::>(); + let argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); + // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end + + let ret = f(args.len() as c_int, argv.as_ptr()); + + jit_module.finish(); + std::process::exit(ret); + } else { + let new_module = |name: String| { + let module: Module = Module::new( + FaerieBuilder::new( + crate::build_isa(tcx.sess), + name + ".o", + FaerieTrapCollection::Disabled, + cranelift_module::default_libcall_names(), + ) + .unwrap(), + ); + assert_eq!(pointer_ty(tcx), module.target_config().pointer_type()); + module + }; + + let emit_module = |name: &str, + kind: ModuleKind, + mut module: Module, + debug: Option| { + module.finalize_definitions(); + let mut artifact = module.finish().artifact; + + if let Some(mut debug) = debug { + debug.emit(&mut artifact); + } + + let tmp_file = tcx + .output_filenames(LOCAL_CRATE) + .temp_path(OutputType::Object, Some(name)); + let obj = artifact.emit().unwrap(); + std::fs::write(&tmp_file, obj).unwrap(); + CompiledModule { + name: name.to_string(), + kind, + object: Some(tmp_file), + bytecode: None, + bytecode_compressed: None, + } + }; + + let mut faerie_module = new_module("some_file".to_string()); + + let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None + // macOS debuginfo doesn't work yet (see #303) + && !tcx.sess.target.target.options.is_like_osx + { + let debug = DebugContext::new( + tcx, + faerie_module.target_config().pointer_type().bytes() as u8, + ); + Some(debug) + } else { + None + }; + + codegen_cgus(tcx, &mut faerie_module, &mut debug, &mut log); + + tcx.sess.abort_if_errors(); + + let mut allocator_module = new_module("allocator_shim.o".to_string()); + let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module); + + rustc_incremental::assert_dep_graph(tcx); + rustc_incremental::save_dep_graph(tcx); + rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE)); + + Box::new(CodegenResults { + crate_name: tcx.crate_name(LOCAL_CRATE), + modules: vec![emit_module( + "dummy_name", + ModuleKind::Regular, + faerie_module, + debug, + )], + allocator_module: if created_alloc_shim { + Some(emit_module( + "allocator_shim", + ModuleKind::Allocator, + allocator_module, + None, + )) + } else { + None + }, + metadata_module: Some(CompiledModule { + name: "dummy_metadata".to_string(), + kind: ModuleKind::Metadata, + object: None, + bytecode: None, + bytecode_compressed: None, + }), + crate_hash: tcx.crate_hash(LOCAL_CRATE), + metadata, + windows_subsystem: None, // Windows is not yet supported + linker_info: LinkerInfo::new(tcx), + crate_info: CrateInfo::new(tcx), + }) + } +} + +fn codegen_cgus<'a, 'tcx: 'a>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + module: &mut Module, + debug: &mut Option>, + log: &mut Option, +) { + let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + let mono_items = cgus + .iter() + .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter()) + .flatten() + .collect::>(); + + codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items); + + crate::main_shim::maybe_create_entry_wrapper(tcx, module); +} + +fn codegen_mono_items<'a, 'tcx: 'a>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + module: &mut Module, + debug_context: Option<&mut DebugContext<'tcx>>, + log: &mut Option, + mono_items: FxHashMap, (RLinkage, Visibility)>, +) { + let mut cx = CodegenCx::new(tcx, module, debug_context); + time("codegen mono items", move || { + for (mono_item, (linkage, visibility)) in mono_items { + crate::unimpl::try_unimpl(tcx, log, || { + let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + trans_mono_item(&mut cx, mono_item, linkage); + }); + } + + cx.finalize(); + }); +} + +fn trans_mono_item<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( + cx: &mut crate::CodegenCx<'a, 'clif, 'tcx, B>, + mono_item: MonoItem<'tcx>, + linkage: Linkage, +) { + let tcx = cx.tcx; + match mono_item { + MonoItem::Fn(inst) => { + let _inst_guard = + PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).as_str())); + debug_assert!(!inst.substs.needs_infer()); + let _mir_guard = PrintOnPanic(|| { + match inst.def { + InstanceDef::Item(_) + | InstanceDef::DropGlue(_, _) + | InstanceDef::Virtual(_, _) + if inst.def_id().krate == LOCAL_CRATE => + { + let mut mir = ::std::io::Cursor::new(Vec::new()); + crate::rustc_mir::util::write_mir_pretty( + tcx, + Some(inst.def_id()), + &mut mir, + ) + .unwrap(); + String::from_utf8(mir.into_inner()).unwrap() + } + _ => { + // FIXME fix write_mir_pretty for these instances + format!("{:#?}", tcx.instance_mir(inst.def)) + } + } + }); + + crate::base::trans_fn(cx, inst, linkage); + } + MonoItem::Static(def_id) => { + crate::constant::codegen_static(&mut cx.ccx, def_id); + } + MonoItem::GlobalAsm(node_id) => tcx + .sess + .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)), + } +} + +fn time(name: &str, f: impl FnOnce() -> R) -> R { + println!("[{}] start", name); + let before = std::time::Instant::now(); + let res = f(); + let after = std::time::Instant::now(); + println!("[{}] end time: {:?}", name, after - before); + res +} diff --git a/src/lib.rs b/src/lib.rs index 95eb75c22c8..bfadb90ae73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,24 +14,16 @@ extern crate rustc_target; extern crate syntax; use std::any::Any; -use std::ffi::CString; -use std::fs::File; -use std::os::raw::{c_char, c_int}; use std::sync::mpsc; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; -use rustc::mir::mono::{Linkage as RLinkage, Visibility}; -use rustc::session::config::{DebugInfo, OutputFilenames, OutputType}; +use rustc::session::config::OutputFilenames; use rustc::ty::query::Providers; use rustc::util::common::ErrorReported; -use rustc_codegen_ssa::back::linker::LinkerInfo; -use rustc_codegen_ssa::CrateInfo; use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_mir::monomorphize::partitioning::CodegenUnitExt; use cranelift::codegen::settings; -use cranelift_faerie::*; use crate::constant::ConstantCx; use crate::prelude::*; @@ -44,6 +36,7 @@ mod base; mod common; mod constant; mod debuginfo; +mod driver; mod intrinsics; mod linkage; mod main_shim; @@ -103,6 +96,15 @@ mod prelude { pub use crate::trap::*; pub use crate::unimpl::{unimpl, with_unimpl_span}; pub use crate::{Caches, CodegenCx}; + + pub struct PrintOnPanic String>(pub F); + impl String> Drop for PrintOnPanic { + fn drop(&mut self) { + if ::std::thread::panicking() { + println!("{}", (self.0)()); + } + } + } } pub struct Caches<'tcx> { @@ -194,168 +196,10 @@ impl CodegenBackend for CraneliftCodegenBackend { &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: EncodedMetadata, - _need_metadata_module: bool, + need_metadata_module: bool, _rx: mpsc::Receiver>, ) -> Box { - env_logger::init(); - if !tcx.sess.crate_types.get().contains(&CrateType::Executable) - && std::env::var("SHOULD_RUN").is_ok() - { - tcx.sess - .err("Can't JIT run non executable (SHOULD_RUN env var is set)"); - } - - tcx.sess.abort_if_errors(); - - let mut log = if cfg!(debug_assertions) { - Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap()) - } else { - None - }; - - if std::env::var("SHOULD_RUN").is_ok() { - let mut jit_module: Module = - Module::new(SimpleJITBuilder::new(cranelift_module::default_libcall_names())); - assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); - - let sig = Signature { - params: vec![ - AbiParam::new(jit_module.target_config().pointer_type()), - AbiParam::new(jit_module.target_config().pointer_type()), - ], - returns: vec![AbiParam::new( - jit_module.target_config().pointer_type(), /*isize*/ - )], - call_conv: CallConv::SystemV, - }; - let main_func_id = jit_module - .declare_function("main", Linkage::Import, &sig) - .unwrap(); - - codegen_cgus(tcx, &mut jit_module, &mut None, &mut log); - crate::allocator::codegen(tcx.sess, &mut jit_module); - jit_module.finalize_definitions(); - - tcx.sess.abort_if_errors(); - - let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); - - println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set"); - - let f: extern "C" fn(c_int, *const *const c_char) -> c_int = - unsafe { ::std::mem::transmute(finalized_main) }; - - let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new()); - let args = args - .split(" ") - .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())) - .map(|arg| CString::new(arg).unwrap()) - .collect::>(); - let argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); - // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end - - let ret = f(args.len() as c_int, argv.as_ptr()); - - jit_module.finish(); - std::process::exit(ret); - } else { - let new_module = |name: String| { - let module: Module = Module::new( - FaerieBuilder::new( - build_isa(tcx.sess), - name + ".o", - FaerieTrapCollection::Disabled, - cranelift_module::default_libcall_names(), - ) - .unwrap(), - ); - assert_eq!(pointer_ty(tcx), module.target_config().pointer_type()); - module - }; - - let emit_module = |name: &str, - kind: ModuleKind, - mut module: Module, - debug: Option| { - module.finalize_definitions(); - let mut artifact = module.finish().artifact; - - if let Some(mut debug) = debug { - debug.emit(&mut artifact); - } - - let tmp_file = tcx - .output_filenames(LOCAL_CRATE) - .temp_path(OutputType::Object, Some(name)); - let obj = artifact.emit().unwrap(); - std::fs::write(&tmp_file, obj).unwrap(); - CompiledModule { - name: name.to_string(), - kind, - object: Some(tmp_file), - bytecode: None, - bytecode_compressed: None, - } - }; - - let mut faerie_module = new_module("some_file".to_string()); - - let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None - // macOS debuginfo doesn't work yet (see #303) - && !tcx.sess.target.target.options.is_like_osx - { - let debug = DebugContext::new( - tcx, - faerie_module.target_config().pointer_type().bytes() as u8, - ); - Some(debug) - } else { - None - }; - - codegen_cgus(tcx, &mut faerie_module, &mut debug, &mut log); - - tcx.sess.abort_if_errors(); - - let mut allocator_module = new_module("allocator_shim.o".to_string()); - let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module); - - rustc_incremental::assert_dep_graph(tcx); - rustc_incremental::save_dep_graph(tcx); - rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE)); - - return Box::new(CodegenResults { - crate_name: tcx.crate_name(LOCAL_CRATE), - modules: vec![emit_module( - "dummy_name", - ModuleKind::Regular, - faerie_module, - debug, - )], - allocator_module: if created_alloc_shim { - Some(emit_module( - "allocator_shim", - ModuleKind::Allocator, - allocator_module, - None, - )) - } else { - None - }, - metadata_module: Some(CompiledModule { - name: "dummy_metadata".to_string(), - kind: ModuleKind::Metadata, - object: None, - bytecode: None, - bytecode_compressed: None, - }), - crate_hash: tcx.crate_hash(LOCAL_CRATE), - metadata, - windows_subsystem: None, // Windows is not yet supported - linker_info: LinkerInfo::new(tcx), - crate_info: CrateInfo::new(tcx), - }); - } + driver::codegen_crate(tcx, metadata, need_metadata_module) } fn join_codegen_and_link( @@ -385,8 +229,6 @@ impl CodegenBackend for CraneliftCodegenBackend { } fn build_isa(sess: &Session) -> Box { - use rustc::session::config::OptLevel; - let mut flags_builder = settings::builder(); flags_builder.enable("is_pic").unwrap(); flags_builder.set("probestack_enabled", "false").unwrap(); // ___cranelift_probestack is not provided @@ -397,7 +239,9 @@ fn build_isa(sess: &Session) -> Box { }).unwrap(); // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed - /*match sess.opts.optimize { + /* + use rustc::session::config::OptLevel; + match sess.opts.optimize { OptLevel::No => { flags_builder.set("opt_level", "fastest").unwrap(); } @@ -416,53 +260,6 @@ fn build_isa(sess: &Session) -> Box { .finish(flags) } -fn codegen_cgus<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - module: &mut Module, - debug: &mut Option>, - log: &mut Option, -) { - let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); - let mono_items = cgus - .iter() - .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter()) - .flatten() - .collect::>(); - - codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items); - - crate::main_shim::maybe_create_entry_wrapper(tcx, module); -} - -fn codegen_mono_items<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - module: &mut Module, - debug_context: Option<&mut DebugContext<'tcx>>, - log: &mut Option, - mono_items: FxHashMap, (RLinkage, Visibility)>, -) { - let mut cx = CodegenCx::new(tcx, module, debug_context); - time("codegen mono items", move || { - for (mono_item, (linkage, visibility)) in mono_items { - unimpl::try_unimpl(tcx, log, || { - let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); - base::trans_mono_item(&mut cx, mono_item, linkage); - }); - } - - cx.finalize(); - }); -} - -fn time(name: &str, f: impl FnOnce() -> R) -> R { - println!("[{}] start", name); - let before = ::std::time::Instant::now(); - let res = f(); - let after = ::std::time::Instant::now(); - println!("[{}] end time: {:?}", name, after - before); - res -} - /// This is the entrypoint for a hot plugged rustc_codegen_cranelift #[no_mangle] pub fn __rustc_codegen_backend() -> Box {