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