about summary refs log tree commit diff
path: root/compiler/rustc_codegen_cranelift/src/driver
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2020-10-26 09:53:27 +0100
committerbjorn3 <bjorn3@users.noreply.github.com>2020-10-26 09:53:27 +0100
commitac4f7deb2f3558d2d923fa6ddcbb7210db9c2d52 (patch)
treeca7dcb9c908285e2af6eb0d8807d3e81dc9ba2ee /compiler/rustc_codegen_cranelift/src/driver
parentcf798c1ec65a5ec3491846777f9003fabb881b4a (diff)
parent793d26047f994e23415f8f6bb5686ff25d3dda92 (diff)
downloadrust-ac4f7deb2f3558d2d923fa6ddcbb7210db9c2d52.tar.gz
rust-ac4f7deb2f3558d2d923fa6ddcbb7210db9c2d52.zip
Add 'compiler/rustc_codegen_cranelift/' from commit '793d26047f994e23415f8f6bb5686ff25d3dda92'
git-subtree-dir: compiler/rustc_codegen_cranelift
git-subtree-mainline: cf798c1ec65a5ec3491846777f9003fabb881b4a
git-subtree-split: 793d26047f994e23415f8f6bb5686ff25d3dda92
Diffstat (limited to 'compiler/rustc_codegen_cranelift/src/driver')
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs450
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs169
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/mod.rs120
3 files changed, 739 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
new file mode 100644
index 00000000000..ff0b994c9a9
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -0,0 +1,450 @@
+//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
+//! standalone executable.
+
+use std::path::PathBuf;
+
+use rustc_codegen_ssa::back::linker::LinkerInfo;
+use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::mir::mono::CodegenUnit;
+use rustc_session::cgu_reuse_tracker::CguReuse;
+use rustc_session::config::{DebugInfo, OutputType};
+
+use cranelift_object::{ObjectModule, ObjectProduct};
+
+use crate::prelude::*;
+
+use crate::backend::AddConstructor;
+
+fn new_module(tcx: TyCtxt<'_>, name: String) -> ObjectModule {
+    let module = crate::backend::make_module(tcx.sess, name);
+    assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
+    module
+}
+
+struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
+
+impl<HCX> HashStable<HCX> for ModuleCodegenResult {
+    fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
+        // do nothing
+    }
+}
+
+fn emit_module(
+    tcx: TyCtxt<'_>,
+    name: String,
+    kind: ModuleKind,
+    module: ObjectModule,
+    debug: Option<DebugContext<'_>>,
+    unwind_context: UnwindContext<'_>,
+    map_product: impl FnOnce(ObjectProduct) -> ObjectProduct,
+) -> ModuleCodegenResult {
+    let mut product = module.finish();
+
+    if let Some(mut debug) = debug {
+        debug.emit(&mut product);
+    }
+
+    unwind_context.emit(&mut product);
+
+    let product = map_product(product);
+
+    let tmp_file = tcx
+        .output_filenames(LOCAL_CRATE)
+        .temp_path(OutputType::Object, Some(&name));
+    let obj = product.object.write().unwrap();
+    if let Err(err) = std::fs::write(&tmp_file, obj) {
+        tcx.sess
+            .fatal(&format!("error writing object file: {}", err));
+    }
+
+    let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() {
+        None
+    } else {
+        rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
+            tcx.sess,
+            &name,
+            &Some(tmp_file.clone()),
+        )
+    };
+
+    ModuleCodegenResult(
+        CompiledModule {
+            name,
+            kind,
+            object: Some(tmp_file),
+            bytecode: None,
+        },
+        work_product,
+    )
+}
+
+fn reuse_workproduct_for_cgu(
+    tcx: TyCtxt<'_>,
+    cgu: &CodegenUnit<'_>,
+    work_products: &mut FxHashMap<WorkProductId, WorkProduct>,
+) -> CompiledModule {
+    let incr_comp_session_dir = tcx.sess.incr_comp_session_dir();
+    let mut object = None;
+    let work_product = cgu.work_product(tcx);
+    if let Some(saved_file) = &work_product.saved_file {
+        let obj_out = tcx
+            .output_filenames(LOCAL_CRATE)
+            .temp_path(OutputType::Object, Some(&cgu.name().as_str()));
+        object = Some(obj_out.clone());
+        let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
+        if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
+            tcx.sess.err(&format!(
+                "unable to copy {} to {}: {}",
+                source_file.display(),
+                obj_out.display(),
+                err
+            ));
+        }
+    }
+
+    work_products.insert(cgu.work_product_id(), work_product);
+
+    CompiledModule {
+        name: cgu.name().to_string(),
+        kind: ModuleKind::Regular,
+        object,
+        bytecode: None,
+    }
+}
+
+fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegenResult {
+    let cgu = tcx.codegen_unit(cgu_name);
+    let mono_items = cgu.items_in_deterministic_order(tcx);
+
+    let mut module = new_module(tcx, cgu_name.as_str().to_string());
+
+    // Initialize the global atomic mutex using a constructor for proc-macros.
+    // FIXME implement atomic instructions in Cranelift.
+    let mut init_atomics_mutex_from_constructor = None;
+    if tcx
+        .sess
+        .crate_types()
+        .contains(&rustc_session::config::CrateType::ProcMacro)
+    {
+        if mono_items.iter().any(|(mono_item, _)| match mono_item {
+            rustc_middle::mir::mono::MonoItem::Static(def_id) => tcx
+                .symbol_name(Instance::mono(tcx, *def_id))
+                .name
+                .contains("__rustc_proc_macro_decls_"),
+            _ => false,
+        }) {
+            init_atomics_mutex_from_constructor =
+                Some(crate::atomic_shim::init_global_lock_constructor(
+                    &mut module,
+                    &format!("{}_init_atomics_mutex", cgu_name.as_str()),
+                ));
+        }
+    }
+
+    let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None);
+    super::codegen_mono_items(&mut cx, mono_items);
+    let (mut module, global_asm, debug, mut unwind_context) =
+        tcx.sess.time("finalize CodegenCx", || cx.finalize());
+    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context, false);
+
+    let codegen_result = emit_module(
+        tcx,
+        cgu.name().as_str().to_string(),
+        ModuleKind::Regular,
+        module,
+        debug,
+        unwind_context,
+        |mut product| {
+            if let Some(func_id) = init_atomics_mutex_from_constructor {
+                product.add_constructor(func_id);
+            }
+
+            product
+        },
+    );
+
+    codegen_global_asm(tcx, &cgu.name().as_str(), &global_asm);
+
+    codegen_result
+}
+
+pub(super) fn run_aot(
+    tcx: TyCtxt<'_>,
+    metadata: EncodedMetadata,
+    need_metadata_module: bool,
+) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
+    let mut work_products = FxHashMap::default();
+
+    let cgus = if tcx.sess.opts.output_types.should_codegen() {
+        tcx.collect_and_partition_mono_items(LOCAL_CRATE).1
+    } else {
+        // If only `--emit metadata` is used, we shouldn't perform any codegen.
+        // Also `tcx.collect_and_partition_mono_items` may panic in that case.
+        &[]
+    };
+
+    if tcx.dep_graph.is_fully_enabled() {
+        for cgu in &*cgus {
+            tcx.ensure().codegen_unit(cgu.name());
+        }
+    }
+
+    let modules = super::time(tcx, "codegen mono items", || {
+        cgus.iter()
+            .map(|cgu| {
+                let cgu_reuse = determine_cgu_reuse(tcx, cgu);
+                tcx.sess
+                    .cgu_reuse_tracker
+                    .set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
+
+                match cgu_reuse {
+                    _ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {}
+                    CguReuse::No => {}
+                    CguReuse::PreLto => {
+                        return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
+                    }
+                    CguReuse::PostLto => unreachable!(),
+                }
+
+                let dep_node = cgu.codegen_dep_node(tcx);
+                let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
+                    dep_node,
+                    tcx,
+                    cgu.name(),
+                    module_codegen,
+                    rustc_middle::dep_graph::hash_result,
+                );
+
+                if let Some((id, product)) = work_product {
+                    work_products.insert(id, product);
+                }
+
+                module
+            })
+            .collect::<Vec<_>>()
+    });
+
+    tcx.sess.abort_if_errors();
+
+    let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
+    let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa());
+    let created_alloc_shim =
+        crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
+
+    let allocator_module = if created_alloc_shim {
+        let ModuleCodegenResult(module, work_product) = emit_module(
+            tcx,
+            "allocator_shim".to_string(),
+            ModuleKind::Allocator,
+            allocator_module,
+            None,
+            allocator_unwind_context,
+            |product| product,
+        );
+        if let Some((id, product)) = work_product {
+            work_products.insert(id, product);
+        }
+        Some(module)
+    } else {
+        None
+    };
+
+    rustc_incremental::assert_dep_graph(tcx);
+    rustc_incremental::save_dep_graph(tcx);
+
+    let metadata_module = if need_metadata_module {
+        let _timer = tcx.prof.generic_activity("codegen crate metadata");
+        let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || {
+            use rustc_middle::mir::mono::CodegenUnitNameBuilder;
+
+            let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+            let metadata_cgu_name = cgu_name_builder
+                .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
+                .as_str()
+                .to_string();
+
+            let tmp_file = tcx
+                .output_filenames(LOCAL_CRATE)
+                .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
+
+            let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
+                crate::metadata::write_metadata(tcx, object);
+            });
+
+            if let Err(err) = std::fs::write(&tmp_file, obj) {
+                tcx.sess
+                    .fatal(&format!("error writing metadata object file: {}", err));
+            }
+
+            (metadata_cgu_name, tmp_file)
+        });
+
+        Some(CompiledModule {
+            name: metadata_cgu_name,
+            kind: ModuleKind::Metadata,
+            object: Some(tmp_file),
+            bytecode: None,
+        })
+    } else {
+        None
+    };
+
+    if tcx.sess.opts.output_types.should_codegen() {
+        rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+    }
+
+    Box::new((
+        CodegenResults {
+            crate_name: tcx.crate_name(LOCAL_CRATE),
+            modules,
+            allocator_module,
+            metadata_module,
+            metadata,
+            windows_subsystem: None, // Windows is not yet supported
+            linker_info: LinkerInfo::new(tcx),
+            crate_info: CrateInfo::new(tcx),
+        },
+        work_products,
+    ))
+}
+
+fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) {
+    use std::io::Write;
+    use std::process::{Command, Stdio};
+
+    if global_asm.is_empty() {
+        return;
+    }
+
+    if cfg!(not(feature = "inline_asm"))
+        || tcx.sess.target.options.is_like_osx
+        || tcx.sess.target.options.is_like_windows
+    {
+        if global_asm.contains("__rust_probestack") {
+            return;
+        }
+
+        // FIXME fix linker error on macOS
+        if cfg!(not(feature = "inline_asm")) {
+            tcx.sess.fatal(
+                "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift",
+            );
+        } else {
+            tcx.sess
+                .fatal("asm! and global_asm! are not yet supported on macOS and Windows");
+        }
+    }
+
+    let assembler = crate::toolchain::get_toolchain_binary(tcx.sess, "as");
+    let linker = crate::toolchain::get_toolchain_binary(tcx.sess, "ld");
+
+    // Remove all LLVM style comments
+    let global_asm = global_asm
+        .lines()
+        .map(|line| {
+            if let Some(index) = line.find("//") {
+                &line[0..index]
+            } else {
+                line
+            }
+        })
+        .collect::<Vec<_>>()
+        .join("\n");
+
+    let output_object_file = tcx
+        .output_filenames(LOCAL_CRATE)
+        .temp_path(OutputType::Object, Some(cgu_name));
+
+    // Assemble `global_asm`
+    let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
+    let mut child = Command::new(assembler)
+        .arg("-o")
+        .arg(&global_asm_object_file)
+        .stdin(Stdio::piped())
+        .spawn()
+        .expect("Failed to spawn `as`.");
+    child
+        .stdin
+        .take()
+        .unwrap()
+        .write_all(global_asm.as_bytes())
+        .unwrap();
+    let status = child.wait().expect("Failed to wait for `as`.");
+    if !status.success() {
+        tcx.sess
+            .fatal(&format!("Failed to assemble `{}`", global_asm));
+    }
+
+    // Link the global asm and main object file together
+    let main_object_file = add_file_stem_postfix(output_object_file.clone(), ".main");
+    std::fs::rename(&output_object_file, &main_object_file).unwrap();
+    let status = Command::new(linker)
+        .arg("-r") // Create a new object file
+        .arg("-o")
+        .arg(output_object_file)
+        .arg(&main_object_file)
+        .arg(&global_asm_object_file)
+        .status()
+        .unwrap();
+    if !status.success() {
+        tcx.sess.fatal(&format!(
+            "Failed to link `{}` and `{}` together",
+            main_object_file.display(),
+            global_asm_object_file.display(),
+        ));
+    }
+
+    std::fs::remove_file(global_asm_object_file).unwrap();
+    std::fs::remove_file(main_object_file).unwrap();
+}
+
+fn add_file_stem_postfix(mut path: PathBuf, postfix: &str) -> PathBuf {
+    let mut new_filename = path.file_stem().unwrap().to_owned();
+    new_filename.push(postfix);
+    if let Some(extension) = path.extension() {
+        new_filename.push(".");
+        new_filename.push(extension);
+    }
+    path.set_file_name(new_filename);
+    path
+}
+
+// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953
+fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
+    if !tcx.dep_graph.is_fully_enabled() {
+        return CguReuse::No;
+    }
+
+    let work_product_id = &cgu.work_product_id();
+    if tcx
+        .dep_graph
+        .previous_work_product(work_product_id)
+        .is_none()
+    {
+        // We don't have anything cached for this CGU. This can happen
+        // if the CGU did not exist in the previous session.
+        return CguReuse::No;
+    }
+
+    // Try to mark the CGU as green. If it we can do so, it means that nothing
+    // affecting the LLVM module has changed and we can re-use a cached version.
+    // If we compile with any kind of LTO, this means we can re-use the bitcode
+    // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
+    // know that later). If we are not doing LTO, there is only one optimized
+    // version of each module, so we re-use that.
+    let dep_node = cgu.codegen_dep_node(tcx);
+    assert!(
+        !tcx.dep_graph.dep_node_exists(&dep_node),
+        "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
+        cgu.name()
+    );
+
+    if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
+        CguReuse::PreLto
+    } else {
+        CguReuse::No
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
new file mode 100644
index 00000000000..b5bab3d9e1e
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -0,0 +1,169 @@
+//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
+//! files.
+
+use std::ffi::CString;
+use std::os::raw::{c_char, c_int};
+
+use rustc_codegen_ssa::CrateInfo;
+
+use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule};
+
+use crate::prelude::*;
+
+pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
+    if !tcx.sess.opts.output_types.should_codegen() {
+        tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
+    }
+
+    #[cfg(unix)]
+    unsafe {
+        // When not using our custom driver rustc will open us without the RTLD_GLOBAL flag, so
+        // __cg_clif_global_atomic_mutex will not be exported. We fix this by opening ourself again
+        // as global.
+        // FIXME remove once atomic_shim is gone
+
+        let mut dl_info: libc::Dl_info = std::mem::zeroed();
+        assert_ne!(
+            libc::dladdr(run_jit as *const libc::c_void, &mut dl_info),
+            0
+        );
+        assert_ne!(
+            libc::dlopen(dl_info.dli_fname, libc::RTLD_NOW | libc::RTLD_GLOBAL),
+            std::ptr::null_mut(),
+        );
+    }
+
+    let imported_symbols = load_imported_symbols_for_jit(tcx);
+
+    let mut jit_builder = SimpleJITBuilder::with_isa(
+        crate::build_isa(tcx.sess, false),
+        cranelift_module::default_libcall_names(),
+    );
+    jit_builder.symbols(imported_symbols);
+    let mut jit_module = SimpleJITModule::new(jit_builder);
+    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::triple_default(&crate::target_triple(tcx.sess)),
+    };
+    let main_func_id = jit_module
+        .declare_function("main", Linkage::Import, &sig)
+        .unwrap();
+
+    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::<FxHashMap<_, (_, _)>>()
+        .into_iter()
+        .collect::<Vec<(_, (_, _))>>();
+
+    let mut cx = crate::CodegenCx::new(tcx, jit_module, false);
+
+    let (mut jit_module, global_asm, _debug, mut unwind_context) =
+        super::time(tcx, "codegen mono items", || {
+            super::codegen_mono_items(&mut cx, mono_items);
+            tcx.sess.time("finalize CodegenCx", || cx.finalize())
+        });
+    if !global_asm.is_empty() {
+        tcx.sess.fatal("Global asm is not supported in JIT mode");
+    }
+    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true);
+    crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
+
+    tcx.sess.abort_if_errors();
+
+    let jit_product = jit_module.finish();
+
+    let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_product) };
+
+    let finalized_main: *const u8 = jit_product.lookup_func(main_func_id);
+
+    println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed");
+
+    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
+        unsafe { ::std::mem::transmute(finalized_main) };
+
+    let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
+    let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
+        .chain(args.split(" "))
+        .map(|arg| CString::new(arg).unwrap())
+        .collect::<Vec<_>>();
+    let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
+
+    // Push a null pointer as a terminating argument. This is required by POSIX and
+    // useful as some dynamic linkers use it as a marker to jump over.
+    argv.push(std::ptr::null());
+
+    let ret = f(args.len() as c_int, argv.as_ptr());
+
+    std::process::exit(ret);
+}
+
+fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
+    use rustc_middle::middle::dependency_format::Linkage;
+
+    let mut dylib_paths = Vec::new();
+
+    let crate_info = CrateInfo::new(tcx);
+    let formats = tcx.dependency_formats(LOCAL_CRATE);
+    let data = &formats
+        .iter()
+        .find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
+        .unwrap()
+        .1;
+    for &(cnum, _) in &crate_info.used_crates_dynamic {
+        let src = &crate_info.used_crate_source[&cnum];
+        match data[cnum.as_usize() - 1] {
+            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
+            Linkage::Static => {
+                let name = tcx.crate_name(cnum);
+                let mut err = tcx
+                    .sess
+                    .struct_err(&format!("Can't load static lib {}", name.as_str()));
+                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
+                err.emit();
+            }
+            Linkage::Dynamic => {
+                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
+            }
+        }
+    }
+
+    let mut imported_symbols = Vec::new();
+    for path in dylib_paths {
+        use object::Object;
+        let lib = libloading::Library::new(&path).unwrap();
+        let obj = std::fs::read(path).unwrap();
+        let obj = object::File::parse(&obj).unwrap();
+        imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| {
+            let name = symbol.name().unwrap().to_string();
+            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
+                return None;
+            }
+            let dlsym_name = if cfg!(target_os = "macos") {
+                // On macOS `dlsym` expects the name without leading `_`.
+                assert!(name.starts_with("_"), "{:?}", name);
+                &name[1..]
+            } else {
+                &name
+            };
+            let symbol: libloading::Symbol<'_, *const u8> =
+                unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap();
+            Some((name, *symbol))
+        }));
+        std::mem::forget(lib)
+    }
+
+    tcx.sess.abort_if_errors();
+
+    imported_symbols
+}
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
new file mode 100644
index 00000000000..2fb353ca162
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -0,0 +1,120 @@
+//! Drivers are responsible for calling [`codegen_mono_items`] and performing any further actions
+//! like JIT executing or writing object files.
+
+use std::any::Any;
+
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
+
+use crate::prelude::*;
+
+mod aot;
+#[cfg(feature = "jit")]
+mod jit;
+
+pub(crate) fn codegen_crate(
+    tcx: TyCtxt<'_>,
+    metadata: EncodedMetadata,
+    need_metadata_module: bool,
+    config: crate::BackendConfig,
+) -> Box<dyn Any> {
+    tcx.sess.abort_if_errors();
+
+    if config.use_jit {
+        let is_executable = tcx
+            .sess
+            .crate_types()
+            .contains(&rustc_session::config::CrateType::Executable);
+        if !is_executable {
+            tcx.sess.fatal("can't jit non-executable crate");
+        }
+
+        #[cfg(feature = "jit")]
+        let _: ! = jit::run_jit(tcx);
+
+        #[cfg(not(feature = "jit"))]
+        tcx.sess
+            .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+    }
+
+    aot::run_aot(tcx, metadata, need_metadata_module)
+}
+
+fn codegen_mono_items<'tcx>(
+    cx: &mut crate::CodegenCx<'tcx, impl Module>,
+    mono_items: Vec<(MonoItem<'tcx>, (RLinkage, Visibility))>,
+) {
+    cx.tcx.sess.time("predefine functions", || {
+        for &(mono_item, (linkage, visibility)) in &mono_items {
+            match mono_item {
+                MonoItem::Fn(instance) => {
+                    let (name, sig) = get_function_name_and_sig(
+                        cx.tcx,
+                        cx.module.isa().triple(),
+                        instance,
+                        false,
+                    );
+                    let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
+                    cx.module.declare_function(&name, linkage, &sig).unwrap();
+                }
+                MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
+            }
+        }
+    });
+
+    for (mono_item, (linkage, visibility)) in mono_items {
+        let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
+        trans_mono_item(cx, mono_item, linkage);
+    }
+}
+
+fn trans_mono_item<'tcx, M: Module>(
+    cx: &mut crate::CodegenCx<'tcx, M>,
+    mono_item: MonoItem<'tcx>,
+    linkage: Linkage,
+) {
+    let tcx = cx.tcx;
+    match mono_item {
+        MonoItem::Fn(inst) => {
+            let _inst_guard =
+                crate::PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name));
+            debug_assert!(!inst.substs.needs_infer());
+            tcx.sess
+                .time("codegen fn", || crate::base::trans_fn(cx, inst, linkage));
+        }
+        MonoItem::Static(def_id) => {
+            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+        }
+        MonoItem::GlobalAsm(hir_id) => {
+            let item = tcx.hir().expect_item(hir_id);
+            if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
+                cx.global_asm.push_str(&*asm.as_str());
+                cx.global_asm.push_str("\n\n");
+            } else {
+                bug!("Expected GlobalAsm found {:?}", item);
+            }
+        }
+    }
+}
+
+fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
+    if std::env::var("CG_CLIF_DISPLAY_CG_TIME")
+        .as_ref()
+        .map(|val| &**val)
+        == Ok("1")
+    {
+        println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name);
+        let before = std::time::Instant::now();
+        let res = tcx.sess.time(name, f);
+        let after = std::time::Instant::now();
+        println!(
+            "[{:<30}: {}] end time: {:?}",
+            tcx.crate_name(LOCAL_CRATE),
+            name,
+            after - before
+        );
+        res
+    } else {
+        tcx.sess.time(name, f)
+    }
+}