Skip to content

Commit 8327b5a

Browse files
committed
Auto merge of #37429 - camlorn:univariant_layout_optimization, r=eddyb
struct field reordering and optimization This is work in progress. The goal is to divorce the order of fields in source code from the order of fields in the LLVM IR, then optimize structs (and tuples/enum variants)by always ordering fields from least to most aligned. It does not work yet. I intend to check compiler memory usage as a benchmark, and a crater run will probably be required. I don't know enough of the compiler to complete this work unaided. If you see places that still need updating, please mention them. The only one I know of currently is debuginfo, which I'm putting off intentionally until a bit later. r? @eddyb
2 parents d54e723 + ff59474 commit 8327b5a

28 files changed

+538
-232
lines changed

src/librustc/session/code_stats.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ impl CodeStats {
142142
max_variant_size = cmp::max(max_variant_size, size);
143143

144144
let mut min_offset = discr_size;
145-
for field in fields {
145+
146+
// We want to print fields by increasing offset.
147+
let mut fields = fields.clone();
148+
fields.sort_by_key(|f| f.offset);
149+
150+
for field in fields.iter() {
146151
let FieldInfo { ref name, offset, size, align } = *field;
147152

148153
// Include field alignment in output only if it caused padding injection

src/librustc/ty/layout.rs

+306-124
Large diffs are not rendered by default.

src/librustc_data_structures/flock.rs

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ mod imp {
3131
mod os {
3232
use libc;
3333

34+
#[repr(C)]
3435
pub struct flock {
3536
pub l_type: libc::c_short,
3637
pub l_whence: libc::c_short,
@@ -53,6 +54,7 @@ mod imp {
5354
mod os {
5455
use libc;
5556

57+
#[repr(C)]
5658
pub struct flock {
5759
pub l_start: libc::off_t,
5860
pub l_len: libc::off_t,
@@ -76,6 +78,7 @@ mod imp {
7678
mod os {
7779
use libc;
7880

81+
#[repr(C)]
7982
pub struct flock {
8083
pub l_start: libc::off_t,
8184
pub l_len: libc::off_t,
@@ -98,6 +101,7 @@ mod imp {
98101
mod os {
99102
use libc;
100103

104+
#[repr(C)]
101105
pub struct flock {
102106
pub l_type: libc::c_short,
103107
pub l_whence: libc::c_short,
@@ -119,6 +123,7 @@ mod imp {
119123
mod os {
120124
use libc;
121125

126+
#[repr(C)]
122127
pub struct flock {
123128
pub l_start: libc::off_t,
124129
pub l_len: libc::off_t,
@@ -141,6 +146,7 @@ mod imp {
141146
mod os {
142147
use libc;
143148

149+
#[repr(C)]
144150
pub struct flock {
145151
pub l_type: libc::c_short,
146152
pub l_whence: libc::c_short,

src/librustc_lint/types.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
750750
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
751751
let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
752752

753-
debug!("enum `{}` is {} bytes large", t, size.bytes());
753+
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
754+
t, size.bytes(), layout);
754755

755756
let (largest, slargest, largest_index) = enum_definition.variants
756757
.iter()

src/librustc_trans/adt.rs

+28-25
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,14 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
151151
| layout::UntaggedUnion { .. } | layout::RawNullablePointer { .. } => { }
152152
layout::Univariant { ..}
153153
| layout::StructWrappedNullablePointer { .. } => {
154-
let (nonnull_variant, packed) = match *l {
155-
layout::Univariant { ref variant, .. } => (0, variant.packed),
154+
let (nonnull_variant_index, nonnull_variant, packed) = match *l {
155+
layout::Univariant { ref variant, .. } => (0, variant, variant.packed),
156156
layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } =>
157-
(nndiscr, nonnull.packed),
157+
(nndiscr, nonnull, nonnull.packed),
158158
_ => unreachable!()
159159
};
160-
let fields = compute_fields(cx, t, nonnull_variant as usize, true);
161-
llty.set_struct_body(&struct_llfields(cx, &fields, false, false),
160+
let fields = compute_fields(cx, t, nonnull_variant_index as usize, true);
161+
llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false),
162162
packed)
163163
},
164164
_ => bug!("This function cannot handle {} with layout {:#?}", t, l)
@@ -188,7 +188,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
188188
let fields = compute_fields(cx, t, nndiscr as usize, false);
189189
match name {
190190
None => {
191-
Type::struct_(cx, &struct_llfields(cx, &fields, sizing, dst),
191+
Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst),
192192
nonnull.packed)
193193
}
194194
Some(name) => {
@@ -203,7 +203,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
203203
let fields = compute_fields(cx, t, 0, true);
204204
match name {
205205
None => {
206-
let fields = struct_llfields(cx, &fields, sizing, dst);
206+
let fields = struct_llfields(cx, &fields, &variant, sizing, dst);
207207
Type::struct_(cx, &fields, variant.packed)
208208
}
209209
Some(name) => {
@@ -291,12 +291,14 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
291291

292292

293293
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
294+
variant: &layout::Struct,
294295
sizing: bool, dst: bool) -> Vec<Type> {
296+
let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
295297
if sizing {
296-
fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
297-
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
298+
fields.filter(|ty| !dst || type_is_sized(cx.tcx(), *ty))
299+
.map(|ty| type_of::sizing_type_of(cx, ty)).collect()
298300
} else {
299-
fields.iter().map(|&ty| type_of::in_memory_type_of(cx, ty)).collect()
301+
fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
300302
}
301303
}
302304

@@ -564,16 +566,16 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
564566
fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
565567
st: &layout::Struct, fields: &Vec<Ty<'tcx>>, val: MaybeSizedValue,
566568
ix: usize, needs_cast: bool) -> ValueRef {
567-
let ccx = bcx.ccx();
568569
let fty = fields[ix];
570+
let ccx = bcx.ccx();
569571
let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
570572
if bcx.is_unreachable() {
571573
return C_undef(ll_fty.ptr_to());
572574
}
573575

574576
let ptr_val = if needs_cast {
575-
let fields = fields.iter().map(|&ty| {
576-
type_of::in_memory_type_of(ccx, ty)
577+
let fields = st.field_index_by_increasing_offset().map(|i| {
578+
type_of::in_memory_type_of(ccx, fields[i])
577579
}).collect::<Vec<_>>();
578580
let real_ty = Type::struct_(ccx, &fields[..], st.packed);
579581
bcx.pointercast(val.value, real_ty.ptr_to())
@@ -585,15 +587,15 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
585587
// * First field - Always aligned properly
586588
// * Packed struct - There is no alignment padding
587589
// * Field is sized - pointer is properly aligned already
588-
if ix == 0 || st.packed || type_is_sized(bcx.tcx(), fty) {
589-
return bcx.struct_gep(ptr_val, ix);
590+
if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed || type_is_sized(bcx.tcx(), fty) {
591+
return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
590592
}
591593

592594
// If the type of the last field is [T] or str, then we don't need to do
593595
// any adjusments
594596
match fty.sty {
595597
ty::TySlice(..) | ty::TyStr => {
596-
return bcx.struct_gep(ptr_val, ix);
598+
return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
597599
}
598600
_ => ()
599601
}
@@ -755,8 +757,12 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
755757
// offset of current value
756758
let mut offset = 0;
757759
let mut cfields = Vec::new();
758-
let offsets = st.offsets.iter().map(|i| i.bytes());
759-
for (&val, target_offset) in vals.iter().zip(offsets) {
760+
cfields.reserve(st.offsets.len()*2);
761+
762+
let parts = st.field_index_by_increasing_offset().map(|i| {
763+
(&vals[i], st.offsets[i].bytes())
764+
});
765+
for (&val, target_offset) in parts {
760766
if offset < target_offset {
761767
cfields.push(padding(ccx, target_offset - offset));
762768
offset = target_offset;
@@ -807,14 +813,11 @@ pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
807813
let l = ccx.layout_of(t);
808814
match *l {
809815
layout::CEnum { .. } => bug!("element access in C-like enum const"),
810-
layout::Univariant { .. } | layout::Vector { .. } => const_struct_field(val, ix),
816+
layout::Univariant { ref variant, .. } => {
817+
const_struct_field(val, variant.memory_index[ix] as usize)
818+
}
819+
layout::Vector { .. } => const_struct_field(val, ix),
811820
layout::UntaggedUnion { .. } => const_struct_field(val, 0),
812-
layout::General { .. } => const_struct_field(val, ix + 1),
813-
layout::RawNullablePointer { .. } => {
814-
assert_eq!(ix, 0);
815-
val
816-
},
817-
layout::StructWrappedNullablePointer{ .. } => const_struct_field(val, ix),
818821
_ => bug!("{} does not have fields.", t)
819822
}
820823
}

src/librustc_trans/base.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,9 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
827827
}
828828
}
829829
DebugLoc::None.apply(cx.fcx);
830-
Alloca(cx, ty, name)
830+
let result = Alloca(cx, ty, name);
831+
debug!("alloca({:?}) = {:?}", name, result);
832+
result
831833
}
832834

833835
impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
@@ -1868,7 +1870,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
18681870
match **layout {
18691871
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
18701872
nndiscr,
1871-
discrfield: _ } => {
1873+
discrfield: _,
1874+
discrfield_source: _ } => {
18721875
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
18731876
ty, nndiscr, variant_layout);
18741877
let variant_def = &adt_def.variants[nndiscr as usize];

src/librustc_trans/debuginfo/metadata.rs

+34-23
Original file line numberDiff line numberDiff line change
@@ -870,25 +870,28 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
870870

871871
// Creates MemberDescriptions for the fields of a struct
872872
struct StructMemberDescriptionFactory<'tcx> {
873+
ty: Ty<'tcx>,
873874
variant: &'tcx ty::VariantDef,
874875
substs: &'tcx Substs<'tcx>,
875-
is_simd: bool,
876876
span: Span,
877877
}
878878

879879
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
880880
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
881881
-> Vec<MemberDescription> {
882-
let field_size = if self.is_simd {
883-
let fty = monomorphize::field_ty(cx.tcx(),
884-
self.substs,
885-
&self.variant.fields[0]);
886-
Some(machine::llsize_of_alloc(
887-
cx,
888-
type_of::type_of(cx, fty)
889-
) as usize)
890-
} else {
891-
None
882+
let layout = cx.layout_of(self.ty);
883+
884+
let tmp;
885+
let offsets = match *layout {
886+
layout::Univariant { ref variant, .. } => &variant.offsets,
887+
layout::Vector { element, count } => {
888+
let element_size = element.size(&cx.tcx().data_layout).bytes();
889+
tmp = (0..count).
890+
map(|i| layout::Size::from_bytes(i*element_size))
891+
.collect::<Vec<layout::Size>>();
892+
&tmp
893+
}
894+
_ => bug!("{} is not a struct", self.ty)
892895
};
893896

894897
self.variant.fields.iter().enumerate().map(|(i, f)| {
@@ -899,11 +902,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
899902
};
900903
let fty = monomorphize::field_ty(cx.tcx(), self.substs, f);
901904

902-
let offset = if self.is_simd {
903-
FixedMemberOffset { bytes: i * field_size.unwrap() }
904-
} else {
905-
ComputedMemberOffset
906-
};
905+
let offset = FixedMemberOffset { bytes: offsets[i].bytes() as usize};
907906

908907
MemberDescription {
909908
name: name,
@@ -945,9 +944,9 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
945944
struct_metadata_stub,
946945
struct_llvm_type,
947946
StructMDF(StructMemberDescriptionFactory {
947+
ty: struct_type,
948948
variant: variant,
949949
substs: substs,
950-
is_simd: struct_type.is_simd(),
951950
span: span,
952951
})
953952
)
@@ -959,13 +958,21 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
959958

960959
// Creates MemberDescriptions for the fields of a tuple
961960
struct TupleMemberDescriptionFactory<'tcx> {
961+
ty: Ty<'tcx>,
962962
component_types: Vec<Ty<'tcx>>,
963963
span: Span,
964964
}
965965

966966
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
967967
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
968968
-> Vec<MemberDescription> {
969+
let layout = cx.layout_of(self.ty);
970+
let offsets = if let layout::Univariant { ref variant, .. } = *layout {
971+
&variant.offsets
972+
} else {
973+
bug!("{} is not a tuple", self.ty);
974+
};
975+
969976
self.component_types
970977
.iter()
971978
.enumerate()
@@ -974,7 +981,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
974981
name: format!("__{}", i),
975982
llvm_type: type_of::type_of(cx, component_type),
976983
type_metadata: type_metadata(cx, component_type, self.span),
977-
offset: ComputedMemberOffset,
984+
offset: FixedMemberOffset { bytes: offsets[i].bytes() as usize },
978985
flags: DIFlags::FlagZero,
979986
}
980987
}).collect()
@@ -1001,6 +1008,7 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
10011008
NO_SCOPE_METADATA),
10021009
tuple_llvm_type,
10031010
TupleMDF(TupleMemberDescriptionFactory {
1011+
ty: tuple_type,
10041012
component_types: component_types.to_vec(),
10051013
span: span,
10061014
})
@@ -1239,7 +1247,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
12391247
},
12401248
layout::StructWrappedNullablePointer { nonnull: ref struct_def,
12411249
nndiscr,
1242-
ref discrfield, ..} => {
1250+
ref discrfield_source, ..} => {
12431251
// Create a description of the non-null variant
12441252
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
12451253
describe_enum_variant(cx,
@@ -1262,12 +1270,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
12621270
// member's name.
12631271
let null_variant_index = (1 - nndiscr) as usize;
12641272
let null_variant_name = adt.variants[null_variant_index].name;
1265-
let discrfield = discrfield.iter()
1273+
let discrfield_source = discrfield_source.iter()
12661274
.skip(1)
12671275
.map(|x| x.to_string())
12681276
.collect::<Vec<_>>().join("$");
12691277
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
1270-
discrfield,
1278+
discrfield_source,
12711279
null_variant_name);
12721280

12731281
// Create the (singleton) list of descriptions of union members.
@@ -1289,6 +1297,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
12891297

12901298
// Creates MemberDescriptions for the fields of a single enum variant.
12911299
struct VariantMemberDescriptionFactory<'tcx> {
1300+
// Cloned from the layout::Struct describing the variant.
1301+
offsets: &'tcx [layout::Size],
12921302
args: Vec<(String, Ty<'tcx>)>,
12931303
discriminant_type_metadata: Option<DIType>,
12941304
span: Span,
@@ -1305,7 +1315,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
13051315
Some(metadata) if i == 0 => metadata,
13061316
_ => type_metadata(cx, ty, self.span)
13071317
},
1308-
offset: ComputedMemberOffset,
1318+
offset: FixedMemberOffset { bytes: self.offsets[i].bytes() as usize },
13091319
flags: DIFlags::FlagZero
13101320
}
13111321
}).collect()
@@ -1325,7 +1335,7 @@ enum EnumDiscriminantInfo {
13251335
// full RecursiveTypeDescription.
13261336
fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
13271337
enum_type: Ty<'tcx>,
1328-
struct_def: &layout::Struct,
1338+
struct_def: &'tcx layout::Struct,
13291339
variant: &'tcx ty::VariantDef,
13301340
discriminant_info: EnumDiscriminantInfo,
13311341
containing_scope: DIScope,
@@ -1409,6 +1419,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
14091419

14101420
let member_description_factory =
14111421
VariantMDF(VariantMemberDescriptionFactory {
1422+
offsets: &struct_def.offsets[..],
14121423
args: args,
14131424
discriminant_type_metadata: match discriminant_info {
14141425
RegularDiscriminant(discriminant_type_metadata) => {

0 commit comments

Comments
 (0)