Add support for calling C abi functions
This commit is contained in:
parent
a4da89d608
commit
82dbd07806
8 changed files with 87 additions and 35 deletions
13
build.sh
13
build.sh
|
@ -1,7 +1,12 @@
|
||||||
cargo build || exit 1
|
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 &&
|
cd examples/
|
||||||
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
|
|
||||||
|
|
||||||
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
|
||||||
|
|
25
examples/mini_core_hello_world.rs
Normal file
25
examples/mini_core_hello_world.rs
Normal file
|
@ -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
|
||||||
|
}
|
36
src/abi.rs
36
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);
|
let sig = ty_fn_sig(tcx, fn_ty);
|
||||||
assert!(!sig.variadic, "Variadic function are not yet supported");
|
assert!(!sig.variadic, "Variadic function are not yet supported");
|
||||||
let (call_conv, inputs, _output): (CallConv, Vec<Ty>, Ty) = match sig.abi {
|
let (call_conv, inputs, _output): (CallConv, Vec<Ty>, 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 => {
|
Abi::RustCall => {
|
||||||
println!("rust-call sig: {:?} inputs: {:?} output: {:?}", sig, sig.inputs(), sig.output());
|
println!("rust-call sig: {:?} inputs: {:?} output: {:?}", sig, sig.inputs(), sig.output());
|
||||||
assert_eq!(sig.inputs().len(), 2);
|
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<Ty> = vec![sig.inputs()[0]];
|
let mut inputs: Vec<Ty> = vec![sig.inputs()[0]];
|
||||||
inputs.extend(extra_args.into_iter());
|
inputs.extend(extra_args.into_iter());
|
||||||
(
|
(
|
||||||
CallConv::SystemV,
|
CallConv::Fast,
|
||||||
inputs,
|
inputs,
|
||||||
sig.output(),
|
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 {
|
Signature {
|
||||||
params: Some(types::I64).into_iter() // First param is place to put return val
|
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(),
|
.map(AbiParam::new).collect(),
|
||||||
returns: vec![],
|
returns: vec![],
|
||||||
call_conv,
|
call_conv,
|
||||||
|
@ -91,17 +102,13 @@ impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
|
||||||
/// Instance must be monomorphized
|
/// Instance must be monomorphized
|
||||||
pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
|
pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
|
||||||
assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types());
|
assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types());
|
||||||
let tcx = self.tcx;
|
let fn_ty = inst.ty(self.tcx);
|
||||||
let module = &mut self.module;
|
let sig = cton_sig_from_fn_ty(self.tcx, fn_ty);
|
||||||
let func_id = *self.def_id_fn_id_map.entry(inst).or_insert_with(|| {
|
let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(self.tcx, false, false);
|
||||||
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();
|
let mut name = String::new();
|
||||||
def_path_based_names.push_instance_as_string(inst, &mut name);
|
def_path_based_names.push_instance_as_string(inst, &mut name);
|
||||||
module.declare_function(&name, Linkage::Local, &sig).unwrap()
|
let func_id = self.module.declare_function(&name, Linkage::Import, &sig).unwrap();
|
||||||
});
|
self.module.declare_func_in_func(func_id, &mut self.bcx.func)
|
||||||
module.declare_func_in_func(func_id, &mut self.bcx.func)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lib_call(
|
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) {
|
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 ret_param = fx.bcx.append_ebb_param(start_ebb, types::I64);
|
||||||
let _ = fx.bcx.create_stack_slot(StackSlotData {
|
let _ = fx.bcx.create_stack_slot(StackSlotData {
|
||||||
kind: StackSlotKind::ExplicitSlot,
|
kind: StackSlotKind::ExplicitSlot,
|
||||||
|
|
|
@ -20,15 +20,13 @@ pub fn trans_mono_item<'a, 'tcx: 'a>(cx: &mut CodegenCx<'a, 'tcx, CurrentBackend
|
||||||
&fn_ty,
|
&fn_ty,
|
||||||
);
|
);
|
||||||
let sig = cton_sig_from_fn_ty(tcx, fn_ty);
|
let sig = cton_sig_from_fn_ty(tcx, fn_ty);
|
||||||
|
|
||||||
let func_id = {
|
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
|
// WARNING: keep in sync with FunctionCx::get_function_ref
|
||||||
let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(tcx, false, false);
|
let def_path_based_names = ::rustc_mir::monomorphize::item::DefPathBasedNames::new(cx.tcx, false, false);
|
||||||
let mut name = String::new();
|
let mut name = String::new();
|
||||||
def_path_based_names.push_instance_as_string(inst, &mut name);
|
def_path_based_names.push_instance_as_string(inst, &mut name);
|
||||||
module.declare_function(&name, Linkage::Local, &sig).unwrap()
|
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);
|
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 {
|
let mut fx = FunctionCx {
|
||||||
tcx: cx.tcx,
|
tcx: cx.tcx,
|
||||||
module: &mut cx.module,
|
module: &mut cx.module,
|
||||||
def_id_fn_id_map: &mut cx.def_id_fn_id_map,
|
|
||||||
instance,
|
instance,
|
||||||
mir,
|
mir,
|
||||||
bcx,
|
bcx,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
||||||
|
|
||||||
use rustc_target::spec::{HasTargetSpec, Target};
|
use rustc_target::spec::{HasTargetSpec, Target};
|
||||||
|
|
||||||
use cranelift_module::{Module, FuncId, DataId};
|
use cranelift_module::{Module, DataId};
|
||||||
|
|
||||||
use crate::prelude::*;
|
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 struct FunctionCx<'a, 'tcx: 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
pub module: &'a mut Module<CurrentBackend>,
|
pub module: &'a mut Module<CurrentBackend>,
|
||||||
pub def_id_fn_id_map: &'a mut HashMap<Instance<'tcx>, FuncId>,
|
|
||||||
pub instance: Instance<'tcx>,
|
pub instance: Instance<'tcx>,
|
||||||
pub mir: &'tcx Mir<'tcx>,
|
pub mir: &'tcx Mir<'tcx>,
|
||||||
pub param_substs: &'tcx Substs<'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> {
|
impl<'a, 'tcx: 'a> fmt::Debug for FunctionCx<'a, 'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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.param_substs)?;
|
||||||
writeln!(f, "{:?}", self.local_map)?;
|
writeln!(f, "{:?}", self.local_map)?;
|
||||||
|
|
||||||
|
|
25
src/lib.rs
25
src/lib.rs
|
@ -89,7 +89,6 @@ use crate::prelude::*;
|
||||||
pub struct CodegenCx<'a, 'tcx: 'a, B: Backend + 'a> {
|
pub struct CodegenCx<'a, 'tcx: 'a, B: Backend + 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
pub module: &'a mut Module<B>,
|
pub module: &'a mut Module<B>,
|
||||||
pub def_id_fn_id_map: &'a mut HashMap<Instance<'tcx>, FuncId>,
|
|
||||||
pub constants: HashMap<AllocId, DataId>,
|
pub constants: HashMap<AllocId, DataId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,13 +224,11 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
||||||
let isa = cranelift::codegen::isa::lookup(target_lexicon::Triple::host()).unwrap().finish(flags);
|
let isa = cranelift::codegen::isa::lookup(target_lexicon::Triple::host()).unwrap().finish(flags);
|
||||||
let mut module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
|
let mut module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let mut def_id_fn_id_map = HashMap::new();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut cx = CodegenCx {
|
let mut cx = CodegenCx {
|
||||||
tcx,
|
tcx,
|
||||||
module: &mut module,
|
module: &mut module,
|
||||||
def_id_fn_id_map: &mut def_id_fn_id_map,
|
|
||||||
constants: HashMap::new(),
|
constants: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -251,12 +248,30 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
||||||
module.finalize_all();
|
module.finalize_all();
|
||||||
tcx.sess.warn("Finalized everything");
|
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::ret_42" {
|
||||||
if tcx.absolute_item_path_str(inst.def_id()) != "example::option_unwrap_or" {
|
if tcx.absolute_item_path_str(inst.def_id()) != "example::option_unwrap_or" {
|
||||||
continue;
|
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 f: extern "C" fn(&mut u32) = unsafe { ::std::mem::transmute(finalized_function) };
|
||||||
let mut res = 0u32;
|
let mut res = 0u32;
|
||||||
f(&mut res);
|
f(&mut res);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue