Fix usage of default_libcall_names (#2378)
* Fix usage of default_libcall_names * Add basic cranelift-object test It is based on a test with the same name in cranelift-simplejit
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -435,6 +435,8 @@ version = "0.68.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
|
"cranelift-entity",
|
||||||
|
"cranelift-frontend",
|
||||||
"cranelift-module",
|
"cranelift-module",
|
||||||
"log",
|
"log",
|
||||||
"object",
|
"object",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||||||
|
|
||||||
/// Default names for `ir::LibCall`s. A function by this name is imported into the object as
|
/// 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.
|
/// part of the translation of a `ir::ExternalName::LibCall` variant.
|
||||||
pub fn default_libcall_names() -> Box<dyn Fn(ir::LibCall) -> String> {
|
pub fn default_libcall_names() -> Box<dyn Fn(ir::LibCall) -> String + Send + Sync> {
|
||||||
Box::new(move |libcall| match libcall {
|
Box::new(move |libcall| match libcall {
|
||||||
ir::LibCall::Probestack => "__cranelift_probestack".to_owned(),
|
ir::LibCall::Probestack => "__cranelift_probestack".to_owned(),
|
||||||
ir::LibCall::UdivI64 => "__udivdi3".to_owned(),
|
ir::LibCall::UdivI64 => "__udivdi3".to_owned(),
|
||||||
|
|||||||
@@ -17,5 +17,9 @@ target-lexicon = "0.11"
|
|||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
log = { version = "0.4.6", default-features = false }
|
log = { version = "0.4.6", default-features = false }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
cranelift-frontend = { path = "../frontend", version = "0.68.0" }
|
||||||
|
cranelift-entity = { path = "../entity", version = "0.68.0" }
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
|
|||||||
199
cranelift/object/tests/basic.rs
Normal file
199
cranelift/object/tests/basic.rs
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
use cranelift_codegen::ir::*;
|
||||||
|
use cranelift_codegen::isa::CallConv;
|
||||||
|
use cranelift_codegen::{binemit::NullTrapSink, settings};
|
||||||
|
use cranelift_codegen::{ir::types::I16, Context};
|
||||||
|
use cranelift_entity::EntityRef;
|
||||||
|
use cranelift_frontend::*;
|
||||||
|
use cranelift_module::*;
|
||||||
|
use cranelift_object::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_on_incompatible_sig_in_declare_function() {
|
||||||
|
let flag_builder = settings::builder();
|
||||||
|
let isa_builder = cranelift_codegen::isa::lookup_by_name("x86_64-unknown-linux-gnu").unwrap();
|
||||||
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
|
let mut module =
|
||||||
|
ObjectModule::new(ObjectBuilder::new(isa, "foo", default_libcall_names()).unwrap());
|
||||||
|
let mut sig = Signature {
|
||||||
|
params: vec![AbiParam::new(types::I64)],
|
||||||
|
returns: vec![],
|
||||||
|
call_conv: CallConv::SystemV,
|
||||||
|
};
|
||||||
|
module
|
||||||
|
.declare_function("abc", Linkage::Local, &sig)
|
||||||
|
.unwrap();
|
||||||
|
sig.params[0] = AbiParam::new(types::I32);
|
||||||
|
module
|
||||||
|
.declare_function("abc", Linkage::Local, &sig)
|
||||||
|
.err()
|
||||||
|
.unwrap(); // Make sure this is an error
|
||||||
|
}
|
||||||
|
|
||||||
|
fn define_simple_function(module: &mut ObjectModule) -> FuncId {
|
||||||
|
let sig = Signature {
|
||||||
|
params: vec![],
|
||||||
|
returns: vec![],
|
||||||
|
call_conv: CallConv::SystemV,
|
||||||
|
};
|
||||||
|
|
||||||
|
let func_id = module
|
||||||
|
.declare_function("abc", 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 block = bcx.create_block();
|
||||||
|
bcx.switch_to_block(block);
|
||||||
|
bcx.ins().return_(&[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut trap_sink = NullTrapSink {};
|
||||||
|
module
|
||||||
|
.define_function(func_id, &mut ctx, &mut trap_sink)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
func_id
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Result::unwrap()` on an `Err` value: DuplicateDefinition(\"abc\")")]
|
||||||
|
fn panic_on_define_after_finalize() {
|
||||||
|
let flag_builder = settings::builder();
|
||||||
|
let isa_builder = cranelift_codegen::isa::lookup_by_name("x86_64-unknown-linux-gnu").unwrap();
|
||||||
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
|
let mut module =
|
||||||
|
ObjectModule::new(ObjectBuilder::new(isa, "foo", default_libcall_names()).unwrap());
|
||||||
|
|
||||||
|
define_simple_function(&mut module);
|
||||||
|
define_simple_function(&mut module);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_error() {
|
||||||
|
use cranelift_codegen::settings;
|
||||||
|
|
||||||
|
let sig = Signature {
|
||||||
|
params: vec![AbiParam::new(types::I32)],
|
||||||
|
returns: vec![AbiParam::new(types::I32)],
|
||||||
|
call_conv: CallConv::SystemV,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
|
||||||
|
|
||||||
|
let mut func_ctx = FunctionBuilderContext::new();
|
||||||
|
{
|
||||||
|
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut func, &mut func_ctx);
|
||||||
|
let start = bcx.create_block();
|
||||||
|
let bb0 = bcx.create_block();
|
||||||
|
let bb1 = bcx.create_block();
|
||||||
|
let bb2 = bcx.create_block();
|
||||||
|
let bb3 = bcx.create_block();
|
||||||
|
println!("{} {} {} {} {}", start, bb0, bb1, bb2, bb3);
|
||||||
|
|
||||||
|
bcx.declare_var(Variable::new(0), types::I32);
|
||||||
|
bcx.declare_var(Variable::new(1), types::I32);
|
||||||
|
let in_val = bcx.append_block_param(start, types::I32);
|
||||||
|
bcx.switch_to_block(start);
|
||||||
|
bcx.def_var(Variable::new(0), in_val);
|
||||||
|
bcx.ins().jump(bb0, &[]);
|
||||||
|
|
||||||
|
bcx.switch_to_block(bb0);
|
||||||
|
let discr = bcx.use_var(Variable::new(0));
|
||||||
|
let mut switch = cranelift_frontend::Switch::new();
|
||||||
|
for &(index, bb) in &[
|
||||||
|
(9, bb1),
|
||||||
|
(13, bb1),
|
||||||
|
(10, bb1),
|
||||||
|
(92, bb1),
|
||||||
|
(39, bb1),
|
||||||
|
(34, bb1),
|
||||||
|
] {
|
||||||
|
switch.set_entry(index, bb);
|
||||||
|
}
|
||||||
|
switch.emit(&mut bcx, discr, bb2);
|
||||||
|
|
||||||
|
bcx.switch_to_block(bb1);
|
||||||
|
let v = bcx.use_var(Variable::new(0));
|
||||||
|
bcx.def_var(Variable::new(1), v);
|
||||||
|
bcx.ins().jump(bb3, &[]);
|
||||||
|
|
||||||
|
bcx.switch_to_block(bb2);
|
||||||
|
let v = bcx.use_var(Variable::new(0));
|
||||||
|
bcx.def_var(Variable::new(1), v);
|
||||||
|
bcx.ins().jump(bb3, &[]);
|
||||||
|
|
||||||
|
bcx.switch_to_block(bb3);
|
||||||
|
let r = bcx.use_var(Variable::new(1));
|
||||||
|
bcx.ins().return_(&[r]);
|
||||||
|
|
||||||
|
bcx.seal_all_blocks();
|
||||||
|
bcx.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
let flags = settings::Flags::new(settings::builder());
|
||||||
|
match cranelift_codegen::verify_function(&func, &flags) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
let pretty_error =
|
||||||
|
cranelift_codegen::print_errors::pretty_verifier_error(&func, None, None, err);
|
||||||
|
panic!("pretty_error:\n{}", pretty_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn libcall_function() {
|
||||||
|
let flag_builder = settings::builder();
|
||||||
|
let isa_builder = cranelift_codegen::isa::lookup_by_name("x86_64-unknown-linux-gnu").unwrap();
|
||||||
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
|
let mut module =
|
||||||
|
ObjectModule::new(ObjectBuilder::new(isa, "foo", default_libcall_names()).unwrap());
|
||||||
|
|
||||||
|
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 block = bcx.create_block();
|
||||||
|
bcx.switch_to_block(block);
|
||||||
|
|
||||||
|
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_(&[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut trap_sink = NullTrapSink {};
|
||||||
|
module
|
||||||
|
.define_function(func_id, &mut ctx, &mut trap_sink)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
module.finish();
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ const READONLY_DATA_ALIGNMENT: u64 = 0x1;
|
|||||||
pub struct SimpleJITBuilder {
|
pub struct SimpleJITBuilder {
|
||||||
isa: Box<dyn TargetIsa>,
|
isa: Box<dyn TargetIsa>,
|
||||||
symbols: HashMap<String, *const u8>,
|
symbols: HashMap<String, *const u8>,
|
||||||
libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
|
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleJITBuilder {
|
impl SimpleJITBuilder {
|
||||||
@@ -43,7 +43,7 @@ impl SimpleJITBuilder {
|
|||||||
/// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
|
/// 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
|
/// floating point instructions, and for stack probes. If you don't know what to use for this
|
||||||
/// argument, use `cranelift_module::default_libcall_names()`.
|
/// argument, use `cranelift_module::default_libcall_names()`.
|
||||||
pub fn new(libcall_names: Box<dyn Fn(ir::LibCall) -> String>) -> Self {
|
pub fn new(libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>) -> Self {
|
||||||
let mut flag_builder = settings::builder();
|
let mut flag_builder = settings::builder();
|
||||||
// On at least AArch64, "colocated" calls use shorter-range relocations,
|
// On at least AArch64, "colocated" calls use shorter-range relocations,
|
||||||
// which might not reach all definitions; we can't handle that here, so
|
// which might not reach all definitions; we can't handle that here, so
|
||||||
@@ -70,7 +70,7 @@ impl SimpleJITBuilder {
|
|||||||
/// argument, use `cranelift_module::default_libcall_names()`.
|
/// argument, use `cranelift_module::default_libcall_names()`.
|
||||||
pub fn with_isa(
|
pub fn with_isa(
|
||||||
isa: Box<dyn TargetIsa>,
|
isa: Box<dyn TargetIsa>,
|
||||||
libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
|
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(!isa.flags().is_pic(), "SimpleJIT requires non-PIC code");
|
debug_assert!(!isa.flags().is_pic(), "SimpleJIT requires non-PIC code");
|
||||||
let symbols = HashMap::new();
|
let symbols = HashMap::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user