Skip to content

Commit 9603ad6

Browse files
new layout
Co-authored-by: Dario Nieuwenhuis <[email protected]>
1 parent 37b43cc commit 9603ad6

File tree

10 files changed

+376
-26
lines changed

10 files changed

+376
-26
lines changed

Diff for: compiler/rustc_abi/src/lib.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1552,8 +1552,10 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
15521552
/// a struct, and they all have space reserved for the tag.
15531553
/// For enums, the tag is the sole field of the layout.
15541554
Multiple {
1555+
/// Tag definition
15551556
tag: Scalar,
15561557
tag_encoding: TagEncoding<VariantIdx>,
1558+
/// Index of tag among fields
15571559
tag_field: usize,
15581560
variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
15591561
},
@@ -1597,6 +1599,7 @@ pub enum TagEncoding<VariantIdx: Idx> {
15971599
pub struct Niche {
15981600
pub offset: Size,
15991601
pub value: Primitive,
1602+
/// A range of valid values with both endpoints being inclusive
16001603
pub valid_range: WrappingRange,
16011604
}
16021605

@@ -1607,17 +1610,23 @@ impl Niche {
16071610
if niche.available(cx) > 0 { Some(niche) } else { None }
16081611
}
16091612

1613+
/// Compute how many values are outside the valid range, available for optimisation through niche filling
16101614
pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
16111615
let Self { value, valid_range: v, .. } = *self;
16121616
let size = value.size(cx);
16131617
assert!(size.bits() <= 128);
16141618
let max_value = size.unsigned_int_max();
16151619

1616-
// Find out how many values are outside the valid range.
16171620
let niche = v.end.wrapping_add(1)..v.start;
16181621
niche.end.wrapping_sub(niche.start) & max_value
16191622
}
16201623

1624+
/// Try to enlarge the valid value range to include another `count` values,
1625+
/// so that they can be used for niche-filling optimisation.
1626+
/// `None` signals impossibility of reservation.
1627+
/// Otherwise, `Some((start, scalar))` signifies that a reservation is possible,
1628+
/// the first value in the reservation is `start`, and the new scalar including
1629+
/// the reserved values is defined in `scalar`.
16211630
pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
16221631
assert!(count > 0);
16231632

Diff for: compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,8 @@ declare_features! (
447447
(unstable, const_try, "1.56.0", Some(74935)),
448448
/// Allows coroutines to be cloned.
449449
(unstable, coroutine_clone, "1.65.0", Some(95360)),
450+
/// Allows aggressive merging coroutine saved slots
451+
(unstable, coroutine_new_layout, "CURRENT_RUSTC_VERSION", Some(99999)),
450452
/// Allows defining coroutines.
451453
(unstable, coroutines, "1.21.0", Some(43122)),
452454
/// Allows function attribute `#[coverage(on/off)]`, to control coverage

Diff for: compiler/rustc_middle/src/mir/query.rs

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_index::bit_set::BitMatrix;
1010
use rustc_index::{Idx, IndexVec};
1111
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1212
use rustc_span::{Span, Symbol};
13+
use rustc_type_ir::data_structures::IndexMap;
1314
use smallvec::SmallVec;
1415

1516
use super::{ConstValue, SourceInfo};
@@ -57,6 +58,10 @@ pub struct CoroutineLayout<'tcx> {
5758
#[type_foldable(identity)]
5859
#[type_visitable(ignore)]
5960
pub storage_conflicts: BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal>,
61+
62+
#[type_foldable(identity)]
63+
#[type_visitable(ignore)]
64+
pub relocated_upvars: IndexMap<CoroutineSavedLocal, CoroutineSavedLocal>,
6065
}
6166

6267
impl Debug for CoroutineLayout<'_> {

Diff for: compiler/rustc_mir_transform/src/coroutine.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -976,9 +976,17 @@ fn compute_layout<'tcx>(
976976
suspension_point_at_block,
977977
} = liveness;
978978

979+
// We need to later establish the map between upvars in UNRESUMED and locals in other states.
980+
let local_upvar_map: UnordMap<_, _> = body
981+
.local_upvar_map
982+
.iter_enumerated()
983+
.filter_map(|(field, local)| local.map(|local| (local, field)))
984+
.collect();
985+
979986
// Gather live local types and their indices.
980987
let mut locals = IndexVec::<CoroutineSavedLocal, _>::new();
981988
let mut tys = IndexVec::<CoroutineSavedLocal, _>::new();
989+
let mut saved_local_upvar_map = UnordMap::default();
982990
for (saved_local, local) in saved_locals.iter_enumerated() {
983991
debug!("coroutine saved local {:?} => {:?}", saved_local, local);
984992

@@ -1006,6 +1014,10 @@ fn compute_layout<'tcx>(
10061014
debug!(?decl);
10071015

10081016
tys.push(decl);
1017+
1018+
if let Some(&field) = local_upvar_map.get(&local) {
1019+
saved_local_upvar_map.insert(field, saved_local);
1020+
}
10091021
}
10101022
// These are the "saved locals" sourced from the UNRESUMED state.
10111023
let upvar_saved_locals: IndexVec<FieldIdx, CoroutineSavedLocal> = upvar_tys
@@ -1058,8 +1070,7 @@ fn compute_layout<'tcx>(
10581070
SourceInfo::outermost(body_span.shrink_to_hi()),
10591071
SourceInfo::outermost(body_span.shrink_to_hi()),
10601072
]
1061-
.iter()
1062-
.copied()
1073+
.into_iter()
10631074
.collect();
10641075

