diff --git a/cranelift/codegen/meta/src/shared/settings.rs b/cranelift/codegen/meta/src/shared/settings.rs index 6b8b7a017f..3b6980daa1 100644 --- a/cranelift/codegen/meta/src/shared/settings.rs +++ b/cranelift/codegen/meta/src/shared/settings.rs @@ -94,6 +94,29 @@ pub fn define() -> SettingGroup { // Settings specific to the `baldrdash` calling convention. + settings.add_enum( + "libcall_call_conv", + r#" + Defines the calling convention to use for LibCalls call expansion, + since it may be different from the ISA default calling convention. + + The default value is to use the same calling convention as the ISA + default calling convention. + + This list should be kept in sync with the list of calling + conventions available in isa/call_conv.rs. + "#, + vec![ + "isa_default", + "fast", + "cold", + "system_v", + "windows_fastcall", + "baldrdash", + "probestack", + ], + ); + settings.add_num( "baldrdash_prologue_words", r#" diff --git a/cranelift/codegen/src/ir/libcall.rs b/cranelift/codegen/src/ir/libcall.rs index f544dd5732..2398e043a0 100644 --- a/cranelift/codegen/src/ir/libcall.rs +++ b/cranelift/codegen/src/ir/libcall.rs @@ -108,11 +108,13 @@ impl LibCall { /// If there is an existing reference, use it, otherwise make a new one. pub fn get_libcall_funcref( libcall: LibCall, + call_conv: CallConv, func: &mut Function, inst: Inst, isa: &dyn TargetIsa, ) -> FuncRef { - find_funcref(libcall, func).unwrap_or_else(|| make_funcref_for_inst(libcall, func, inst, isa)) + find_funcref(libcall, func) + .unwrap_or_else(|| make_funcref_for_inst(libcall, call_conv, func, inst, isa)) } /// Get a function reference for the probestack function in `func`. @@ -164,11 +166,12 @@ fn make_funcref_for_probestack( /// Create a funcref for `libcall` with a signature matching `inst`. fn make_funcref_for_inst( libcall: LibCall, + call_conv: CallConv, func: &mut Function, inst: Inst, isa: &dyn TargetIsa, ) -> FuncRef { - let mut sig = Signature::new(isa.default_call_conv()); + let mut sig = Signature::new(call_conv); for &v in func.dfg.inst_args(inst) { sig.params.push(AbiParam::new(func.dfg.value_type(v))); } @@ -176,6 +179,14 @@ fn make_funcref_for_inst( sig.returns.push(AbiParam::new(func.dfg.value_type(v))); } + if call_conv == CallConv::Baldrdash { + // Adds the special VMContext parameter to the signature. + sig.params.push(AbiParam::special( + isa.pointer_type(), + ArgumentPurpose::VMContext, + )); + } + make_funcref(libcall, func, sig, isa) } diff --git a/cranelift/codegen/src/isa/call_conv.rs b/cranelift/codegen/src/isa/call_conv.rs index d4b4d3999b..dcebde35e5 100644 --- a/cranelift/codegen/src/isa/call_conv.rs +++ b/cranelift/codegen/src/isa/call_conv.rs @@ -1,3 +1,5 @@ +use crate::isa::TargetIsa; +use crate::settings::LibcallCallConv; use core::fmt; use core::str; use target_lexicon::{CallingConvention, Triple}; @@ -29,6 +31,19 @@ impl CallConv { Ok(CallingConvention::WindowsFastcall) => CallConv::WindowsFastcall, } } + + /// Returns the calling convention used for libcalls for the given ISA. + pub fn for_libcall(isa: &dyn TargetIsa) -> Self { + match isa.flags().libcall_call_conv() { + LibcallCallConv::IsaDefault => isa.default_call_conv(), + LibcallCallConv::Fast => CallConv::Fast, + LibcallCallConv::Cold => CallConv::Cold, + LibcallCallConv::SystemV => CallConv::SystemV, + LibcallCallConv::WindowsFastcall => CallConv::WindowsFastcall, + LibcallCallConv::Baldrdash => CallConv::Baldrdash, + LibcallCallConv::Probestack => CallConv::Probestack, + } + } } impl fmt::Display for CallConv { diff --git a/cranelift/codegen/src/legalizer/libcall.rs b/cranelift/codegen/src/legalizer/libcall.rs index 01ff630f01..a5368948e9 100644 --- a/cranelift/codegen/src/legalizer/libcall.rs +++ b/cranelift/codegen/src/legalizer/libcall.rs @@ -2,7 +2,7 @@ use crate::ir; use crate::ir::{get_libcall_funcref, InstBuilder}; -use crate::isa::TargetIsa; +use crate::isa::{CallConv, TargetIsa}; use crate::legalizer::boundary::legalize_libcall_signature; use std::vec::Vec; @@ -18,8 +18,17 @@ pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function, isa: &dyn Targ // Now we convert `inst` to a call. First save the arguments. let mut args = Vec::new(); args.extend_from_slice(func.dfg.inst_args(inst)); + + let call_conv = CallConv::for_libcall(isa); + if call_conv == CallConv::Baldrdash { + let vmctx = func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("Missing vmctx parameter for baldrdash libcall"); + args.push(vmctx); + } + // The replace builder will preserve the instruction result values. - let funcref = get_libcall_funcref(libcall, func, inst, isa); + let funcref = get_libcall_funcref(libcall, call_conv, func, inst, isa); func.dfg.replace(inst).call(funcref, &args); // Ask the ISA to legalize the signature. diff --git a/cranelift/codegen/src/settings.rs b/cranelift/codegen/src/settings.rs index b93e3d7149..75462869bc 100644 --- a/cranelift/codegen/src/settings.rs +++ b/cranelift/codegen/src/settings.rs @@ -379,6 +379,7 @@ mod tests { f.to_string(), "[shared]\n\ opt_level = \"default\"\n\ + libcall_call_conv = \"isa_default\"\n\ baldrdash_prologue_words = 0\n\ probestack_size_log2 = 12\n\ enable_verifier = true\n\