@@ -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 ;
@@ -17,6 +18,7 @@ use rustc_middle::ty::TypeVisitableExt;
17
18
use rustc_monomorphize:: is_call_from_compiler_builtins_to_upstream_monomorphization;
18
19
use rustc_session:: Session ;
19
20
use rustc_span:: source_map:: Spanned ;
21
+ use rustc_span:: sym:: assert;
20
22
use rustc_target:: abi:: call:: { Conv , FnAbi } ;
21
23
use rustc_target:: spec:: abi:: Abi ;
22
24
@@ -425,7 +427,8 @@ pub(crate) fn codegen_terminator_call<'tcx>(
425
427
None
426
428
} ;
427
429
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..] ;
429
432
let extra_args = fx. tcx . mk_type_list_from_iter (
430
433
extra_args. iter ( ) . map ( |op_arg| fx. monomorphize ( op_arg. node . ty ( fx. mir , fx. tcx ) ) ) ,
431
434
) ;
@@ -532,18 +535,59 @@ pub(crate) fn codegen_terminator_call<'tcx>(
532
535
} ;
533
536
534
537
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
536
546
. into_iter ( )
537
547
. chain ( first_arg_override. into_iter ( ) )
538
548
. 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 } )
541
553
. skip ( if first_arg_override. is_some ( ) { 1 } else { 0 } )
542
554
. flat_map ( |( i, arg) | {
543
555
adjust_arg_for_abi ( fx, arg. value , & fn_abi. args [ i] , arg. is_owned ) . into_iter ( )
544
556
} ) ,
545
557
)
546
558
. 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
+ }
547
591
548
592
let call_inst = match func_ref {
549
593
CallTarget :: Direct ( func_ref) => fx. bcx . ins ( ) . call ( func_ref, & call_args) ,
@@ -561,20 +605,36 @@ pub(crate) fn codegen_terminator_call<'tcx>(
561
605
) ;
562
606
}
563
607
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
+ ) ;
578
638
fx. bcx . func . dfg . signatures [ sig_ref] . params = abi_params;
579
639
}
580
640
0 commit comments