@@ -6,7 +6,7 @@ mod returning;
6
6
7
7
use std:: borrow:: Cow ;
8
8
9
- use cranelift_codegen:: ir:: SigRef ;
9
+ use cranelift_codegen:: ir:: { ArgumentPurpose , SigRef } ;
10
10
use cranelift_codegen:: isa:: CallConv ;
11
11
use cranelift_module:: ModuleError ;
12
12
use rustc_codegen_ssa:: errors:: CompilerBuiltinsCannotCall ;
@@ -532,18 +532,64 @@ pub(crate) fn codegen_terminator_call<'tcx>(
532
532
} ;
533
533
534
534
self :: returning:: codegen_with_call_return_arg ( fx, & fn_abi. ret , ret_place, |fx, return_ptr| {
535
- let call_args = return_ptr
535
+ // The majority of this block is hacky workarounds for cranelift not supporting C variadic
536
+ // functions. The only bits that aren't are the `let mut call_args =` statement (excluding
537
+ // the `.take()`; `(&mut args_iter)` can be replace with `args.into_iter().enumerate()`)
538
+ // and the `let call_inst = ` statement.
539
+
540
+ let has_return_arg = return_ptr. is_some ( ) ;
541
+ let mut args_iter = args. into_iter ( ) . enumerate ( ) ;
542
+ let mut call_args = return_ptr
536
543
. into_iter ( )
537
544
. chain ( first_arg_override. into_iter ( ) )
538
545
. chain (
539
- args. into_iter ( )
540
- . enumerate ( )
546
+ ( & mut args_iter)
547
+ // If the function is variadic, only add the fixed argument first so that how
548
+ // many `Value`s the fixed arguments expand to can be counted.
549
+ . take ( fn_abi. fixed_count as usize )
541
550
. skip ( if first_arg_override. is_some ( ) { 1 } else { 0 } )
542
551
. flat_map ( |( i, arg) | {
543
552
adjust_arg_for_abi ( fx, arg. value , & fn_abi. args [ i] , arg. is_owned ) . into_iter ( )
544
553
} ) ,
545
554
)
546
555
. collect :: < Vec < Value > > ( ) ;
556
+ // Count how many `Value`s represent the fixed arguments.
557
+ let fixed_arg_count = call_args. len ( ) ;
558
+ // Add the rest of the arguments. This is a no-op unless the function is variadic.
559
+ call_args. extend ( args_iter. flat_map ( |( i, arg) | {
560
+ adjust_arg_for_abi ( fx, arg. value , & fn_abi. args [ i] , arg. is_owned ) . into_iter ( )
561
+ } ) ) ;
562
+
563
+ let padding_arg_count = if fx. tcx . sess . target . is_like_osx
564
+ && fx. tcx . sess . target . arch == "aarch64"
565
+ && fn_sig. c_variadic ( )
566
+ // No need to pad the argument list unless variadic arguments are actually being passed.
567
+ && call_args. len ( ) > fixed_arg_count
568
+ {
569
+ // 128-bit integers take 2 registers, and everything else takes 1.
570
+ // FIXME: Add support for non-integer types
571
+ // This relies on the checks below to ensure all arguments are integer types and that
572
+ // the ABI is "C".
573
+ // The return argument isn't counted as it goes in its own dedicated register.
574
+ let integer_registers_used: usize = call_args
575
+ [ if has_return_arg { 1 } else { 0 } ..fixed_arg_count]
576
+ . iter ( )
577
+ . map ( |arg| if fx. bcx . func . dfg . value_type ( * arg) . bits ( ) == 128 { 2 } else { 1 } )
578
+ . sum ( ) ;
579
+ // The ABI uses 8 registers before it starts pushing arguments to the stack. Pad out
580
+ // the registers if needed to ensure the variadic arguments are passed on the stack.
581
+ if integer_registers_used < 8 {
582
+ call_args. splice (
583
+ fixed_arg_count..fixed_arg_count,
584
+ ( integer_registers_used..8 ) . map ( |_| fx. bcx . ins ( ) . iconst ( types:: I64 , 0 ) ) ,
585
+ ) ;
586
+ 8 - integer_registers_used
587
+ } else {
588
+ 0
589
+ }
590
+ } else {
591
+ 0
592
+ } ;
547
593
548
594
let call_inst = match func_ref {
549
595
CallTarget :: Direct ( func_ref) => fx. bcx . ins ( ) . call ( func_ref, & call_args) ,
@@ -561,21 +607,37 @@ pub(crate) fn codegen_terminator_call<'tcx>(
561
607
) ;
562
608
}
563
609
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 > > ( ) ;
578
- fx. bcx . func . dfg . signatures [ sig_ref] . params = abi_params;
610
+ // Ensure the signature includes all the extra arguments.
611
+ fx. bcx . func . dfg . signatures [ sig_ref] =
612
+ clif_sig_from_fn_abi ( fx. tcx , fx. target_config . default_call_conv , & fn_abi) ;
613
+ // Add any padding arguments needed for Apple AArch64.
614
+ fx. bcx . func . dfg . signatures [ sig_ref] . params . splice (
615
+ fixed_arg_count..fixed_arg_count,
616
+ ( 0 ..padding_arg_count) . map ( |_| AbiParam :: new ( types:: I64 ) ) ,
617
+ ) ;
618
+ // Check all parameters are integers.
619
+ for param in & fx. bcx . func . dfg . signatures [ sig_ref] . params {
620
+ if !param. value_type . is_int ( ) {
621
+ // FIXME set %al to upperbound on float args once floats are supported
622
+ fx. tcx . dcx ( ) . span_fatal (
623
+ source_info. span ,
624
+ format ! ( "Non int ty {:?} for variadic call" , param. value_type) ,
625
+ ) ;
626
+ }
627
+ }
628
+
629
+ if fx. tcx . sess . target . is_like_osx && fx. tcx . sess . target . arch == "aarch64" {
630
+ // `StructArgument` is not currently used by the `aarch64`, and is therefore not
631
+ // handled when calculating how many padding arguments to use. Assert that this
632
+ // remains the case.
633
+ assert ! ( fx. bcx. func. dfg. signatures[ sig_ref] . params. iter( ) . all( |param| matches!(
634
+ param. purpose,
635
+ // The only purposes used are `Normal` and `StructReturn`.
636
+ ArgumentPurpose :: Normal | ArgumentPurpose :: StructReturn
637
+ ) ) )
638
+ }
639
+
640
+ assert_eq ! ( fx. bcx. func. dfg. signatures[ sig_ref] . params. len( ) , call_args. len( ) ) ;
579
641
}
580
642
581
643
call_inst
0 commit comments