Skip to content

Commit b27ec02

Browse files
committed
Fix varargs support on aarch64-apple-darwin
1 parent 1cb7282 commit b27ec02

File tree

1 file changed

+79
-19
lines changed

1 file changed

+79
-19
lines changed

src/abi/mod.rs

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ mod pass_mode;
55
mod returning;
66

77
use std::borrow::Cow;
8+
use std::mem;
89

9-
use cranelift_codegen::ir::SigRef;
10+
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
1011
use cranelift_codegen::isa::CallConv;
1112
use cranelift_module::ModuleError;
1213
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
@@ -17,6 +18,7 @@ use rustc_middle::ty::TypeVisitableExt;
1718
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1819
use rustc_session::Session;
1920
use rustc_span::source_map::Spanned;
21+
use rustc_span::sym::assert;
2022
use rustc_target::abi::call::{Conv, FnAbi};
2123
use rustc_target::spec::abi::Abi;
2224

@@ -425,7 +427,8 @@ pub(crate) fn codegen_terminator_call<'tcx>(
425427
None
426428
};
427429

428-
let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
430+
let fixed_arg_count = fn_sig.inputs().skip_binder().len();
431+
let extra_args = &args[fixed_arg_count..];
429432
let extra_args = fx.tcx.mk_type_list_from_iter(
430433
extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.node.ty(fx.mir, fx.tcx))),
431434
);
@@ -532,18 +535,59 @@ pub(crate) fn codegen_terminator_call<'tcx>(
532535
};
533536

534537
self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
535-
let call_args = return_ptr
538+
// The majority of this block is hacky workarounds for cranelift not supporting C variadic
539+
// functions. The only bits that aren't are the `let mut call_args =` statement (excluding
540+
// the `.take()`; `(&mut args_iter)` can be replace with `args.into_iter().enumerate()`)
541+
// and the `let call_inst = ` statement.
542+
543+
let has_return_arg = return_ptr.is_some();
544+
let mut args_iter = args.into_iter().enumerate();
545+
let mut call_args = return_ptr
536546
.into_iter()
537547
.chain(first_arg_override.into_iter())
538548
.chain(
539-
args.into_iter()
540-
.enumerate()
549+
(&mut args_iter)
550+
// If the function is variadic, only add the fixed argument first so that how
551+
// many `Value`s the fixed arguments expand to can be counted.
552+
.take(if fn_sig.c_variadic() { fixed_arg_count } else { usize::MAX })
541553
.skip(if first_arg_override.is_some() { 1 } else { 0 })
542554
.flat_map(|(i, arg)| {
543555
adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
544556
}),
545557
)
546558
.collect::<Vec<Value>>();
559+
// Count how many `Value`s represent the fixed arguments.
560+
let fixed_arg_count = call_args.len();
561+
// Add the rest of the arguments. This is a no-op unless the function is variadic.
562+
call_args.extend(args_iter.flat_map(|(i, arg)| {
563+
adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
564+
}));
565+
566+
if fx.tcx.sess.target.is_like_osx
567+
&& fx.tcx.sess.target.arch == "aarch64"
568+
&& fn_sig.c_variadic()
569+
// No need to pad the argument list unless variadic arguments are actually being passed.
570+
&& call_args.len() > fixed_arg_count
571+
{
572+
// 128-bit integers take 2 registers, and everything else takes 1.
573+
// FIXME: Add support for non-integer types
574+
// This relies on the checks below to ensure all arguments are integer types and that
575+
// the ABI is "C".
576+
// The return argument isn't counted as it goes in its own dedicated register.
577+
let integer_registers_used: usize = call_args
578+
[if has_return_arg { 1 } else { 0 }..fixed_arg_count]
579+
.iter()
580+
.map(|arg| if fx.bcx.func.dfg.value_type(*arg).bits() == 128 { 2 } else { 1 })
581+
.sum();
582+
// The ABI uses 8 registers before it starts pushing arguments to the stack. Pad out
583+
// the registers if needed to ensure the variadic arguments are passed on the stack.
584+
if integer_registers_used < 8 {
585+
call_args.splice(
586+
fixed_arg_count..fixed_arg_count,
587+
(integer_registers_used..8).map(|_| fx.bcx.ins().iconst(types::I64, 0)),
588+
);
589+
}
590+
}
547591

548592
let call_inst = match func_ref {
549593
CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
@@ -561,20 +605,36 @@ pub(crate) fn codegen_terminator_call<'tcx>(
561605
);
562606
}
563607
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
564-
let abi_params = call_args
565-
.into_iter()
566-
.map(|arg| {
567-
let ty = fx.bcx.func.dfg.value_type(arg);
568-
if !ty.is_int() {
569-
// FIXME set %al to upperbound on float args once floats are supported
570-
fx.tcx.dcx().span_fatal(
571-
source_info.span,
572-
format!("Non int ty {:?} for variadic call", ty),
573-
);
574-
}
575-
AbiParam::new(ty)
576-
})
577-
.collect::<Vec<AbiParam>>();
608+
let mut abi_params = mem::take(&mut fx.bcx.func.dfg.signatures[sig_ref].params);
609+
assert_eq!(abi_params.len(), fixed_arg_count);
610+
if fx.tcx.sess.target.is_like_osx && fx.tcx.sess.target.arch == "aarch64" {
611+
// `StructArgument` is not currently used by the `aarch64`, and is therefore not
612+
// handled when calculating how many padding arguments to use. Assert that this
613+
// remains the case.
614+
assert!(abi_params.iter().all(|param| matches!(
615+
param.purpose,
616+
// The only purposes used are `Normal` and `StructReturn`.
617+
ArgumentPurpose::Normal | ArgumentPurpose::StructReturn
618+
)))
619+
}
620+
// Don't replace existing `AbiParam`s as they might have `ArgumentPurpose` or
621+
// `ArgumentExtension`.
622+
abi_params.extend(
623+
call_args
624+
.into_iter()
625+
.map(|arg| {
626+
let ty = fx.bcx.func.dfg.value_type(arg);
627+
if !ty.is_int() {
628+
// FIXME set %al to upperbound on float args once floats are supported
629+
fx.tcx.dcx().span_fatal(
630+
source_info.span,
631+
format!("Non int ty {:?} for variadic call", ty),
632+
);
633+
}
634+
AbiParam::new(ty)
635+
})
636+
.skip(fixed_arg_count),
637+
);
578638
fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
579639
}
580640

0 commit comments

Comments
 (0)