Skip to content

Commit 3e6a399

Browse files
new layout
Co-authored-by: Dario Nieuwenhuis <[email protected]>
1 parent f319d1a commit 3e6a399

File tree

10 files changed

+374
-26
lines changed

10 files changed

+374
-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
@@ -11,6 +11,7 @@ use rustc_index::bit_set::BitMatrix;
1111
use rustc_index::{Idx, IndexVec};
1212
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1313
use rustc_span::{Span, Symbol};
14+
use rustc_type_ir::data_structures::IndexMap;
1415
use smallvec::SmallVec;
1516

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

6368
impl Debug for CoroutineLayout<'_> {

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

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

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

@@ -1005,6 +1013,10 @@ fn compute_layout<'tcx>(
10051013
debug!(?decl);
10061014

10071015
tys.push(decl);
1016+
1017+
if let Some(&field) = local_upvar_map.get(&local) {
1018+
saved_local_upvar_map.insert(field, saved_local);
1019+
}
10081020
}
10091021
// These are the "saved locals" sourced from the UNRESUMED state.
10101022
let upvar_saved_locals: IndexVec<FieldIdx, CoroutineSavedLocal> = upvar_tys
@@ -1057,8 +1069,7 @@ fn compute_layout<'tcx>(
10571069
SourceInfo::outermost(body_span.shrink_to_hi()),
10581070
SourceInfo::outermost(body_span.shrink_to_hi()),
10591071
]
1060-
.iter()
1061-
.copied()
1072+
.into_iter()
10621073
.collect();
10631074

10641075
// Build the coroutine variant field list.
@@ -1100,17 +1111,24 @@ fn compute_layout<'tcx>(
11001111
field_names.get_or_insert_with(saved_local, || var.name);
11011112
}
11021113
}
1103-
for (capture, saved_local) in upvar_infos.iter().zip(upvar_saved_locals) {
1114+
for (capture, &saved_local) in upvar_infos.iter().zip(&upvar_saved_locals) {
11041115
field_names.get_or_insert_with(saved_local, || capture.var_ident.name);
11051116
}
11061117
debug!(field_names = ?field_names.debug_map_view());
11071118

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

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

+1
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ symbols! {
693693
core_panic_macro,
694694
coroutine,
695695
coroutine_clone,
696+
coroutine_new_layout,
696697
coroutine_resume,
697698
coroutine_return,
698699
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) {
@@ -397,7 +399,13 @@ fn layout_of_uncached<'tcx>(
397399
tcx.mk_layout(unit)
398400
}
399401

400-
ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
402+
ty::Coroutine(def_id, args) => {
403+
// if tcx.features().coroutine_new_layout() {
404+
coroutine::coroutine_layout(cx, ty, def_id, args)?
405+
// } else {
406+
// coroutine_layout(cx, ty, def_id, args)?
407+
// }
408+
}
401409

402410
ty::Closure(_, args) => {
403411
let tys = args.as_closure().upvar_tys();
@@ -1168,8 +1176,10 @@ fn variant_info_for_coroutine<'tcx>(
11681176
.zip_eq(upvar_names)
11691177
.enumerate()
11701178
.map(|(field_idx, (_, name))| {
1171-
let field_layout = layout.field(cx, field_idx);
1172-
let offset = layout.fields.offset(field_idx);
1179+
// Upvars occupies the Unresumed variant at index zero
1180+
let variant_layout = layout.for_variant(cx, VariantIdx::ZERO);
1181+
let field_layout = variant_layout.field(cx, field_idx);
1182+
let offset = variant_layout.fields.offset(field_idx);
11731183
upvars_size = upvars_size.max(offset + field_layout.size);
11741184
FieldInfo {
11751185
kind: FieldKind::Upvar,
@@ -1189,12 +1199,11 @@ fn variant_info_for_coroutine<'tcx>(
11891199
let variant_layout = layout.for_variant(cx, variant_idx);
11901200
let mut variant_size = Size::ZERO;
11911201
let fields = variant_def
1192-
.iter()
1193-
.enumerate()
1202+
.iter_enumerated()
11941203
.map(|(field_idx, local)| {
11951204
let field_name = coroutine.field_names[*local];
1196-
let field_layout = variant_layout.field(cx, field_idx);
1197-
let offset = variant_layout.fields.offset(field_idx);
1205+
let field_layout = variant_layout.field(cx, field_idx.index());
1206+
let offset = variant_layout.fields.offset(field_idx.index());
11981207
// The struct is as large as the last field's end
11991208
variant_size = variant_size.max(offset + field_layout.size);
12001209
FieldInfo {

0 commit comments

Comments
 (0)