@@ -18,6 +18,7 @@ use syntax_pos::DUMMY_SP;
1818use std:: cmp;
1919use std:: fmt;
2020use std:: i128;
21+ use std:: iter;
2122use std:: mem;
2223
2324use ich:: StableHashingContext ;
@@ -813,11 +814,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
813814 if let Some ( i) = dataful_variant {
814815 let count = ( niche_variants. end ( ) - niche_variants. start ( ) + 1 ) as u128 ;
815816 for ( field_index, & field) in variants[ i] . iter ( ) . enumerate ( ) {
816- let ( offset, niche, niche_start) =
817- match self . find_niche ( field, count) ? {
818- Some ( niche) => niche,
819- None => continue
820- } ;
817+ let niche = match self . find_niche ( field) ? {
818+ Some ( niche) => niche,
819+ _ => continue ,
820+ } ;
821+ let ( niche_start, niche_scalar) = match niche. reserve ( self , count) {
822+ Some ( pair) => pair,
823+ None => continue ,
824+ } ;
825+
821826 let mut align = dl. aggregate_align ;
822827 let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
823828 let mut st = univariant_uninterned ( v,
@@ -829,21 +834,27 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
829834 Ok ( st)
830835 } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
831836
832- let offset = st[ i] . fields . offset ( field_index) + offset;
837+ let offset = st[ i] . fields . offset ( field_index) + niche . offset ;
833838 let size = st[ i] . size ;
834839
835840 let mut abi = match st[ i] . abi {
836- Abi :: Scalar ( _) => Abi :: Scalar ( niche . clone ( ) ) ,
841+ Abi :: Scalar ( _) => Abi :: Scalar ( niche_scalar . clone ( ) ) ,
837842 Abi :: ScalarPair ( ref first, ref second) => {
838843 // We need to use scalar_unit to reset the
839844 // valid range to the maximal one for that
840845 // primitive, because only the niche is
841846 // guaranteed to be initialised, not the
842847 // other primitive.
843848 if offset. bytes ( ) == 0 {
844- Abi :: ScalarPair ( niche. clone ( ) , scalar_unit ( second. value ) )
849+ Abi :: ScalarPair (
850+ niche_scalar. clone ( ) ,
851+ scalar_unit ( second. value ) ,
852+ )
845853 } else {
846- Abi :: ScalarPair ( scalar_unit ( first. value ) , niche. clone ( ) )
854+ Abi :: ScalarPair (
855+ scalar_unit ( first. value ) ,
856+ niche_scalar. clone ( ) ,
857+ )
847858 }
848859 }
849860 _ => Abi :: Aggregate { sized : true } ,
@@ -857,7 +868,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
857868 variants : Variants :: NicheFilling {
858869 dataful_variant : i,
859870 niche_variants,
860- niche,
871+ niche : niche_scalar ,
861872 niche_start,
862873 variants : st,
863874 } ,
@@ -1674,40 +1685,56 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
16741685 }
16751686}
16761687
1688+ struct Niche {
1689+ offset : Size ,
1690+ scalar : Scalar ,
1691+ available : u128 ,
1692+ }
1693+
1694+ impl Niche {
1695+ fn reserve < ' a , ' tcx > (
1696+ & self ,
1697+ cx : LayoutCx < ' tcx , TyCtxt < ' a , ' tcx , ' tcx > > ,
1698+ count : u128 ,
1699+ ) -> Option < ( u128 , Scalar ) > {
1700+ if count > self . available {
1701+ return None ;
1702+ }
1703+ let Scalar { value, valid_range : ref v } = self . scalar ;
1704+ let bits = value. size ( cx) . bits ( ) ;
1705+ assert ! ( bits <= 128 ) ;
1706+ let max_value = !0u128 >> ( 128 - bits) ;
1707+ let start = v. end ( ) . wrapping_add ( 1 ) & max_value;
1708+ let end = v. end ( ) . wrapping_add ( count) & max_value;
1709+ Some ( ( start, Scalar { value, valid_range : * v. start ( ) ..=end } ) )
1710+ }
1711+ }
1712+
16771713impl < ' a , ' tcx > LayoutCx < ' tcx , TyCtxt < ' a , ' tcx , ' tcx > > {
16781714 /// Find the offset of a niche leaf field, starting from
1679- /// the given type and recursing through aggregates, which
1680- /// has at least `count` consecutive invalid values.
1681- /// The tuple is `(offset, scalar, niche_value)`.
1715+ /// the given type and recursing through aggregates.
16821716 // FIXME(eddyb) traverse already optimized enums.
1683- fn find_niche ( self , layout : TyLayout < ' tcx > , count : u128 )
1684- -> Result < Option < ( Size , Scalar , u128 ) > , LayoutError < ' tcx > >
1685- {
1686- let scalar_component = |scalar : & Scalar , offset| {
1717+ fn find_niche ( self , layout : TyLayout < ' tcx > ) -> Result < Option < Niche > , LayoutError < ' tcx > > {
1718+ let scalar_niche = |scalar : & Scalar , offset| {
16871719 let Scalar { value, valid_range : ref v } = * scalar;
16881720
16891721 let bits = value. size ( self ) . bits ( ) ;
16901722 assert ! ( bits <= 128 ) ;
16911723 let max_value = !0u128 >> ( 128 - bits) ;
16921724
16931725 // Find out how many values are outside the valid range.
1694- let niches = if v. start ( ) <= v. end ( ) {
1726+ let available = if v. start ( ) <= v. end ( ) {
16951727 v. start ( ) + ( max_value - v. end ( ) )
16961728 } else {
16971729 v. start ( ) - v. end ( ) - 1
16981730 } ;
16991731
1700- // Give up if we can't fit `count` consecutive niches .
1701- if count > niches {
1732+ // Give up if there is no niche value available .
1733+ if available == 0 {
17021734 return None ;
17031735 }
17041736
1705- let niche_start = v. end ( ) . wrapping_add ( 1 ) & max_value;
1706- let niche_end = v. end ( ) . wrapping_add ( count) & max_value;
1707- Some ( ( offset, Scalar {
1708- value,
1709- valid_range : * v. start ( ) ..=niche_end
1710- } , niche_start) )
1737+ Some ( Niche { offset, scalar : scalar. clone ( ) , available } )
17111738 } ;
17121739
17131740 // Locals variables which live across yields are stored
@@ -1719,15 +1746,19 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
17191746
17201747 match layout. abi {
17211748 Abi :: Scalar ( ref scalar) => {
1722- return Ok ( scalar_component ( scalar, Size :: from_bytes ( 0 ) ) ) ;
1749+ return Ok ( scalar_niche ( scalar, Size :: from_bytes ( 0 ) ) ) ;
17231750 }
17241751 Abi :: ScalarPair ( ref a, ref b) => {
1725- return Ok ( scalar_component ( a, Size :: from_bytes ( 0 ) ) . or_else ( || {
1726- scalar_component ( b, a. value . size ( self ) . abi_align ( b. value . align ( self ) ) )
1727- } ) ) ;
1752+ // HACK(nox): We iter on `b` and then `a` because `max_by_key`
1753+ // returns the last maximum.
1754+ let niche = iter:: once ( ( b, a. value . size ( self ) . abi_align ( b. value . align ( self ) ) ) )
1755+ . chain ( iter:: once ( ( a, Size :: from_bytes ( 0 ) ) ) )
1756+ . filter_map ( |( scalar, offset) | scalar_niche ( scalar, offset) )
1757+ . max_by_key ( |niche| niche. available ) ;
1758+ return Ok ( niche) ;
17281759 }
17291760 Abi :: Vector { ref element, .. } => {
1730- return Ok ( scalar_component ( element, Size :: from_bytes ( 0 ) ) ) ;
1761+ return Ok ( scalar_niche ( element, Size :: from_bytes ( 0 ) ) ) ;
17311762 }
17321763 _ => { }
17331764 }
@@ -1742,17 +1773,23 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
17421773 }
17431774 if let FieldPlacement :: Array { .. } = layout. fields {
17441775 if layout. fields . count ( ) > 0 {
1745- return self . find_niche ( layout. field ( self , 0 ) ?, count) ;
1776+ return self . find_niche ( layout. field ( self , 0 ) ?) ;
1777+ } else {
1778+ return Ok ( None ) ;
17461779 }
17471780 }
1781+ let mut niche = None ;
1782+ let mut available = 0 ;
17481783 for i in 0 ..layout. fields . count ( ) {
1749- let r = self . find_niche ( layout. field ( self , i) ?, count) ?;
1750- if let Some ( ( offset, scalar, niche_value) ) = r {
1751- let offset = layout. fields . offset ( i) + offset;
1752- return Ok ( Some ( ( offset, scalar, niche_value) ) ) ;
1784+ if let Some ( mut c) = self . find_niche ( layout. field ( self , i) ?) ? {
1785+ if c. available > available {
1786+ available = c. available ;
1787+ c. offset += layout. fields . offset ( i) ;
1788+ niche = Some ( c) ;
1789+ }
17531790 }
17541791 }
1755- Ok ( None )
1792+ Ok ( niche )
17561793 }
17571794}
17581795
0 commit comments