11// FIXME: This needs an audit for correctness and completeness.
22
3- use crate :: abi:: call:: { ArgAbi , FnAbi , Reg , RegKind , Uniform } ;
4- use crate :: abi:: { HasDataLayout , TyAbiInterface } ;
3+ use crate :: abi:: call:: {
4+ ArgAbi , ArgAttribute , ArgAttributes , ArgExtension , CastTarget , FnAbi , Reg , RegKind , Uniform ,
5+ } ;
6+ use crate :: abi:: { self , HasDataLayout , Size , TyAbiInterface } ;
57
68fn is_homogeneous_aggregate < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > ) -> Option < Uniform >
79where
@@ -16,41 +18,15 @@ where
1618
1719 let valid_unit = match unit. kind {
1820 RegKind :: Integer => false ,
19- RegKind :: Float => true ,
21+ RegKind :: Float => false ,
2022 RegKind :: Vector => arg. layout . size . bits ( ) == 128 ,
2123 } ;
2224
2325 valid_unit. then_some ( Uniform { unit, total : arg. layout . size } )
2426 } )
2527}
2628
27- fn classify_ret < ' a , Ty , C > ( cx : & C , ret : & mut ArgAbi < ' a , Ty > )
28- where
29- Ty : TyAbiInterface < ' a , C > + Copy ,
30- C : HasDataLayout ,
31- {
32- if !ret. layout . is_aggregate ( ) {
33- ret. extend_integer_width_to ( 64 ) ;
34- return ;
35- }
36-
37- if let Some ( uniform) = is_homogeneous_aggregate ( cx, ret) {
38- ret. cast_to ( uniform) ;
39- return ;
40- }
41- let size = ret. layout . size ;
42- let bits = size. bits ( ) ;
43- if bits <= 256 {
44- let unit = Reg :: i64 ( ) ;
45- ret. cast_to ( Uniform { unit, total : size } ) ;
46- return ;
47- }
48-
49- // don't return aggregates in registers
50- ret. make_indirect ( ) ;
51- }
52-
53- fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > )
29+ fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > , in_registers_max : Size )
5430where
5531 Ty : TyAbiInterface < ' a , C > + Copy ,
5632 C : HasDataLayout ,
@@ -60,13 +36,97 @@ where
6036 return ;
6137 }
6238
39+ // This doesn't intentionally handle structures with floats which needs
40+ // special care below.
6341 if let Some ( uniform) = is_homogeneous_aggregate ( cx, arg) {
6442 arg. cast_to ( uniform) ;
6543 return ;
6644 }
6745
46+ if let abi:: FieldsShape :: Arbitrary { .. } = arg. layout . fields {
47+ let dl = cx. data_layout ( ) ;
48+ let size = arg. layout . size ;
49+ let mut prefix = [ None ; 8 ] ;
50+ let mut prefix_index = 0 ;
51+ let mut last_offset = Size :: ZERO ;
52+ let mut has_float = false ;
53+ let mut arg_attribute = ArgAttribute :: default ( ) ;
54+
55+ for i in 0 ..arg. layout . fields . count ( ) {
56+ let field = arg. layout . field ( cx, i) ;
57+ let offset = arg. layout . fields . offset ( i) ;
58+
59+ if let abi:: Abi :: Scalar ( scalar) = & field. abi {
60+ if scalar. value == abi:: F32 || scalar. value == abi:: F64 {
61+ has_float = true ;
62+
63+ if !last_offset. is_aligned ( dl. f64_align . abi ) && last_offset < offset {
64+ if prefix_index == prefix. len ( ) {
65+ break ;
66+ }
67+ prefix[ prefix_index] = Some ( Reg :: i32 ( ) ) ;
68+ prefix_index += 1 ;
69+ last_offset = last_offset + Reg :: i32 ( ) . size ;
70+ }
71+
72+ for _ in 0 ..( ( offset - last_offset) . bits ( ) / 64 )
73+ . min ( ( prefix. len ( ) - prefix_index) as u64 )
74+ {
75+ prefix[ prefix_index] = Some ( Reg :: i64 ( ) ) ;
76+ prefix_index += 1 ;
77+ last_offset = last_offset + Reg :: i64 ( ) . size ;
78+ }
79+
80+ if last_offset < offset {
81+ if prefix_index == prefix. len ( ) {
82+ break ;
83+ }
84+ prefix[ prefix_index] = Some ( Reg :: i32 ( ) ) ;
85+ prefix_index += 1 ;
86+ last_offset = last_offset + Reg :: i32 ( ) . size ;
87+ }
88+
89+ if prefix_index == prefix. len ( ) {
90+ break ;
91+ }
92+
93+ if scalar. value == abi:: F32 {
94+ arg_attribute = ArgAttribute :: InReg ;
95+ prefix[ prefix_index] = Some ( Reg :: f32 ( ) ) ;
96+ last_offset = offset + Reg :: f32 ( ) . size ;
97+ } else {
98+ prefix[ prefix_index] = Some ( Reg :: f64 ( ) ) ;
99+ last_offset = offset + Reg :: f64 ( ) . size ;
100+ }
101+ prefix_index += 1 ;
102+ }
103+ }
104+ }
105+
106+ if has_float && arg. layout . size <= in_registers_max {
107+ let mut rest_size = size - last_offset;
108+
109+ if ( rest_size. raw % 8 ) != 0 && prefix_index < prefix. len ( ) {
110+ prefix[ prefix_index] = Some ( Reg :: i32 ( ) ) ;
111+ rest_size = rest_size - Reg :: i32 ( ) . size ;
112+ }
113+
114+ arg. cast_to ( CastTarget {
115+ prefix,
116+ rest : Uniform { unit : Reg :: i64 ( ) , total : rest_size } ,
117+ attrs : ArgAttributes {
118+ regular : arg_attribute,
119+ arg_ext : ArgExtension :: None ,
120+ pointee_size : Size :: ZERO ,
121+ pointee_align : None ,
122+ } ,
123+ } ) ;
124+ return ;
125+ }
126+ }
127+
68128 let total = arg. layout . size ;
69- if total. bits ( ) > 128 {
129+ if total > in_registers_max {
70130 arg. make_indirect ( ) ;
71131 return ;
72132 }
@@ -80,13 +140,13 @@ where
80140 C : HasDataLayout ,
81141{
82142 if !fn_abi. ret . is_ignore ( ) {
83- classify_ret ( cx, & mut fn_abi. ret ) ;
143+ classify_arg ( cx, & mut fn_abi. ret , Size { raw : 32 } ) ;
84144 }
85145
86146 for arg in & mut fn_abi. args {
87147 if arg. is_ignore ( ) {
88148 continue ;
89149 }
90- classify_arg ( cx, arg) ;
150+ classify_arg ( cx, arg, Size { raw : 16 } ) ;
91151 }
92152}
0 commit comments