@@ -805,19 +805,19 @@ pub enum Variants {
805
805
variants : Vec < CachedLayout > ,
806
806
} ,
807
807
808
- /// Two cases distinguished by a niche (a value invalid for a type):
808
+ /// Multiple cases distinguished by a niche (values invalid for a type):
809
809
/// the variant `dataful_variant` contains a niche at an arbitrary
810
- /// offset (field 0 of the enum), which is set to `niche_value`
811
- /// for the other variant .
810
+ /// offset (field 0 of the enum), which for a variant with discriminant
811
+ /// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)` .
812
812
///
813
813
/// For example, `Option<(usize, &T)>` is represented such that
814
814
/// `None` has a null pointer for the second tuple field, and
815
815
/// `Some` is the identity function (with a non-null reference).
816
816
NicheFilling {
817
817
dataful_variant : usize ,
818
- niche_variant : usize ,
818
+ niche_variants : RangeInclusive < usize > ,
819
819
niche : Scalar ,
820
- niche_value : u128 ,
820
+ niche_start : u128 ,
821
821
variants : Vec < CachedLayout > ,
822
822
}
823
823
}
@@ -1372,11 +1372,11 @@ impl<'a, 'tcx> CachedLayout {
1372
1372
} ) . collect :: < Result < Vec < _ > , _ > > ( )
1373
1373
} ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1374
1374
1375
- let ( inh_first, inh_second, inh_third ) = {
1375
+ let ( inh_first, inh_second) = {
1376
1376
let mut inh_variants = ( 0 ..variants. len ( ) ) . filter ( |& v| {
1377
1377
variants[ v] . iter ( ) . all ( |f| f. abi != Abi :: Uninhabited )
1378
1378
} ) ;
1379
- ( inh_variants. next ( ) , inh_variants. next ( ) , inh_variants . next ( ) )
1379
+ ( inh_variants. next ( ) , inh_variants. next ( ) )
1380
1380
} ;
1381
1381
if inh_first. is_none ( ) {
1382
1382
// Uninhabited because it has no variants, or only uninhabited ones.
@@ -1472,68 +1472,94 @@ impl<'a, 'tcx> CachedLayout {
1472
1472
let no_explicit_discriminants = def. variants . iter ( ) . enumerate ( )
1473
1473
. all ( |( i, v) | v. discr == ty:: VariantDiscr :: Relative ( i) ) ;
1474
1474
1475
- if inh_second. is_some ( ) && inh_third. is_none ( ) &&
1476
- !def. repr . inhibit_enum_layout_opt ( ) &&
1477
- no_explicit_discriminants {
1478
- // Nullable pointer optimization
1479
- let ( a, b) = ( inh_first. unwrap ( ) , inh_second. unwrap ( ) ) ;
1480
- for & ( i, other) in & [ ( a, b) , ( b, a) ] {
1481
- if !variants[ other] . iter ( ) . all ( |f| f. is_zst ( ) ) {
1482
- continue ;
1475
+ // Niche-filling enum optimization.
1476
+ if !def. repr . inhibit_enum_layout_opt ( ) && no_explicit_discriminants {
1477
+ let mut dataful_variant = None ;
1478
+ let mut niche_variants = usize:: max_value ( ) ..=0 ;
1479
+
1480
+ // Find one non-ZST variant.
1481
+ ' variants: for ( v, fields) in variants. iter ( ) . enumerate ( ) {
1482
+ for f in fields {
1483
+ if f. abi == Abi :: Uninhabited {
1484
+ continue ' variants;
1485
+ }
1486
+ if !f. is_zst ( ) {
1487
+ if dataful_variant. is_none ( ) {
1488
+ dataful_variant = Some ( v) ;
1489
+ continue ' variants;
1490
+ } else {
1491
+ dataful_variant = None ;
1492
+ break ' variants;
1493
+ }
1494
+ }
1495
+ }
1496
+ if niche_variants. start > v {
1497
+ niche_variants. start = v;
1483
1498
}
1499
+ niche_variants. end = v;
1500
+ }
1501
+
1502
+ if niche_variants. start > niche_variants. end {
1503
+ dataful_variant = None ;
1504
+ }
1484
1505
1506
+ if let Some ( i) = dataful_variant {
1507
+ let count = ( niche_variants. end - niche_variants. start + 1 ) as u128 ;
1485
1508
for ( field_index, field) in variants[ i] . iter ( ) . enumerate ( ) {
1486
- if let Some ( ( offset, niche, niche_value) ) = field. find_niche ( cx) ? {
1487
- let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
1488
- let mut st = univariant_uninterned ( v,
1489
- & def. repr , StructKind :: AlwaysSized ) ?;
1490
- st. variants = Variants :: Single { index : j } ;
1491
- Ok ( st)
1492
- } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1493
-
1494
- let offset = st[ i] . fields . offset ( field_index) + offset;
1495
- let CachedLayout {
1496
- size,
1497
- mut align,
1498
- mut primitive_align,
1499
- ..
1500
- } = st[ i] ;
1501
-
1502
- let mut niche_align = niche. value . align ( dl) ;
1503
- let abi = if offset. bytes ( ) == 0 && niche. value . size ( dl) == size {
1504
- Abi :: Scalar ( niche. clone ( ) )
1505
- } else {
1506
- let mut packed = st[ i] . abi . is_packed ( ) ;
1507
- if offset. abi_align ( niche_align) != offset {
1508
- packed = true ;
1509
- niche_align = dl. i8_align ;
1510
- }
1511
- Abi :: Aggregate {
1512
- sized : true ,
1513
- packed
1514
- }
1509
+ let ( offset, niche, niche_start) =
1510
+ match field. find_niche ( cx, count) ? {
1511
+ Some ( niche) => niche,
1512
+ None => continue
1515
1513
} ;
1516
- align = align. max ( niche_align) ;
1517
- primitive_align = primitive_align. max ( niche_align) ;
1518
-
1519
- return Ok ( tcx. intern_layout ( CachedLayout {
1520
- variants : Variants :: NicheFilling {
1521
- dataful_variant : i,
1522
- niche_variant : other,
1523
- niche,
1524
- niche_value,
1525
- variants : st,
1526
- } ,
1527
- fields : FieldPlacement :: Arbitrary {
1528
- offsets : vec ! [ offset] ,
1529
- memory_index : vec ! [ 0 ]
1530
- } ,
1531
- abi,
1532
- size,
1533
- align,
1534
- primitive_align
1535
- } ) ) ;
1536
- }
1514
+ let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
1515
+ let mut st = univariant_uninterned ( v,
1516
+ & def. repr , StructKind :: AlwaysSized ) ?;
1517
+ st. variants = Variants :: Single { index : j } ;
1518
+ Ok ( st)
1519
+ } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1520
+
1521
+ let offset = st[ i] . fields . offset ( field_index) + offset;
1522
+ let CachedLayout {
1523
+ size,
1524
+ mut align,
1525
+ mut primitive_align,
1526
+ ..
1527
+ } = st[ i] ;
1528
+
1529
+ let mut niche_align = niche. value . align ( dl) ;
1530
+ let abi = if offset. bytes ( ) == 0 && niche. value . size ( dl) == size {
1531
+ Abi :: Scalar ( niche. clone ( ) )
1532
+ } else {
1533
+ let mut packed = st[ i] . abi . is_packed ( ) ;
1534
+ if offset. abi_align ( niche_align) != offset {
1535
+ packed = true ;
1536
+ niche_align = dl. i8_align ;
1537
+ }
1538
+ Abi :: Aggregate {
1539
+ sized : true ,
1540
+ packed
1541
+ }
1542
+ } ;
1543
+ align = align. max ( niche_align) ;
1544
+ primitive_align = primitive_align. max ( niche_align) ;
1545
+
1546
+ return Ok ( tcx. intern_layout ( CachedLayout {
1547
+ variants : Variants :: NicheFilling {
1548
+ dataful_variant : i,
1549
+ niche_variants,
1550
+ niche,
1551
+ niche_start,
1552
+ variants : st,
1553
+ } ,
1554
+ fields : FieldPlacement :: Arbitrary {
1555
+ offsets : vec ! [ offset] ,
1556
+ memory_index : vec ! [ 0 ]
1557
+ } ,
1558
+ abi,
1559
+ size,
1560
+ align,
1561
+ primitive_align
1562
+ } ) ) ;
1537
1563
}
1538
1564
}
1539
1565
}
@@ -2267,50 +2293,50 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2267
2293
}
2268
2294
2269
2295
/// Find the offset of a niche leaf field, starting from
2270
- /// the given type and recursing through aggregates.
2296
+ /// the given type and recursing through aggregates, which
2297
+ /// has at least `count` consecutive invalid values.
2271
2298
/// The tuple is `(offset, scalar, niche_value)`.
2272
2299
// FIXME(eddyb) traverse already optimized enums.
2273
- fn find_niche < C > ( & self , cx : C )
2300
+ fn find_niche < C > ( & self , cx : C , count : u128 )
2274
2301
-> Result < Option < ( Size , Scalar , u128 ) > , LayoutError < ' tcx > >
2275
2302
where C : LayoutOf < Ty < ' tcx > , TyLayout = Result < Self , LayoutError < ' tcx > > > +
2276
2303
HasTyCtxt < ' tcx >
2277
2304
{
2278
2305
let scalar_component = |scalar : & Scalar , offset| {
2279
- // FIXME(eddyb) support negative/wrap-around discriminant ranges.
2280
- let Scalar { value, ref valid_range } = * scalar;
2281
- if valid_range. start < valid_range. end {
2282
- let bits = value. size ( cx) . bits ( ) ;
2283
- assert ! ( bits <= 128 ) ;
2284
- let max_value = !0u128 >> ( 128 - bits) ;
2285
- if valid_range. start > 0 {
2286
- let niche = valid_range. start - 1 ;
2287
- Ok ( Some ( ( offset, Scalar {
2288
- value,
2289
- valid_range : niche..=valid_range. end
2290
- } , niche) ) )
2291
- } else if valid_range. end < max_value {
2292
- let niche = valid_range. end + 1 ;
2293
- Ok ( Some ( ( offset, Scalar {
2294
- value,
2295
- valid_range : valid_range. start ..=niche
2296
- } , niche) ) )
2297
- } else {
2298
- Ok ( None )
2299
- }
2306
+ let Scalar { value, valid_range : ref v } = * scalar;
2307
+
2308
+ let bits = value. size ( cx) . bits ( ) ;
2309
+ assert ! ( bits <= 128 ) ;
2310
+ let max_value = !0u128 >> ( 128 - bits) ;
2311
+
2312
+ // Find out how many values are outside the valid range.
2313
+ let niches = if v. start <= v. end {
2314
+ v. start + ( max_value - v. end )
2300
2315
} else {
2301
- Ok ( None )
2316
+ v. start - v. end - 1
2317
+ } ;
2318
+
2319
+ // Give up if we can't fit `count` consecutive niches.
2320
+ if count > niches {
2321
+ return None ;
2302
2322
}
2323
+
2324
+ let niche_start = v. end . wrapping_add ( 1 ) & max_value;
2325
+ let niche_end = v. end . wrapping_add ( count) & max_value;
2326
+ Some ( ( offset, Scalar {
2327
+ value,
2328
+ valid_range : v. start ..=niche_end
2329
+ } , niche_start) )
2303
2330
} ;
2304
2331
2305
2332
match self . abi {
2306
2333
Abi :: Scalar ( ref scalar) => {
2307
- return scalar_component ( scalar, Size :: from_bytes ( 0 ) ) ;
2334
+ return Ok ( scalar_component ( scalar, Size :: from_bytes ( 0 ) ) ) ;
2308
2335
}
2309
2336
Abi :: ScalarPair ( ref a, ref b) => {
2310
- if let Some ( result) = scalar_component ( a, Size :: from_bytes ( 0 ) ) ? {
2311
- return Ok ( Some ( result) ) ;
2312
- }
2313
- return scalar_component ( b, a. value . size ( cx) . abi_align ( b. value . align ( cx) ) ) ;
2337
+ return Ok ( scalar_component ( a, Size :: from_bytes ( 0 ) ) . or_else ( || {
2338
+ scalar_component ( b, a. value . size ( cx) . abi_align ( b. value . align ( cx) ) )
2339
+ } ) ) ;
2314
2340
}
2315
2341
_ => { }
2316
2342
}
@@ -2323,13 +2349,13 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2323
2349
return Ok ( None ) ;
2324
2350
}
2325
2351
}
2326
- if let FieldPlacement :: Array { count , .. } = self . fields {
2327
- if count > 0 {
2328
- return self . field ( cx, 0 ) ?. find_niche ( cx) ;
2352
+ if let FieldPlacement :: Array { .. } = self . fields {
2353
+ if self . fields . count ( ) > 0 {
2354
+ return self . field ( cx, 0 ) ?. find_niche ( cx, count ) ;
2329
2355
}
2330
2356
}
2331
2357
for i in 0 ..self . fields . count ( ) {
2332
- let r = self . field ( cx, i) ?. find_niche ( cx) ?;
2358
+ let r = self . field ( cx, i) ?. find_niche ( cx, count ) ?;
2333
2359
if let Some ( ( offset, scalar, niche_value) ) = r {
2334
2360
let offset = self . fields . offset ( i) + offset;
2335
2361
return Ok ( Some ( ( offset, scalar, niche_value) ) ) ;
@@ -2359,15 +2385,16 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
2359
2385
}
2360
2386
NicheFilling {
2361
2387
dataful_variant,
2362
- niche_variant ,
2388
+ niche_variants : RangeInclusive { start , end } ,
2363
2389
ref niche,
2364
- niche_value ,
2390
+ niche_start ,
2365
2391
ref variants,
2366
2392
} => {
2367
2393
dataful_variant. hash_stable ( hcx, hasher) ;
2368
- niche_variant. hash_stable ( hcx, hasher) ;
2394
+ start. hash_stable ( hcx, hasher) ;
2395
+ end. hash_stable ( hcx, hasher) ;
2369
2396
niche. hash_stable ( hcx, hasher) ;
2370
- niche_value . hash_stable ( hcx, hasher) ;
2397
+ niche_start . hash_stable ( hcx, hasher) ;
2371
2398
variants. hash_stable ( hcx, hasher) ;
2372
2399
}
2373
2400
}
0 commit comments