@@ -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,7 +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 ;
20
- use rustc_target:: abi:: call:: { Conv , FnAbi } ;
21
+ use rustc_target:: abi:: call:: { Conv , FnAbi , PassMode } ;
21
22
use rustc_target:: spec:: abi:: Abi ;
22
23
23
24
use self :: pass_mode:: * ;
@@ -487,6 +488,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
487
488
let args = args;
488
489
assert_eq ! ( fn_abi. args. len( ) , args. len( ) ) ;
489
490
491
+ #[ derive( Copy , Clone ) ]
490
492
enum CallTarget {
491
493
Direct ( FuncRef ) ,
492
494
Indirect ( SigRef , Value ) ,
@@ -532,7 +534,7 @@ 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
+ let mut call_args = return_ptr
536
538
. into_iter ( )
537
539
. chain ( first_arg_override. into_iter ( ) )
538
540
. chain (
@@ -545,47 +547,118 @@ pub(crate) fn codegen_terminator_call<'tcx>(
545
547
)
546
548
. collect :: < Vec < Value > > ( ) ;
547
549
548
- let call_inst = match func_ref {
550
+ // FIXME: Find a cleaner way to support varargs.
551
+ if fn_abi. c_variadic {
552
+ adjust_call_for_c_variadic ( fx, & fn_abi, source_info, func_ref, & mut call_args) ;
553
+ }
554
+
555
+ match func_ref {
549
556
CallTarget :: Direct ( func_ref) => fx. bcx . ins ( ) . call ( func_ref, & call_args) ,
550
557
CallTarget :: Indirect ( sig, func_ptr) => {
551
558
fx. bcx . ins ( ) . call_indirect ( sig, func_ptr, & call_args)
552
559
}
560
+ }
561
+ } ) ;
562
+
563
+ if let Some ( dest) = target {
564
+ let ret_block = fx. get_block ( dest) ;
565
+ fx. bcx . ins ( ) . jump ( ret_block, & [ ] ) ;
566
+ } else {
567
+ fx. bcx . ins ( ) . trap ( TrapCode :: UnreachableCodeReached ) ;
568
+ }
569
+
570
+ fn adjust_call_for_c_variadic < ' tcx > (
571
+ fx : & mut FunctionCx < ' _ , ' _ , ' tcx > ,
572
+ fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
573
+ source_info : mir:: SourceInfo ,
574
+ target : CallTarget ,
575
+ call_args : & mut Vec < Value > ,
576
+ ) {
577
+ if fn_abi. conv != Conv :: C {
578
+ fx. tcx . dcx ( ) . span_fatal (
579
+ source_info. span ,
580
+ format ! ( "Variadic call for non-C abi {:?}" , fn_abi. conv) ,
581
+ ) ;
582
+ }
583
+ let sig_ref = match target {
584
+ CallTarget :: Direct ( func_ref) => fx. bcx . func . dfg . ext_funcs [ func_ref] . signature ,
585
+ CallTarget :: Indirect ( sig_ref, _) => sig_ref,
553
586
} ;
587
+ // `mem::take()` the `params` so that `fx.bcx` can be used below.
588
+ let mut abi_params = mem:: take ( & mut fx. bcx . func . dfg . signatures [ sig_ref] . params ) ;
589
+
590
+ // Recalculate the parameters in the signature to ensure the signature contains the variadic arguments.
591
+ let has_return_arg = matches ! ( fn_abi. ret. mode, PassMode :: Indirect { .. } ) ;
592
+ // Drop everything except the return argument (if there is one).
593
+ abi_params. truncate ( if has_return_arg { 1 } else { 0 } ) ;
594
+ // Add the fixed arguments.
595
+ abi_params. extend (
596
+ fn_abi. args [ ..fn_abi. fixed_count as usize ]
597
+ . iter ( )
598
+ . flat_map ( |arg_abi| arg_abi. get_abi_param ( fx. tcx ) . into_iter ( ) ) ,
599
+ ) ;
600
+ let fixed_arg_count = abi_params. len ( ) ;
601
+ // Add the variadic arguments.
602
+ abi_params. extend (
603
+ fn_abi. args [ fn_abi. fixed_count as usize ..]
604
+ . iter ( )
605
+ . flat_map ( |arg_abi| arg_abi. get_abi_param ( fx. tcx ) . into_iter ( ) ) ,
606
+ ) ;
554
607
555
- // FIXME find a cleaner way to support varargs
556
- if fn_sig. c_variadic ( ) {
557
- if !matches ! ( fn_sig. abi( ) , Abi :: C { .. } ) {
608
+ if fx. tcx . sess . target . is_like_osx && fx. tcx . sess . target . arch == "aarch64" {
609
+ // Add any padding arguments needed for Apple AArch64.
610
+ // There's no need to pad the argument list unless variadic arguments are actually being
611
+ // passed.
612
+ if abi_params. len ( ) > fixed_arg_count {
613
+ // 128-bit integers take 2 registers, and everything else takes 1.
614
+ // FIXME: Add support for non-integer types
615
+ // This relies on the checks below to ensure all arguments are integer types and
616
+ // that the ABI is "C".
617
+ // The return argument isn't counted as it goes in its own dedicated register.
618
+ let integer_registers_used: usize = abi_params
619
+ [ if has_return_arg { 1 } else { 0 } ..fixed_arg_count]
620
+ . iter ( )
621
+ . map ( |arg| if arg. value_type . bits ( ) == 128 { 2 } else { 1 } )
622
+ . sum ( ) ;
623
+ // The ABI uses 8 registers before it starts pushing arguments to the stack. Pad out
624
+ // the registers if needed to ensure the variadic arguments are passed on the stack.
625
+ if integer_registers_used < 8 {
626
+ abi_params. splice (
627
+ fixed_arg_count..fixed_arg_count,
628
+ ( integer_registers_used..8 ) . map ( |_| AbiParam :: new ( types:: I64 ) ) ,
629
+ ) ;
630
+ call_args. splice (
631
+ fixed_arg_count..fixed_arg_count,
632
+ ( integer_registers_used..8 ) . map ( |_| fx. bcx . ins ( ) . iconst ( types:: I64 , 0 ) ) ,
633
+ ) ;
634
+ }
635
+ }
636
+
637
+ // `StructArgument` is not currently used by the `aarch64` ABI, and is therefore not
638
+ // handled when calculating how many padding arguments to use. Assert that this remains
639
+ // the case.
640
+ assert ! ( abi_params. iter( ) . all( |param| matches!(
641
+ param. purpose,
642
+ // The only purposes used are `Normal` and `StructReturn`.
643
+ ArgumentPurpose :: Normal | ArgumentPurpose :: StructReturn
644
+ ) ) ) ;
645
+ }
646
+
647
+ // Check all parameters are integers.
648
+ for param in abi_params. iter ( ) {
649
+ if !param. value_type . is_int ( ) {
650
+ // FIXME: Set %al to upperbound on float args once floats are supported.
558
651
fx. tcx . dcx ( ) . span_fatal (
559
652
source_info. span ,
560
- format ! ( "Variadic call for non-C abi {:?}" , fn_sig . abi ( ) ) ,
653
+ format ! ( "Non int ty {:?} for variadic call " , param . value_type ) ,
561
654
) ;
562
655
}
563
- 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;
579
656
}
580
657
581
- call_inst
582
- } ) ;
658
+ assert_eq ! ( abi_params. len( ) , call_args. len( ) ) ;
583
659
584
- if let Some ( dest) = target {
585
- let ret_block = fx. get_block ( dest) ;
586
- fx. bcx . ins ( ) . jump ( ret_block, & [ ] ) ;
587
- } else {
588
- fx. bcx . ins ( ) . trap ( TrapCode :: UnreachableCodeReached ) ;
660
+ // Put the `AbiParam`s back in the signature.
661
+ fx. bcx . func . dfg . signatures [ sig_ref] . params = abi_params;
589
662
}
590
663
}
591
664
0 commit comments