@@ -228,6 +228,33 @@ impl CastTarget {
228228 }
229229}
230230
231+ /// Return value from the `homogeneous_aggregate` test function.
232+ #[ derive( Copy , Clone , Debug ) ]
233+ pub enum HomogeneousAggregate {
234+ /// Yes, all the "leaf fields" of this struct are passed in the
235+ /// same way (specified in the `Reg` value).
236+ Homogeneous ( Reg ) ,
237+
238+ /// There are distinct leaf fields passed in different ways,
239+ /// or this is uninhabited.
240+ Heterogeneous ,
241+
242+ /// There are no leaf fields at all.
243+ NoData ,
244+ }
245+
246+ impl HomogeneousAggregate {
247+ /// If this is a homogeneous aggregate, returns the homogeneous
248+ /// unit, else `None`.
249+ pub fn unit ( self ) -> Option < Reg > {
250+ if let HomogeneousAggregate :: Homogeneous ( r) = self {
251+ Some ( r)
252+ } else {
253+ None
254+ }
255+ }
256+ }
257+
231258impl < ' a , Ty > TyLayout < ' a , Ty > {
232259 fn is_aggregate ( & self ) -> bool {
233260 match self . abi {
@@ -239,11 +266,21 @@ impl<'a, Ty> TyLayout<'a, Ty> {
239266 }
240267 }
241268
242- fn homogeneous_aggregate < C > ( & self , cx : & C ) -> Option < Reg >
269+ /// True if this layout is an aggregate containing fields of only
270+ /// a single type (e.g., `(u32, u32)`). Such aggregates are often
271+ /// special-cased in ABIs.
272+ ///
273+ /// Note: We generally ignore fields of zero-sized type when computing
274+ /// this value (cc #56877).
275+ ///
276+ /// This is public so that it can be used in unit tests, but
277+ /// should generally only be relevant to the ABI details of
278+ /// specific targets.
279+ pub fn homogeneous_aggregate < C > ( & self , cx : & C ) -> HomogeneousAggregate
243280 where Ty : TyLayoutMethods < ' a , C > + Copy , C : LayoutOf < Ty = Ty , TyLayout = Self >
244281 {
245282 match self . abi {
246- Abi :: Uninhabited => None ,
283+ Abi :: Uninhabited => HomogeneousAggregate :: Heterogeneous ,
247284
248285 // The primitive for this algorithm.
249286 Abi :: Scalar ( ref scalar) => {
@@ -252,14 +289,15 @@ impl<'a, Ty> TyLayout<'a, Ty> {
252289 abi:: Pointer => RegKind :: Integer ,
253290 abi:: Float ( _) => RegKind :: Float ,
254291 } ;
255- Some ( Reg {
292+ HomogeneousAggregate :: Homogeneous ( Reg {
256293 kind,
257294 size : self . size
258295 } )
259296 }
260297
261298 Abi :: Vector { .. } => {
262- Some ( Reg {
299+ assert ! ( !self . is_zst( ) ) ;
300+ HomogeneousAggregate :: Homogeneous ( Reg {
263301 kind : RegKind :: Vector ,
264302 size : self . size
265303 } )
@@ -275,7 +313,7 @@ impl<'a, Ty> TyLayout<'a, Ty> {
275313 if count > 0 {
276314 return self . field ( cx, 0 ) . homogeneous_aggregate ( cx) ;
277315 } else {
278- return None ;
316+ return HomogeneousAggregate :: NoData ;
279317 }
280318 }
281319 FieldPlacement :: Union ( _) => true ,
@@ -284,21 +322,27 @@ impl<'a, Ty> TyLayout<'a, Ty> {
284322
285323 for i in 0 ..self . fields . count ( ) {
286324 if !is_union && total != self . fields . offset ( i) {
287- return None ;
325+ return HomogeneousAggregate :: Heterogeneous ;
288326 }
289327
290328 let field = self . field ( cx, i) ;
329+
291330 match ( result, field. homogeneous_aggregate ( cx) ) {
292- // The field itself must be a homogeneous aggregate.
293- ( _, None ) => return None ,
331+ ( _, HomogeneousAggregate :: NoData ) => {
332+ // Ignore fields that have no data
333+ }
334+ ( _, HomogeneousAggregate :: Heterogeneous ) => {
335+ // The field itself must be a homogeneous aggregate.
336+ return HomogeneousAggregate :: Heterogeneous ;
337+ }
294338 // If this is the first field, record the unit.
295- ( None , Some ( unit) ) => {
339+ ( None , HomogeneousAggregate :: Homogeneous ( unit) ) => {
296340 result = Some ( unit) ;
297341 }
298342 // For all following fields, the unit must be the same.
299- ( Some ( prev_unit) , Some ( unit) ) => {
343+ ( Some ( prev_unit) , HomogeneousAggregate :: Homogeneous ( unit) ) => {
300344 if prev_unit != unit {
301- return None ;
345+ return HomogeneousAggregate :: Heterogeneous ;
302346 }
303347 }
304348 }
@@ -314,9 +358,18 @@ impl<'a, Ty> TyLayout<'a, Ty> {
314358
315359 // There needs to be no padding.
316360 if total != self . size {
317- None
361+ HomogeneousAggregate :: Heterogeneous
318362 } else {
319- result
363+ match result {
364+ Some ( reg) => {
365+ assert_ne ! ( total, Size :: ZERO ) ;
366+ HomogeneousAggregate :: Homogeneous ( reg)
367+ }
368+ None => {
369+ assert_eq ! ( total, Size :: ZERO ) ;
370+ HomogeneousAggregate :: NoData
371+ }
372+ }
320373 }
321374 }
322375 }
0 commit comments