@@ -799,19 +799,19 @@ pub enum Variants {
799
799
variants : Vec < CachedLayout > ,
800
800
} ,
801
801
802
- /// Two cases distinguished by a niche (a value invalid for a type):
802
+ /// Multiple cases distinguished by a niche (values invalid for a type):
803
803
/// the variant `dataful_variant` contains a niche at an arbitrary
804
- /// offset (field 0 of the enum), which is set to `niche_value`
805
- /// for the other variant .
804
+ /// offset (field 0 of the enum), which for a variant with discriminant
805
+ /// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)` .
806
806
///
807
807
/// For example, `Option<(usize, &T)>` is represented such that
808
808
/// `None` has a null pointer for the second tuple field, and
809
809
/// `Some` is the identity function (with a non-null reference).
810
810
NicheFilling {
811
811
dataful_variant : usize ,
812
- niche_variant : usize ,
812
+ niche_variants : RangeInclusive < usize > ,
813
813
niche : Scalar ,
814
- niche_value : u128 ,
814
+ niche_start : u128 ,
815
815
variants : Vec < CachedLayout > ,
816
816
}
817
817
}
@@ -1358,11 +1358,11 @@ impl<'a, 'tcx> CachedLayout {
1358
1358
} ) . collect :: < Result < Vec < _ > , _ > > ( )
1359
1359
} ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1360
1360
1361
- let ( inh_first, inh_second, inh_third ) = {
1361
+ let ( inh_first, inh_second) = {
1362
1362
let mut inh_variants = ( 0 ..variants. len ( ) ) . filter ( |& v| {
1363
1363
variants[ v] . iter ( ) . all ( |f| f. abi != Abi :: Uninhabited )
1364
1364
} ) ;
1365
- ( inh_variants. next ( ) , inh_variants. next ( ) , inh_variants . next ( ) )
1365
+ ( inh_variants. next ( ) , inh_variants. next ( ) )
1366
1366
} ;
1367
1367
if inh_first. is_none ( ) {
1368
1368
// Uninhabited because it has no variants, or only uninhabited ones.
@@ -1458,53 +1458,79 @@ impl<'a, 'tcx> CachedLayout {
1458
1458
let no_explicit_discriminants = def. variants . iter ( ) . enumerate ( )
1459
1459
. all ( |( i, v) | v. discr == ty:: VariantDiscr :: Relative ( i) ) ;
1460
1460
1461
- if inh_second. is_some ( ) && inh_third. is_none ( ) &&
1462
- !def. repr . inhibit_enum_layout_opt ( ) &&
1463
- no_explicit_discriminants {
1464
- // Nullable pointer optimization
1465
- let ( a, b) = ( inh_first. unwrap ( ) , inh_second. unwrap ( ) ) ;
1466
- for & ( i, other) in & [ ( a, b) , ( b, a) ] {
1467
- if !variants[ other] . iter ( ) . all ( |f| f. is_zst ( ) ) {
1468
- continue ;
1461
+ // Niche-filling enum optimization.
1462
+ if !def. repr . inhibit_enum_layout_opt ( ) && no_explicit_discriminants {
1463
+ let mut dataful_variant = None ;
1464
+ let mut niche_variants = usize:: max_value ( ) ...0 ;
1465
+
1466
+ // Find one non-ZST variant.
1467
+ ' variants: for ( v, fields) in variants. iter ( ) . enumerate ( ) {
1468
+ for f in fields {
1469
+ if f. abi == Abi :: Uninhabited {
1470
+ continue ' variants;
1471
+ }
1472
+ if !f. is_zst ( ) {
1473
+ if dataful_variant. is_none ( ) {
1474
+ dataful_variant = Some ( v) ;
1475
+ continue ' variants;
1476
+ } else {
1477
+ dataful_variant = None ;
1478
+ break ' variants;
1479
+ }
1480
+ }
1481
+ }
1482
+ if niche_variants. start > v {
1483
+ niche_variants. start = v;
1469
1484
}
1485
+ niche_variants. end = v;
1486
+ }
1487
+
1488
+ if niche_variants. start > niche_variants. end {
1489
+ dataful_variant = None ;
1490
+ }
1470
1491
1492
+ if let Some ( i) = dataful_variant {
1493
+ let count = ( niche_variants. end - niche_variants. start + 1 ) as u128 ;
1471
1494
for ( field_index, field) in variants[ i] . iter ( ) . enumerate ( ) {
1472
- if let Some ( ( offset, niche, niche_value) ) = field. find_niche ( cx) ? {
1473
- let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
1474
- let mut st = univariant_uninterned ( v,
1475
- & def. repr , StructKind :: AlwaysSized ) ?;
1476
- st. variants = Variants :: Single { index : j } ;
1477
- Ok ( st)
1478
- } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1479
-
1480
- let offset = st[ i] . fields . offset ( field_index) + offset;
1481
- let CachedLayout { size, align, primitive_align, .. } = st[ i] ;
1482
- let abi = if offset. bytes ( ) == 0 && niche. value . size ( dl) == size {
1483
- Abi :: Scalar ( niche. clone ( ) )
1484
- } else {
1485
- Abi :: Aggregate {
1486
- sized : true ,
1487
- packed : st[ i] . abi . is_packed ( )
1488
- }
1495
+ let ( offset, niche, niche_start) =
1496
+ match field. find_niche ( cx, count) ? {
1497
+ Some ( niche) => niche,
1498
+ None => continue
1489
1499
} ;
1490
- return Ok ( tcx. intern_layout ( CachedLayout {
1491
- variants : Variants :: NicheFilling {
1492
- dataful_variant : i,
1493
- niche_variant : other,
1494
- niche,
1495
- niche_value,
1496
- variants : st,
1497
- } ,
1498
- fields : FieldPlacement :: Arbitrary {
1499
- offsets : vec ! [ offset] ,
1500
- memory_index : vec ! [ 0 ]
1501
- } ,
1502
- abi,
1503
- size,
1504
- align,
1505
- primitive_align
1506
- } ) ) ;
1507
- }
1500
+ let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
1501
+ let mut st = univariant_uninterned ( v,
1502
+ & def. repr , StructKind :: AlwaysSized ) ?;
1503
+ st. variants = Variants :: Single { index : j } ;
1504
+ Ok ( st)
1505
+ } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1506
+
1507
+ let offset = st[ i] . fields . offset ( field_index) + offset;
1508
+ let CachedLayout { size, align, primitive_align, .. } = st[ i] ;
1509
+ let abi = if offset. bytes ( ) == 0 && niche. value . size ( dl) == size {
1510
+ Abi :: Scalar ( niche. clone ( ) )
1511
+ } else {
1512
+ Abi :: Aggregate {
1513
+ sized : true ,
1514
+ packed : st[ i] . abi . is_packed ( )
1515
+ }
1516
+ } ;
1517
+ return Ok ( tcx. intern_layout ( CachedLayout {
1518
+ variants : Variants :: NicheFilling {
1519
+ dataful_variant : i,
1520
+ niche_variants,
1521
+ niche,
1522
+ niche_start,
1523
+ variants : st,
1524
+ } ,
1525
+ fields : FieldPlacement :: Arbitrary {
1526
+ offsets : vec ! [ offset] ,
1527
+ memory_index : vec ! [ 0 ]
1528
+ } ,
1529
+ abi,
1530
+ size,
1531
+ align,
1532
+ primitive_align
1533
+ } ) ) ;
1508
1534
}
1509
1535
}
1510
1536
}
@@ -2234,50 +2260,50 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2234
2260
}
2235
2261
2236
2262
/// Find the offset of a niche leaf field, starting from
2237
- /// the given type and recursing through aggregates.
2263
+ /// the given type and recursing through aggregates, which
2264
+ /// has at least `count` consecutive invalid values.
2238
2265
/// The tuple is `(offset, scalar, niche_value)`.
2239
2266
// FIXME(eddyb) traverse already optimized enums.
2240
- fn find_niche < C > ( & self , cx : C )
2267
+ fn find_niche < C > ( & self , cx : C , count : u128 )
2241
2268
-> Result < Option < ( Size , Scalar , u128 ) > , LayoutError < ' tcx > >
2242
2269
where C : LayoutOf < Ty < ' tcx > , TyLayout = Result < Self , LayoutError < ' tcx > > > +
2243
2270
HasTyCtxt < ' tcx >
2244
2271
{
2245
2272
let scalar_component = |scalar : & Scalar , offset| {
2246
- // FIXME(eddyb) support negative/wrap-around discriminant ranges.
2247
- let Scalar { value, ref valid_range } = * scalar;
2248
- if valid_range. start < valid_range. end {
2249
- let bits = value. size ( cx) . bits ( ) ;
2250
- assert ! ( bits <= 128 ) ;
2251
- let max_value = !0u128 >> ( 128 - bits) ;
2252
- if valid_range. start > 0 {
2253
- let niche = valid_range. start - 1 ;
2254
- Ok ( Some ( ( offset, Scalar {
2255
- value,
2256
- valid_range : niche...valid_range. end
2257
- } , niche) ) )
2258
- } else if valid_range. end < max_value {
2259
- let niche = valid_range. end + 1 ;
2260
- Ok ( Some ( ( offset, Scalar {
2261
- value,
2262
- valid_range : valid_range. start ...niche
2263
- } , niche) ) )
2264
- } else {
2265
- Ok ( None )
2266
- }
2273
+ let Scalar { value, valid_range : ref v } = * scalar;
2274
+
2275
+ let bits = value. size ( cx) . bits ( ) ;
2276
+ assert ! ( bits <= 128 ) ;
2277
+ let max_value = !0u128 >> ( 128 - bits) ;
2278
+
2279
+ // Find out how many values are outside the valid range.
2280
+ let niches = if v. start <= v. end {
2281
+ v. start + ( max_value - v. end )
2267
2282
} else {
2268
- Ok ( None )
2283
+ v. start - v. end - 1
2284
+ } ;
2285
+
2286
+ // Give up if we can't fit `count` consecutive niches.
2287
+ if count > niches {
2288
+ return None ;
2269
2289
}
2290
+
2291
+ let niche_start = v. end . wrapping_add ( 1 ) & max_value;
2292
+ let niche_end = v. end . wrapping_add ( count) & max_value;
2293
+ Some ( ( offset, Scalar {
2294
+ value,
2295
+ valid_range : v. start ...niche_end
2296
+ } , niche_start) )
2270
2297
} ;
2271
2298
2272
2299
match self . abi {
2273
2300
Abi :: Scalar ( ref scalar) => {
2274
- return scalar_component ( scalar, Size :: from_bytes ( 0 ) ) ;
2301
+ return Ok ( scalar_component ( scalar, Size :: from_bytes ( 0 ) ) ) ;
2275
2302
}
2276
2303
Abi :: ScalarPair ( ref a, ref b) => {
2277
- if let Some ( result) = scalar_component ( a, Size :: from_bytes ( 0 ) ) ? {
2278
- return Ok ( Some ( result) ) ;
2279
- }
2280
- return scalar_component ( b, a. value . size ( cx) . abi_align ( b. value . align ( cx) ) ) ;
2304
+ return Ok ( scalar_component ( a, Size :: from_bytes ( 0 ) ) . or_else ( || {
2305
+ scalar_component ( b, a. value . size ( cx) . abi_align ( b. value . align ( cx) ) )
2306
+ } ) ) ;
2281
2307
}
2282
2308
_ => { }
2283
2309
}
@@ -2290,13 +2316,13 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2290
2316
return Ok ( None ) ;
2291
2317
}
2292
2318
}
2293
- if let FieldPlacement :: Array { count , .. } = self . fields {
2294
- if count > 0 {
2295
- return self . field ( cx, 0 ) ?. find_niche ( cx) ;
2319
+ if let FieldPlacement :: Array { .. } = self . fields {
2320
+ if self . fields . count ( ) > 0 {
2321
+ return self . field ( cx, 0 ) ?. find_niche ( cx, count ) ;
2296
2322
}
2297
2323
}
2298
2324
for i in 0 ..self . fields . count ( ) {
2299
- let r = self . field ( cx, i) ?. find_niche ( cx) ?;
2325
+ let r = self . field ( cx, i) ?. find_niche ( cx, count ) ?;
2300
2326
if let Some ( ( offset, scalar, niche_value) ) = r {
2301
2327
let offset = self . fields . offset ( i) + offset;
2302
2328
return Ok ( Some ( ( offset, scalar, niche_value) ) ) ;
@@ -2326,15 +2352,16 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
2326
2352
}
2327
2353
NicheFilling {
2328
2354
dataful_variant,
2329
- niche_variant ,
2355
+ niche_variants : RangeInclusive { start , end } ,
2330
2356
ref niche,
2331
- niche_value ,
2357
+ niche_start ,
2332
2358
ref variants,
2333
2359
} => {
2334
2360
dataful_variant. hash_stable ( hcx, hasher) ;
2335
- niche_variant. hash_stable ( hcx, hasher) ;
2361
+ start. hash_stable ( hcx, hasher) ;
2362
+ end. hash_stable ( hcx, hasher) ;
2336
2363
niche. hash_stable ( hcx, hasher) ;
2337
- niche_value . hash_stable ( hcx, hasher) ;
2364
+ niche_start . hash_stable ( hcx, hasher) ;
2338
2365
variants. hash_stable ( hcx, hasher) ;
2339
2366
}
2340
2367
}
0 commit comments