use cranelift_codegen::ir::*; use cranelift_codegen::isa::CallConv; use cranelift_codegen::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)) .unwrap(); 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(UserFuncName::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_(&[]); } module.define_function(func_id, &mut ctx).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)) .unwrap(); 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(UserFuncName::default(), 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, 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)) .unwrap(); 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(UserFuncName::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_(&[]); } module.define_function(func_id, &mut ctx).unwrap(); module.finish(); } #[test] #[should_panic(expected = "has a null byte, which is disallowed")] fn reject_nul_byte_symbol_for_func() { 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)) .unwrap(); 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 _ = module .declare_function("function\u{0}with\u{0}nul\u{0}bytes", Linkage::Local, &sig) .unwrap(); } #[test] #[should_panic(expected = "has a null byte, which is disallowed")] fn reject_nul_byte_symbol_for_data() { 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)) .unwrap(); let mut module = ObjectModule::new(ObjectBuilder::new(isa, "foo", default_libcall_names()).unwrap()); let _ = module .declare_data( "data\u{0}with\u{0}nul\u{0}bytes", Linkage::Local, /* writable = */ true, /* tls = */ false, ) .unwrap(); }