diff --git a/cranelift/faerie/src/backend.rs b/cranelift/faerie/src/backend.rs index 1deb46e073..0adb564b30 100644 --- a/cranelift/faerie/src/backend.rs +++ b/cranelift/faerie/src/backend.rs @@ -46,7 +46,7 @@ impl FaerieBuilder { /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall` /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain /// floating point instructions, and for stack probes. If you don't know what to use for this - /// argument, use `FaerieBuilder::default_libcall_names()`. + /// argument, use `cranelift_module::default_libcall_names()`. pub fn new( isa: Box, name: String, @@ -65,25 +65,6 @@ impl FaerieBuilder { libcall_names, }) } - - /// Default names for `ir::LibCall`s. A function by this name is imported into the object as - /// part of the translation of a `ir::ExternalName::LibCall` variant. - pub fn default_libcall_names() -> Box String> { - Box::new(move |libcall| match libcall { - ir::LibCall::Probestack => "__cranelift_probestack".to_owned(), - ir::LibCall::CeilF32 => "ceilf".to_owned(), - ir::LibCall::CeilF64 => "ceil".to_owned(), - ir::LibCall::FloorF32 => "floorf".to_owned(), - ir::LibCall::FloorF64 => "floor".to_owned(), - ir::LibCall::TruncF32 => "truncf".to_owned(), - ir::LibCall::TruncF64 => "trunc".to_owned(), - ir::LibCall::NearestF32 => "nearbyintf".to_owned(), - ir::LibCall::NearestF64 => "nearbyint".to_owned(), - ir::LibCall::Memcpy => "memcpy".to_owned(), - ir::LibCall::Memset => "memset".to_owned(), - ir::LibCall::Memmove => "memmove".to_owned(), - }) - } } /// A `FaerieBackend` implements `Backend` and emits ".o" files using the `faerie` library. diff --git a/cranelift/module/src/backend.rs b/cranelift/module/src/backend.rs index 956c206948..3f89e18fde 100644 --- a/cranelift/module/src/backend.rs +++ b/cranelift/module/src/backend.rs @@ -9,6 +9,10 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::Context; use cranelift_codegen::{binemit, ir}; +use std::borrow::ToOwned; +use std::boxed::Box; +use std::string::String; + /// A `Backend` implements the functionality needed to support a `Module`. /// /// Two notable implementations of this trait are: @@ -127,3 +131,22 @@ where /// provide additional functionality through this result. fn finish(self) -> Self::Product; } + +/// Default names for `ir::LibCall`s. A function by this name is imported into the object as +/// part of the translation of a `ir::ExternalName::LibCall` variant. +pub fn default_libcall_names() -> Box String> { + Box::new(move |libcall| match libcall { + ir::LibCall::Probestack => "__cranelift_probestack".to_owned(), + ir::LibCall::CeilF32 => "ceilf".to_owned(), + ir::LibCall::CeilF64 => "ceil".to_owned(), + ir::LibCall::FloorF32 => "floorf".to_owned(), + ir::LibCall::FloorF64 => "floor".to_owned(), + ir::LibCall::TruncF32 => "truncf".to_owned(), + ir::LibCall::TruncF64 => "trunc".to_owned(), + ir::LibCall::NearestF32 => "nearbyintf".to_owned(), + ir::LibCall::NearestF64 => "nearbyint".to_owned(), + ir::LibCall::Memcpy => "memcpy".to_owned(), + ir::LibCall::Memset => "memset".to_owned(), + ir::LibCall::Memmove => "memmove".to_owned(), + }) +} diff --git a/cranelift/module/src/lib.rs b/cranelift/module/src/lib.rs index e30961c3bc..33d12d96c2 100644 --- a/cranelift/module/src/lib.rs +++ b/cranelift/module/src/lib.rs @@ -37,7 +37,7 @@ mod backend; mod data_context; mod module; -pub use crate::backend::Backend; +pub use crate::backend::{default_libcall_names, Backend}; pub use crate::data_context::{DataContext, DataDescription, Init}; pub use crate::module::{ DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleError, ModuleFunction, ModuleNamespace, diff --git a/cranelift/simplejit/examples/simplejit-minimal.rs b/cranelift/simplejit/examples/simplejit-minimal.rs index eb1d3257ac..3b8e147830 100644 --- a/cranelift/simplejit/examples/simplejit-minimal.rs +++ b/cranelift/simplejit/examples/simplejit-minimal.rs @@ -1,10 +1,11 @@ use cranelift::prelude::*; -use cranelift_module::{Linkage, Module}; +use cranelift_module::{default_libcall_names, Linkage, Module}; use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; use std::mem; fn main() { - let mut module: Module = Module::new(SimpleJITBuilder::new()); + let mut module: Module = + Module::new(SimpleJITBuilder::new(default_libcall_names())); let mut ctx = module.make_context(); let mut func_ctx = FunctionBuilderContext::new(); diff --git a/cranelift/simplejit/src/backend.rs b/cranelift/simplejit/src/backend.rs index 8dc3ee09d0..7be3b3b2fa 100644 --- a/cranelift/simplejit/src/backend.rs +++ b/cranelift/simplejit/src/backend.rs @@ -21,17 +21,23 @@ use winapi; pub struct SimpleJITBuilder { isa: Box, symbols: HashMap, + libcall_names: Box String>, } impl SimpleJITBuilder { /// Create a new `SimpleJITBuilder`. - pub fn new() -> Self { + /// + /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall` + /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain + /// floating point instructions, and for stack probes. If you don't know what to use for this + /// argument, use `cranelift_module::default_libcall_names()`. + pub fn new(libcall_names: Box String>) -> Self { let flag_builder = settings::builder(); let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| { panic!("host machine is not supported: {}", msg); }); let isa = isa_builder.finish(settings::Flags::new(flag_builder)); - Self::with_isa(isa) + Self::with_isa(isa, libcall_names) } /// Create a new `SimpleJITBuilder` with an arbitrary target. This is mainly @@ -41,10 +47,19 @@ impl SimpleJITBuilder { /// /// To create a `SimpleJITBuilder` for native use, use the `new` constructor /// instead. - pub fn with_isa(isa: Box) -> Self { + /// + /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall` + /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain + /// floating point instructions, and for stack probes. If you don't know what to use for this + /// argument, use `cranelift_module::default_libcall_names()`. + pub fn with_isa(isa: Box, libcall_names: Box String>) -> Self { debug_assert!(!isa.flags().is_pic(), "SimpleJIT requires non-PIC code"); let symbols = HashMap::new(); - Self { isa, symbols } + Self { + isa, + symbols, + libcall_names, + } } /// Define a symbol in the internal symbol table. @@ -91,6 +106,7 @@ impl SimpleJITBuilder { pub struct SimpleJITBackend { isa: Box, symbols: HashMap, + libcall_names: Box String>, code_memory: Memory, readonly_memory: Memory, writable_memory: Memory, @@ -123,6 +139,35 @@ impl SimpleJITBackend { None => lookup_with_dlsym(name), } } + + fn get_definition( + &self, + namespace: &ModuleNamespace, + name: &ir::ExternalName, + ) -> *const u8 { + match *name { + ir::ExternalName::User { .. } => { + if namespace.is_function(name) { + let (def, name_str, _signature) = namespace.get_function_definition(&name); + match def { + Some(compiled) => compiled.code, + None => self.lookup_symbol(name_str), + } + } else { + let (def, name_str, _writable) = namespace.get_data_definition(&name); + match def { + Some(compiled) => compiled.storage, + None => self.lookup_symbol(name_str), + } + } + } + ir::ExternalName::LibCall(ref libcall) => { + let sym = (self.libcall_names)(*libcall); + self.lookup_symbol(&sym) + } + _ => panic!("invalid ExternalName {}", name), + } + } } impl<'simple_jit_backend> Backend for SimpleJITBackend { @@ -149,6 +194,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { Self { isa: builder.isa, symbols: builder.symbols, + libcall_names: builder.libcall_names, code_memory: Memory::new(), readonly_memory: Memory::new(), writable_memory: Memory::new(), @@ -308,19 +354,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { let ptr = func.code; debug_assert!((offset as usize) < func.size); let at = unsafe { ptr.offset(offset as isize) }; - let base = if namespace.is_function(name) { - let (def, name_str, _signature) = namespace.get_function_definition(&name); - match def { - Some(compiled) => compiled.code, - None => self.lookup_symbol(name_str), - } - } else { - let (def, name_str, _writable) = namespace.get_data_definition(&name); - match def { - Some(compiled) => compiled.storage, - None => self.lookup_symbol(name_str), - } - }; + let base = self.get_definition(namespace, name); // TODO: Handle overflow. let what = unsafe { base.offset(addend as isize) }; match reloc { @@ -373,19 +407,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { let ptr = data.storage; debug_assert!((offset as usize) < data.size); let at = unsafe { ptr.offset(offset as isize) }; - let base = if namespace.is_function(name) { - let (def, name_str, _signature) = namespace.get_function_definition(&name); - match def { - Some(compiled) => compiled.code, - None => self.lookup_symbol(name_str), - } - } else { - let (def, name_str, _writable) = namespace.get_data_definition(&name); - match def { - Some(compiled) => compiled.storage, - None => self.lookup_symbol(name_str), - } - }; + let base = self.get_definition(namespace, name); // TODO: Handle overflow. let what = unsafe { base.offset(addend as isize) }; match reloc { diff --git a/cranelift/simplejit/tests/basic.rs b/cranelift/simplejit/tests/basic.rs index 38da80c9a2..a3932b1d6a 100644 --- a/cranelift/simplejit/tests/basic.rs +++ b/cranelift/simplejit/tests/basic.rs @@ -1,6 +1,6 @@ use cranelift_codegen::ir::*; use cranelift_codegen::isa::CallConv; -use cranelift_codegen::Context; +use cranelift_codegen::{ir::types::I16, Context}; use cranelift_entity::EntityRef; use cranelift_frontend::*; use cranelift_module::*; @@ -8,7 +8,8 @@ use cranelift_simplejit::*; #[test] fn error_on_incompatible_sig_in_declare_function() { - let mut module: Module = Module::new(SimpleJITBuilder::new()); + let mut module: Module = + Module::new(SimpleJITBuilder::new(default_libcall_names())); let mut sig = Signature { params: vec![AbiParam::new(types::I64)], returns: vec![], @@ -52,7 +53,8 @@ fn define_simple_function(module: &mut Module) -> FuncId { #[test] fn double_finalize() { - let mut module: Module = Module::new(SimpleJITBuilder::new()); + let mut module: Module = + Module::new(SimpleJITBuilder::new(default_libcall_names())); define_simple_function(&mut module); module.finalize_definitions(); @@ -65,7 +67,8 @@ fn double_finalize() { #[test] #[should_panic(expected = "Result::unwrap()` on an `Err` value: DuplicateDefinition(\"abc\")")] fn panic_on_define_after_finalize() { - let mut module: Module = Module::new(SimpleJITBuilder::new()); + let mut module: Module = + Module::new(SimpleJITBuilder::new(default_libcall_names())); define_simple_function(&mut module); module.finalize_definitions(); @@ -144,3 +147,51 @@ fn switch_error() { } } } + +#[test] +fn libcall_function() { + let mut module: Module = + Module::new(SimpleJITBuilder::new(default_libcall_names())); + + let sig = Signature { + params: vec![], + returns: vec![], + call_conv: CallConv::SystemV, + }; + + let func_id = module + .declare_function("function", Linkage::Local, &sig) + .unwrap(); + + let mut ctx = Context::new(); + ctx.func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); + let ebb = bcx.create_ebb(); + bcx.switch_to_block(ebb); + + let int = module.target_config().pointer_type(); + let zero = bcx.ins().iconst(I16, 0); + let size = bcx.ins().iconst(int, 10); + + let mut signature = module.make_signature(); + signature.params.push(AbiParam::new(int)); + signature.returns.push(AbiParam::new(int)); + let callee = module + .declare_function("malloc", Linkage::Import, &signature) + .expect("declare malloc function"); + let local_callee = module.declare_func_in_func(callee, &mut bcx.func); + let argument_exprs = vec![size]; + let call = bcx.ins().call(local_callee, &argument_exprs); + let buffer = bcx.inst_results(call)[0]; + + bcx.call_memset(module.target_config(), buffer, zero, size); + + bcx.ins().return_(&[]); + } + + module.define_function(func_id, &mut ctx).unwrap(); + + module.finalize_definitions(); +}