@@ -5,8 +5,9 @@ mod pass_mode;
55mod returning;
66
77use std:: borrow:: Cow ;
8+ use std:: mem;
89
9- use cranelift_codegen:: ir:: SigRef ;
10+ use cranelift_codegen:: ir:: { ArgumentPurpose , SigRef } ;
1011use cranelift_codegen:: isa:: CallConv ;
1112use cranelift_module:: ModuleError ;
1213use rustc_codegen_ssa:: errors:: CompilerBuiltinsCannotCall ;
@@ -17,7 +18,7 @@ use rustc_middle::ty::TypeVisitableExt;
1718use rustc_monomorphize:: is_call_from_compiler_builtins_to_upstream_monomorphization;
1819use rustc_session:: Session ;
1920use rustc_span:: source_map:: Spanned ;
20- use rustc_target:: abi:: call:: { Conv , FnAbi } ;
21+ use rustc_target:: abi:: call:: { Conv , FnAbi , PassMode } ;
2122use rustc_target:: spec:: abi:: Abi ;
2223
2324use self :: pass_mode:: * ;
@@ -487,6 +488,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
487488 let args = args;
488489 assert_eq ! ( fn_abi. args. len( ) , args. len( ) ) ;
489490
491+ #[ derive( Copy , Clone ) ]
490492 enum CallTarget {
491493 Direct ( FuncRef ) ,
492494 Indirect ( SigRef , Value ) ,
@@ -532,7 +534,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
532534 } ;
533535
534536 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
536538 . into_iter ( )
537539 . chain ( first_arg_override. into_iter ( ) )
538540 . chain (
@@ -545,47 +547,118 @@ pub(crate) fn codegen_terminator_call<'tcx>(
545547 )
546548 . collect :: < Vec < Value > > ( ) ;
547549
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 {
549556 CallTarget :: Direct ( func_ref) => fx. bcx . ins ( ) . call ( func_ref, & call_args) ,
550557 CallTarget :: Indirect ( sig, func_ptr) => {
551558 fx. bcx . ins ( ) . call_indirect ( sig, func_ptr, & call_args)
552559 }
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,
553586 } ;
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+ ) ;
554607
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.
558651 fx. tcx . dcx ( ) . span_fatal (
559652 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 ) ,
561654 ) ;
562655 }
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;
579656 }
580657
581- call_inst
582- } ) ;
658+ assert_eq ! ( abi_params. len( ) , call_args. len( ) ) ;
583659
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;
589662 }
590663}
591664
0 commit comments