1
1
use std:: iter;
2
2
3
- use rustc_abi:: Primitive :: { Float , Pointer } ;
4
- use rustc_abi:: { Abi , AddressSpace , PointerKind , Scalar , Size } ;
3
+ use rustc_abi:: Primitive :: Pointer ;
4
+ use rustc_abi:: { Abi , PointerKind , Scalar , Size } ;
5
5
use rustc_hir as hir;
6
6
use rustc_hir:: lang_items:: LangItem ;
7
7
use rustc_middle:: bug;
@@ -13,8 +13,7 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt};
13
13
use rustc_session:: config:: OptLevel ;
14
14
use rustc_span:: def_id:: DefId ;
15
15
use rustc_target:: abi:: call:: {
16
- ArgAbi , ArgAttribute , ArgAttributes , ArgExtension , Conv , FnAbi , PassMode , Reg , RegKind ,
17
- RiscvInterruptKind ,
16
+ ArgAbi , ArgAttribute , ArgAttributes , ArgExtension , Conv , FnAbi , PassMode , RiscvInterruptKind ,
18
17
} ;
19
18
use rustc_target:: spec:: abi:: Abi as SpecAbi ;
20
19
use tracing:: debug;
@@ -678,6 +677,8 @@ fn fn_abi_adjust_for_abi<'tcx>(
678
677
let tcx = cx. tcx ( ) ;
679
678
680
679
if abi == SpecAbi :: Rust || abi == SpecAbi :: RustCall || abi == SpecAbi :: RustIntrinsic {
680
+ fn_abi. adjust_for_rust_abi ( cx, abi) ;
681
+
681
682
// Look up the deduced parameter attributes for this function, if we have its def ID and
682
683
// we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
683
684
// as appropriate.
@@ -688,135 +689,17 @@ fn fn_abi_adjust_for_abi<'tcx>(
688
689
& [ ]
689
690
} ;
690
691
691
- let fixup = | arg : & mut ArgAbi < ' tcx , Ty < ' tcx > > , arg_idx : Option < usize > | {
692
+ for ( arg_idx , arg) in fn_abi . args . iter_mut ( ) . enumerate ( ) {
692
693
if arg. is_ignore ( ) {
693
- return ;
694
- }
695
-
696
- // Avoid returning floats in x87 registers on x86 as loading and storing from x87
697
- // registers will quiet signalling NaNs. Also avoid using SSE registers since they
698
- // are not always available (depending on target features).
699
- if tcx. sess . target . arch == "x86"
700
- && arg_idx. is_none ( )
701
- // Intrinsics themselves are not actual "real" functions, so theres no need to
702
- // change their ABIs.
703
- && abi != SpecAbi :: RustIntrinsic
704
- {
705
- let has_float = match arg. layout . abi {
706
- Abi :: Scalar ( s) => matches ! ( s. primitive( ) , Float ( _) ) ,
707
- Abi :: ScalarPair ( s1, s2) => {
708
- matches ! ( s1. primitive( ) , Float ( _) ) || matches ! ( s2. primitive( ) , Float ( _) )
709
- }
710
- _ => false , // anyway not passed via registers on x86
711
- } ;
712
- if has_float {
713
- if arg. layout . size <= Pointer ( AddressSpace :: DATA ) . size ( cx) {
714
- // Same size or smaller than pointer, return in a register.
715
- arg. cast_to ( Reg { kind : RegKind :: Integer , size : arg. layout . size } ) ;
716
- } else {
717
- // Larger than a pointer, return indirectly.
718
- arg. make_indirect ( ) ;
719
- }
720
- return ;
721
- }
722
- }
723
-
724
- if arg_idx. is_none ( ) && arg. layout . size > Pointer ( AddressSpace :: DATA ) . size ( cx) * 2 {
725
- // Return values larger than 2 registers using a return area
726
- // pointer. LLVM and Cranelift disagree about how to return
727
- // values that don't fit in the registers designated for return
728
- // values. LLVM will force the entire return value to be passed
729
- // by return area pointer, while Cranelift will look at each IR level
730
- // return value independently and decide to pass it in a
731
- // register or not, which would result in the return value
732
- // being passed partially in registers and partially through a
733
- // return area pointer.
734
- //
735
- // While Cranelift may need to be fixed as the LLVM behavior is
736
- // generally more correct with respect to the surface language,
737
- // forcing this behavior in rustc itself makes it easier for
738
- // other backends to conform to the Rust ABI and for the C ABI
739
- // rustc already handles this behavior anyway.
740
- //
741
- // In addition LLVM's decision to pass the return value in
742
- // registers or using a return area pointer depends on how
743
- // exactly the return type is lowered to an LLVM IR type. For
744
- // example `Option<u128>` can be lowered as `{ i128, i128 }`
745
- // in which case the x86_64 backend would use a return area
746
- // pointer, or it could be passed as `{ i32, i128 }` in which
747
- // case the x86_64 backend would pass it in registers by taking
748
- // advantage of an LLVM ABI extension that allows using 3
749
- // registers for the x86_64 sysv call conv rather than the
750
- // officially specified 2 registers.
751
- //
752
- // FIXME: Technically we should look at the amount of available
753
- // return registers rather than guessing that there are 2
754
- // registers for return values. In practice only a couple of
755
- // architectures have less than 2 return registers. None of
756
- // which supported by Cranelift.
757
- //
758
- // NOTE: This adjustment is only necessary for the Rust ABI as
759
- // for other ABI's the calling convention implementations in
760
- // rustc_target already ensure any return value which doesn't
761
- // fit in the available amount of return registers is passed in
762
- // the right way for the current target.
763
- arg. make_indirect ( ) ;
764
- return ;
765
- }
766
-
767
- match arg. layout . abi {
768
- Abi :: Aggregate { .. } => { }
769
-
770
- // This is a fun case! The gist of what this is doing is
771
- // that we want callers and callees to always agree on the
772
- // ABI of how they pass SIMD arguments. If we were to *not*
773
- // make these arguments indirect then they'd be immediates
774
- // in LLVM, which means that they'd used whatever the
775
- // appropriate ABI is for the callee and the caller. That
776
- // means, for example, if the caller doesn't have AVX
777
- // enabled but the callee does, then passing an AVX argument
778
- // across this boundary would cause corrupt data to show up.
779
- //
780
- // This problem is fixed by unconditionally passing SIMD
781
- // arguments through memory between callers and callees
782
- // which should get them all to agree on ABI regardless of
783
- // target feature sets. Some more information about this
784
- // issue can be found in #44367.
785
- //
786
- // Note that the intrinsic ABI is exempt here as
787
- // that's how we connect up to LLVM and it's unstable
788
- // anyway, we control all calls to it in libstd.
789
- Abi :: Vector { .. }
790
- if abi != SpecAbi :: RustIntrinsic && tcx. sess . target . simd_types_indirect =>
791
- {
792
- arg. make_indirect ( ) ;
793
- return ;
794
- }
795
-
796
- _ => return ,
797
- }
798
- // Compute `Aggregate` ABI.
799
-
800
- let is_indirect_not_on_stack =
801
- matches ! ( arg. mode, PassMode :: Indirect { on_stack: false , .. } ) ;
802
- assert ! ( is_indirect_not_on_stack, "{:?}" , arg) ;
803
-
804
- let size = arg. layout . size ;
805
- if !arg. layout . is_unsized ( ) && size <= Pointer ( AddressSpace :: DATA ) . size ( cx) {
806
- // We want to pass small aggregates as immediates, but using
807
- // an LLVM aggregate type for this leads to bad optimizations,
808
- // so we pick an appropriately sized integer type instead.
809
- arg. cast_to ( Reg { kind : RegKind :: Integer , size } ) ;
694
+ continue ;
810
695
}
811
696
812
697
// If we deduced that this parameter was read-only, add that to the attribute list now.
813
698
//
814
699
// The `readonly` parameter only applies to pointers, so we can only do this if the
815
700
// argument was passed indirectly. (If the argument is passed directly, it's an SSA
816
701
// value, so it's implicitly immutable.)
817
- if let ( Some ( arg_idx) , & mut PassMode :: Indirect { ref mut attrs, .. } ) =
818
- ( arg_idx, & mut arg. mode )
819
- {
702
+ if let & mut PassMode :: Indirect { ref mut attrs, .. } = & mut arg. mode {
820
703
// The `deduced_param_attrs` list could be empty if this is a type of function
821
704
// we can't deduce any parameters for, so make sure the argument index is in
822
705
// bounds.
@@ -827,11 +710,6 @@ fn fn_abi_adjust_for_abi<'tcx>(
827
710
}
828
711
}
829
712
}
830
- } ;
831
-
832
- fixup ( & mut fn_abi. ret , None ) ;
833
- for ( arg_idx, arg) in fn_abi. args . iter_mut ( ) . enumerate ( ) {
834
- fixup ( arg, Some ( arg_idx) ) ;
835
713
}
836
714
} else {
837
715
fn_abi
0 commit comments