@@ -86,11 +86,91 @@ fn ty_size(ty: Type) -> usize {
86
86
}
87
87
}
88
88
89
+ fn is_homogenous_aggregate_ty ( ty : Type ) -> Option < ( Type , u64 ) > {
90
+ fn check_array ( ty : Type ) -> Option < ( Type , u64 ) > {
91
+ let len = ty. array_length ( ) as u64 ;
92
+ if len == 0 {
93
+ return None
94
+ }
95
+ let elt = ty. element_type ( ) ;
96
+
97
+ // if our element is an HFA/HVA, so are we; multiply members by our len
98
+ is_homogenous_aggregate_ty ( elt) . map ( |( base_ty, members) | ( base_ty, len * members) )
99
+ }
100
+
101
+ fn check_struct ( ty : Type ) -> Option < ( Type , u64 ) > {
102
+ let str_tys = ty. field_types ( ) ;
103
+ if str_tys. len ( ) == 0 {
104
+ return None
105
+ }
106
+
107
+ let mut prev_base_ty = None ;
108
+ let mut members = 0 ;
109
+ for opt_homog_agg in str_tys. iter ( ) . map ( |t| is_homogenous_aggregate_ty ( * t) ) {
110
+ match ( prev_base_ty, opt_homog_agg) {
111
+ // field isn't itself an HFA, so we aren't either
112
+ ( _, None ) => return None ,
113
+
114
+ // first field - store its type and number of members
115
+ ( None , Some ( ( field_ty, field_members) ) ) => {
116
+ prev_base_ty = Some ( field_ty) ;
117
+ members = field_members;
118
+ } ,
119
+
120
+ // 2nd or later field - give up if it's a different type; otherwise incr. members
121
+ ( Some ( prev_ty) , Some ( ( field_ty, field_members) ) ) => {
122
+ if prev_ty != field_ty {
123
+ return None ;
124
+ }
125
+ members += field_members;
126
+ }
127
+ }
128
+ }
129
+
130
+ // Because of previous checks, we know prev_base_ty is Some(...) because
131
+ // 1. str_tys has at least one element; and
132
+ // 2. prev_base_ty was filled in (or we would've returned early)
133
+ let ( base_ty, members) = ( prev_base_ty. unwrap ( ) , members) ;
134
+
135
+ // Ensure there is no padding.
136
+ if ty_size ( ty) == ty_size ( base_ty) * ( members as usize ) {
137
+ Some ( ( base_ty, members) )
138
+ } else {
139
+ None
140
+ }
141
+ }
142
+
143
+ let homog_agg = match ty. kind ( ) {
144
+ Float => Some ( ( ty, 1 ) ) ,
145
+ Double => Some ( ( ty, 1 ) ) ,
146
+ Array => check_array ( ty) ,
147
+ Struct => check_struct ( ty) ,
148
+ Vector => match ty_size ( ty) {
149
+ 4 |8 => Some ( ( ty, 1 ) ) ,
150
+ _ => None
151
+ } ,
152
+ _ => None
153
+ } ;
154
+
155
+ // Ensure we have at most four uniquely addressable members
156
+ homog_agg. and_then ( |( base_ty, members) | {
157
+ if members > 0 && members <= 4 {
158
+ Some ( ( base_ty, members) )
159
+ } else {
160
+ None
161
+ }
162
+ } )
163
+ }
164
+
89
165
fn classify_ret_ty ( ccx : & CrateContext , ty : Type ) -> ArgType {
90
166
if is_reg_ty ( ty) {
91
167
let attr = if ty == Type :: i1 ( ccx) { Some ( ZExtAttribute ) } else { None } ;
92
168
return ArgType :: direct ( ty, None , None , attr) ;
93
169
}
170
+ if let Some ( ( base_ty, members) ) = is_homogenous_aggregate_ty ( ty) {
171
+ let llty = Type :: array ( & base_ty, members) ;
172
+ return ArgType :: direct ( ty, Some ( llty) , None , None ) ;
173
+ }
94
174
let size = ty_size ( ty) ;
95
175
if size <= 16 {
96
176
let llty = if size <= 1 {
@@ -114,6 +194,10 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
114
194
let attr = if ty == Type :: i1 ( ccx) { Some ( ZExtAttribute ) } else { None } ;
115
195
return ArgType :: direct ( ty, None , None , attr) ;
116
196
}
197
+ if let Some ( ( base_ty, members) ) = is_homogenous_aggregate_ty ( ty) {
198
+ let llty = Type :: array ( & base_ty, members) ;
199
+ return ArgType :: direct ( ty, Some ( llty) , None , None ) ;
200
+ }
117
201
let size = ty_size ( ty) ;
118
202
if size <= 16 {
119
203
let llty = if size == 0 {
0 commit comments