10651076
// Build the coroutine variant field list.
@@ -1101,17 +1112,24 @@ fn compute_layout<'tcx>(
11011112
field_names.get_or_insert_with(saved_local, || var.name);
11021113
}
11031114
}
1104-
for (capture, saved_local) in upvar_infos.iter().zip(upvar_saved_locals) {
1115+
for (capture, &saved_local) in upvar_infos.iter().zip(&upvar_saved_locals) {
11051116
field_names.get_or_insert_with(saved_local, || capture.var_ident.name);
11061117
}
11071118
debug!(field_names = ?field_names.debug_map_view());
11081119

1120+
let relocated_upvars = upvar_saved_locals
1121+
.iter_enumerated()
1122+
.filter_map(|(field, &source)| {
1123+
saved_local_upvar_map.get(&field).map(|&dest| (source, dest))
1124+
})
1125+
.collect();
11091126
let layout = CoroutineLayout {
11101127
field_tys: tys,
11111128
field_names,
11121129
variant_fields,
11131130
variant_source_info,
11141131
storage_conflicts,
1132+
relocated_upvars,
11151133
};
11161134
debug!(?layout);
11171135

Diff for: compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ symbols! {
694694
core_panic_macro,
695695
coroutine,
696696
coroutine_clone,
697+
coroutine_new_layout,
697698
coroutine_resume,
698699
coroutine_return,
699700
coroutine_state,

Diff for: compiler/rustc_ty_utils/src/layout.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(unused)]
12
use std::fmt::Debug;
23
use std::iter;
34

@@ -31,6 +32,7 @@ use crate::errors::{
3132
MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType,
3233
};
3334

35+
mod coroutine;
3436
mod invariant;
3537

3638
pub(crate) fn provide(providers: &mut Providers) {
@@ -427,7 +429,13 @@ fn layout_of_uncached<'tcx>(
427429
tcx.mk_layout(unit)
428430
}
429431

430-
ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
432+
ty::Coroutine(def_id, args) => {
433+
// if tcx.features().coroutine_new_layout() {
434+
coroutine::coroutine_layout(cx, ty, def_id, args)?
435+
// } else {
436+
// coroutine_layout(cx, ty, def_id, args)?
437+
// }
438+
}
431439

432440
ty::Closure(_, args) => {
433441
let tys = args.as_closure().upvar_tys();
@@ -1207,8 +1215,10 @@ fn variant_info_for_coroutine<'tcx>(
12071215
.zip_eq(upvar_names)
12081216
.enumerate()
12091217
.map(|(field_idx, (_, name))| {
1210-
let field_layout = layout.field(cx, field_idx);
1211-
let offset = layout.fields.offset(field_idx);
1218+
// Upvars occupies the Unresumed variant at index zero
1219+
let variant_layout = layout.for_variant(cx, VariantIdx::ZERO);
1220+
let field_layout = variant_layout.field(cx, field_idx);
1221+
let offset = variant_layout.fields.offset(field_idx);
12121222
upvars_size = upvars_size.max(offset + field_layout.size);
12131223
FieldInfo {
12141224
kind: FieldKind::Upvar,
@@ -1228,12 +1238,11 @@ fn variant_info_for_coroutine<'tcx>(
12281238
let variant_layout = layout.for_variant(cx, variant_idx);
12291239
let mut variant_size = Size::ZERO;
12301240
let fields = variant_def
1231-
.iter()
1232-
.enumerate()
1241+
.iter_enumerated()
12331242
.map(|(field_idx, local)| {
12341243
let field_name = coroutine.field_names[*local];
1235-
let field_layout = variant_layout.field(cx, field_idx);
1236-
let offset = variant_layout.fields.offset(field_idx);
1244+
let field_layout = variant_layout.field(cx, field_idx.index());
1245+
let offset = variant_layout.fields.offset(field_idx.index());
12371246
// The struct is as large as the last field's end
12381247
variant_size = variant_size.max(offset + field_layout.size);
12391248
FieldInfo {

0 commit comments

Comments
 (0)