From 82dbd0780694bd5281f9eb93199369da56e21ee2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 30 Jul 2018 18:20:37 +0200 Subject: [PATCH] Add support for calling C abi functions --- build.sh | 13 ++++++--- example.rs => examples/example.rs | 0 mini_core.rs => examples/mini_core.rs | 0 examples/mini_core_hello_world.rs | 25 +++++++++++++++++ src/abi.rs | 40 +++++++++++++++++---------- src/base.rs | 15 ++++------ src/common.rs | 4 +-- src/lib.rs | 25 +++++++++++++---- 8 files changed, 87 insertions(+), 35 deletions(-) rename example.rs => examples/example.rs (100%) rename mini_core.rs => examples/mini_core.rs (100%) create mode 100644 examples/mini_core_hello_world.rs diff --git a/build.sh b/build.sh index 724f5deedfc..82160c6435d 100755 --- a/build.sh +++ b/build.sh @@ -1,7 +1,12 @@ cargo build || exit 1 -rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so mini_core.rs --crate-name mini_core --crate-type lib -Og && -rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so -L crate=. example.rs --crate-type lib -Og && -rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so ./target/libcore/src/libcore/lib.rs --crate-type lib -Og +cd examples/ -rm libmini_core.rlib libexample.rlib +RUSTC="rustc -Zcodegen-backend=$(pwd)/../target/debug/librustc_codegen_cranelift.so -Og -L crate=. --crate-type lib" + +$RUSTC mini_core.rs --crate-name mini_core && +$RUSTC example.rs && +$RUSTC mini_core_hello_world.rs && +$RUSTC ../target/libcore/src/libcore/lib.rs + +rm *.rlib diff --git a/example.rs b/examples/example.rs similarity index 100% rename from example.rs rename to examples/example.rs diff --git a/mini_core.rs b/examples/mini_core.rs similarity index 100% rename from mini_core.rs rename to examples/mini_core.rs diff --git a/examples/mini_core_hello_world.rs b/examples/mini_core_hello_world.rs new file mode 100644 index 00000000000..5fc0cff08bd --- /dev/null +++ b/examples/mini_core_hello_world.rs @@ -0,0 +1,25 @@ +// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs + +#![feature(no_core, unboxed_closures, start)] +#![no_core] +#![allow(dead_code)] + +extern crate mini_core; + +use mini_core::*; + +#[link(name = "c")] +extern "C" {} + +extern "C" { + fn puts(s: *const u8); +} + +#[start] +fn main(i: isize, _: *const *const u8) -> isize { + unsafe { + let (ptr, _): (*const u8, usize) = intrinsics::transmute("Hello!\0"); + puts(ptr); + } + 0 +} diff --git a/src/abi.rs b/src/abi.rs index 144ba167c51..2c9f72d2fe1 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -9,7 +9,8 @@ pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty< let sig = ty_fn_sig(tcx, fn_ty); assert!(!sig.variadic, "Variadic function are not yet supported"); let (call_conv, inputs, _output): (CallConv, Vec, Ty) = match sig.abi { - Abi::Rust => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()), + Abi::Rust => (CallConv::Fast, sig.inputs().to_vec(), sig.output()), + Abi::C => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()), Abi::RustCall => { println!("rust-call sig: {:?} inputs: {:?} output: {:?}", sig, sig.inputs(), sig.output()); assert_eq!(sig.inputs().len(), 2); @@ -20,7 +21,7 @@ pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty< let mut inputs: Vec = vec![sig.inputs()[0]]; inputs.extend(extra_args.into_iter()); ( - CallConv::SystemV, + CallConv::Fast, inputs, sig.output(), ) @@ -31,7 +32,17 @@ pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty< }; Signature { params: Some(types::I64).into_iter() // First param is place to put return val - .chain(inputs.into_iter().map(|ty| cton_type_from_ty(tcx, ty).unwrap_or(types::I64))) + .chain(inputs.into_iter().map(|ty| { + let cton_ty = cton_type_from_ty(tcx, ty); + if let Some(cton_ty) = cton_ty { + cton_ty + } else { + if sig.abi == Abi::C { + unimplemented!("Non scalars are not yet supported for \"C\" abi"); + } + types::I64 + } + })) .map(AbiParam::new).collect(), returns: vec![], call_conv, @@ -91,17 +102,13 @@ impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> { /// Instance must be monomorphized pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef { assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types()); - let tcx = self.tcx; - let module = &mut self.module; - let func_id = *self.def_id_fn_id_map.entry(inst).or_insert_with(|| { - let fn_ty = inst.ty(tcx); - let sig = cton_sig_from_fn_ty(tcx, fn_ty); - let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(tcx, false, false); - let mut name = String::new(); - def_path_based_names.push_instance_as_string(inst, &mut name); - module.declare_function(&name, Linkage::Local, &sig).unwrap() - }); - module.declare_func_in_func(func_id, &mut self.bcx.func) + let fn_ty = inst.ty(self.tcx); + let sig = cton_sig_from_fn_ty(self.tcx, fn_ty); + let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(self.tcx, false, false); + let mut name = String::new(); + def_path_based_names.push_instance_as_string(inst, &mut name); + let func_id = self.module.declare_function(&name, Linkage::Import, &sig).unwrap(); + self.module.declare_func_in_func(func_id, &mut self.bcx.func) } fn lib_call( @@ -156,6 +163,11 @@ impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> { } pub fn codegen_fn_prelude<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, start_ebb: Ebb) { + match fx.self_sig().abi { + Abi::Rust | Abi::RustCall => {} + _ => unimplemented!("declared function with non \"rust\" or \"rust-call\" abi"), + } + let ret_param = fx.bcx.append_ebb_param(start_ebb, types::I64); let _ = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, diff --git a/src/base.rs b/src/base.rs index dbb562e4e5a..3647bcc4001 100644 --- a/src/base.rs +++ b/src/base.rs @@ -20,15 +20,13 @@ pub fn trans_mono_item<'a, 'tcx: 'a>(cx: &mut CodegenCx<'a, 'tcx, CurrentBackend &fn_ty, ); let sig = cton_sig_from_fn_ty(tcx, fn_ty); + let func_id = { - let module = &mut cx.module; - *cx.def_id_fn_id_map.entry(inst).or_insert_with(|| { - // WARNING: keep in sync with FunctionCx::get_function_ref - let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(tcx, false, false); - let mut name = String::new(); - def_path_based_names.push_instance_as_string(inst, &mut name); - module.declare_function(&name, Linkage::Local, &sig).unwrap() - }) + // WARNING: keep in sync with FunctionCx::get_function_ref + let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(cx.tcx, false, false); + let mut name = String::new(); + def_path_based_names.push_instance_as_string(inst, &mut name); + cx.module.declare_function(&name, Linkage::Export, &sig).unwrap() }; let mut f = Function::with_name_signature(ExternalName::user(0, func_id.index() as u32), sig); @@ -84,7 +82,6 @@ pub fn trans_fn<'a, 'tcx: 'a>(cx: &mut CodegenCx<'a, 'tcx, CurrentBackend>, f: & let mut fx = FunctionCx { tcx: cx.tcx, module: &mut cx.module, - def_id_fn_id_map: &mut cx.def_id_fn_id_map, instance, mir, bcx, diff --git a/src/common.rs b/src/common.rs index 2ef9d1d6772..d98818604ee 100644 --- a/src/common.rs +++ b/src/common.rs @@ -2,7 +2,7 @@ use std::fmt; use rustc_target::spec::{HasTargetSpec, Target}; -use cranelift_module::{Module, FuncId, DataId}; +use cranelift_module::{Module, DataId}; use crate::prelude::*; @@ -295,7 +295,6 @@ pub fn cton_intcast<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, val: Value, fro pub struct FunctionCx<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub module: &'a mut Module, - pub def_id_fn_id_map: &'a mut HashMap, FuncId>, pub instance: Instance<'tcx>, pub mir: &'tcx Mir<'tcx>, pub param_substs: &'tcx Substs<'tcx>, @@ -308,7 +307,6 @@ pub struct FunctionCx<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> fmt::Debug for FunctionCx<'a, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "{:?}", self.def_id_fn_id_map)?; writeln!(f, "{:?}", self.param_substs)?; writeln!(f, "{:?}", self.local_map)?; diff --git a/src/lib.rs b/src/lib.rs index e69c1625f3f..66d2e662c8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,6 @@ use crate::prelude::*; pub struct CodegenCx<'a, 'tcx: 'a, B: Backend + 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub module: &'a mut Module, - pub def_id_fn_id_map: &'a mut HashMap, FuncId>, pub constants: HashMap, } @@ -225,13 +224,11 @@ impl CodegenBackend for CraneliftCodegenBackend { let isa = cranelift::codegen::isa::lookup(target_lexicon::Triple::host()).unwrap().finish(flags); let mut module: Module = Module::new(SimpleJITBuilder::new()); let mut context = Context::new(); - let mut def_id_fn_id_map = HashMap::new(); { let mut cx = CodegenCx { tcx, module: &mut module, - def_id_fn_id_map: &mut def_id_fn_id_map, constants: HashMap::new(), }; @@ -251,12 +248,30 @@ impl CodegenBackend for CraneliftCodegenBackend { module.finalize_all(); tcx.sess.warn("Finalized everything"); - for (inst, func_id) in def_id_fn_id_map.iter() { + for mono_item in + collector::collect_crate_mono_items( + tcx, + collector::MonoItemCollectionMode::Eager + ).0 { + + let inst = match mono_item { + MonoItem::Fn(inst) => inst, + _ => continue, + }; + //if tcx.absolute_item_path_str(inst.def_id()) != "example::ret_42" { if tcx.absolute_item_path_str(inst.def_id()) != "example::option_unwrap_or" { continue; } - let finalized_function: *const u8 = module.finalize_function(*func_id); + + let fn_ty = inst.ty(tcx); + let sig = cton_sig_from_fn_ty(tcx, fn_ty); + let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(tcx, false, false); + let mut name = String::new(); + def_path_based_names.push_instance_as_string(inst, &mut name); + let func_id = module.declare_function(&name, Linkage::Import, &sig).unwrap(); + + let finalized_function: *const u8 = module.finalize_function(func_id); /*let f: extern "C" fn(&mut u32) = unsafe { ::std::mem::transmute(finalized_function) }; let mut res = 0u32; f(&mut res);