@@ -18,6 +18,7 @@ use syntax_pos::DUMMY_SP;
18
18
use std:: cmp;
19
19
use std:: fmt;
20
20
use std:: i128;
21
+ use std:: iter;
21
22
use std:: mem;
22
23
23
24
use ich:: StableHashingContext ;
@@ -813,11 +814,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
813
814
if let Some ( i) = dataful_variant {
814
815
let count = ( niche_variants. end ( ) - niche_variants. start ( ) + 1 ) as u128 ;
815
816
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
+
821
826
let mut align = dl. aggregate_align ;
822
827
let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
823
828
let mut st = univariant_uninterned ( v,
@@ -829,21 +834,27 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
829
834
Ok ( st)
830
835
} ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
831
836
832
- let offset = st[ i] . fields . offset ( field_index) + offset;
837
+ let offset = st[ i] . fields . offset ( field_index) + niche . offset ;
833
838
let size = st[ i] . size ;
834
839
835
840
let mut abi = match st[ i] . abi {
836
- Abi :: Scalar ( _) => Abi :: Scalar ( niche . clone ( ) ) ,
841
+ Abi :: Scalar ( _) => Abi :: Scalar ( niche_scalar . clone ( ) ) ,
837
842
Abi :: ScalarPair ( ref first, ref second) => {
838
843
// We need to use scalar_unit to reset the
839
844
// valid range to the maximal one for that
840
845
// primitive, because only the niche is
841
846
// guaranteed to be initialised, not the
842
847
// other primitive.
843
848
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
+ )
845
853
} else {
846
- Abi :: ScalarPair ( scalar_unit ( first. value ) , niche. clone ( ) )
854
+ Abi :: ScalarPair (
855
+ scalar_unit ( first. value ) ,
856
+ niche_scalar. clone ( ) ,
857
+ )
847
858
}
848
859
}
849
860
_ => Abi :: Aggregate { sized : true } ,
@@ -857,7 +868,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
857
868
variants : Variants :: NicheFilling {
858
869
dataful_variant : i,
859
870
niche_variants,
860
- niche,
871
+ niche : niche_scalar ,
861
872
niche_start,
862
873
variants : st,
863
874
} ,
@@ -1674,40 +1685,56 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
1674
1685
}
1675
1686
}
1676
1687
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
+
1677
1713
impl < ' a , ' tcx > LayoutCx < ' tcx , TyCtxt < ' a , ' tcx , ' tcx > > {
1678
1714
/// 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.
1682
1716
// 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| {
1687
1719
let Scalar { value, valid_range : ref v } = * scalar;
1688
1720
1689
1721
let bits = value. size ( self ) . bits ( ) ;
1690
1722
assert ! ( bits <= 128 ) ;
1691
1723
let max_value = !0u128 >> ( 128 - bits) ;
1692
1724
1693
1725
// 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 ( ) {
1695
1727
v. start ( ) + ( max_value - v. end ( ) )
1696
1728
} else {
1697
1729
v. start ( ) - v. end ( ) - 1
1698
1730
} ;
1699
1731
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 {
1702
1734
return None ;
1703
1735
}
1704
1736
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 } )
1711
1738
} ;
1712
1739
1713
1740
// Locals variables which live across yields are stored
@@ -1719,15 +1746,19 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
1719
1746
1720
1747
match layout. abi {
1721
1748
Abi :: Scalar ( ref scalar) => {
1722
- return Ok ( scalar_component ( scalar, Size :: from_bytes ( 0 ) ) ) ;
1749
+ return Ok ( scalar_niche ( scalar, Size :: from_bytes ( 0 ) ) ) ;
1723
1750
}
1724
1751
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) ;
1728
1759
}
1729
1760
Abi :: Vector { ref element, .. } => {
1730
- return Ok ( scalar_component ( element, Size :: from_bytes ( 0 ) ) ) ;
1761
+ return Ok ( scalar_niche ( element, Size :: from_bytes ( 0 ) ) ) ;
1731
1762
}
1732
1763
_ => { }
1733
1764
}
@@ -1742,17 +1773,23 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
1742
1773
}
1743
1774
if let FieldPlacement :: Array { .. } = layout. fields {
1744
1775
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 ) ;
1746
1779
}
1747
1780
}
1781
+ let mut niche = None ;
1782
+ let mut available = 0 ;
1748
1783
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
+ }
1753
1790
}
1754
1791
}
1755
- Ok ( None )
1792
+ Ok ( niche )
1756
1793
}
1757
1794
}
1758
1795
0 commit comments