Skip to content

Commit e954fc4

Browse files
committed
librustc: Traverse arbitrarily deep for nullable enum opt.
1 parent 3e6b29f commit e954fc4

File tree

3 files changed

+84
-97
lines changed

3 files changed

+84
-97
lines changed

src/librustc_trans/trans/adt.rs

Lines changed: 76 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,13 @@
4343
4444
#![allow(unsigned_negation)]
4545

46-
pub use self::PointerField::*;
4746
pub use self::Repr::*;
4847

4948
use std::num::Int;
5049
use std::rc::Rc;
5150

5251
use llvm::{ValueRef, True, IntEQ, IntNE};
53-
use back::abi;
52+
use back::abi::FAT_PTR_ADDR;
5453
use middle::subst;
5554
use middle::subst::Subst;
5655
use trans::_match;
@@ -71,7 +70,6 @@ use util::ppaux::ty_to_string;
7170

7271
type Hint = attr::ReprAttr;
7372

74-
7573
/// Representations.
7674
#[deriving(Eq, PartialEq, Show)]
7775
pub enum Repr<'tcx> {
@@ -101,7 +99,7 @@ pub enum Repr<'tcx> {
10199
nullfields: Vec<Ty<'tcx>>
102100
},
103101
/// Two cases distinguished by a nullable pointer: the case with discriminant
104-
/// `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th
102+
/// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
105103
/// field is known to be nonnull due to its type; if that field is null, then
106104
/// it represents the other case, which is inhabited by at most one value
107105
/// (and all other fields are undefined/unused).
@@ -112,7 +110,7 @@ pub enum Repr<'tcx> {
112110
StructWrappedNullablePointer {
113111
nonnull: Struct<'tcx>,
114112
nndiscr: Disr,
115-
ptrfield: PointerField,
113+
discrfield: DiscrField,
116114
nullfields: Vec<Ty<'tcx>>,
117115
}
118116
}
@@ -230,18 +228,20 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
230228
let st = mk_struct(cx, cases[discr].tys[],
231229
false, t);
232230
match cases[discr].find_ptr(cx) {
233-
Some(ThinPointer(_)) if st.fields.len() == 1 => {
231+
Some(ref pf) if pf.len() == 1 && st.fields.len() == 1 => {
234232
return RawNullablePointer {
235233
nndiscr: discr as Disr,
236234
nnty: st.fields[0],
237235
nullfields: cases[1 - discr].tys.clone()
238236
};
239237
}
240-
Some(ptrfield) => {
238+
Some(pf) => {
239+
let mut discrfield = vec![0];
240+
discrfield.extend(pf.into_iter());
241241
return StructWrappedNullablePointer {
242242
nndiscr: discr as Disr,
243243
nonnull: st,
244-
ptrfield: ptrfield,
244+
discrfield: discrfield,
245245
nullfields: cases[1 - discr].tys.clone()
246246
};
247247
}
@@ -335,49 +335,67 @@ struct Case<'tcx> {
335335
tys: Vec<Ty<'tcx>>
336336
}
337337

338+
/// This represents the (GEP) indices to follow to get to the discriminant field
339+
pub type DiscrField = Vec<uint>;
338340

339-
#[deriving(Copy, Eq, PartialEq, Show)]
340-
pub enum PointerField {
341-
ThinPointer(uint),
342-
FatPointer(uint)
343-
}
341+
fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Option<DiscrField> {
342+
match ty.sty {
343+
// &T/&mut T/Box<T> could either be a thin or fat pointer depending on T
344+
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty {
345+
// &[T] and &str are a pointer and length pair
346+
ty::ty_vec(_, None) | ty::ty_str => Some(vec![FAT_PTR_ADDR]),
344347

345-
impl<'tcx> Case<'tcx> {
346-
fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>)
347-
-> bool {
348-
mk_struct(cx, self.tys[], false, scapegoat).size == 0
349-
}
348+
ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]),
350349

351-
fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<PointerField> {
352-
for (i, &ty) in self.tys.iter().enumerate() {
353-
match ty.sty {
354-
// &T/&mut T/Box<T> could either be a thin or fat pointer depending on T
355-
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty {
356-
// &[T] and &str are a pointer and length pair
357-
ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i)),
350+
// Any other &T is just a pointer
351+
_ => Some(vec![])
352+
},
358353

359-
// &Trait is a pair of pointers: the actual object and a vtable
360-
ty::ty_trait(..) => return Some(FatPointer(i)),
354+
// Functions are just pointers
355+
ty::ty_bare_fn(..) => Some(vec![]),
361356

362-
ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => {
363-
return Some(FatPointer(i))
364-
}
357+
// Closures are a pair of pointers: the code and environment
358+
ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]),
365359

366-
// Any other &T is just a pointer
367-
_ => return Some(ThinPointer(i))
368-
},
360+
// Perhaps one of the fields of this struct is non-null
361+
// let's recurse and find out
362+
ty::ty_struct(def_id, ref substs) => {
363+
let fields = ty::lookup_struct_fields(tcx, def_id);
364+
for (j, field) in fields.iter().enumerate() {
365+
let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs);
366+
match find_discr_field_candidate(tcx, field_ty) {
367+
Some(v) => {
368+
let mut discrfield = vec![j];
369+
discrfield.extend(v.into_iter());
370+
return Some(discrfield);
371+
}
372+
None => continue
373+
}
374+
}
375+
None
376+
},
369377

370-
// Functions are just pointers
371-
ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
378+
// Anything else is not a pointer
379+
_ => None
380+
}
381+
}
372382

373-
// Closures are a pair of pointers: the code and environment
374-
ty::ty_closure(..) => return Some(FatPointer(i)),
383+
impl<'tcx> Case<'tcx> {
384+
fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool {
385+
mk_struct(cx, self.tys[], false, scapegoat).size == 0
386+
}
375387

376-
// Anything else is not a pointer
377-
_ => continue
388+
fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<DiscrField> {
389+
for (i, &ty) in self.tys.iter().enumerate() {
390+
match find_discr_field_candidate(cx.tcx(), ty) {
391+
Some(v) => {
392+
let mut discrfield = vec![i];
393+
discrfield.extend(v.into_iter());
394+
return Some(discrfield);
395+
}
396+
None => continue
378397
}
379398
}
380-
381399
None
382400
}
383401
}
@@ -709,8 +727,8 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
709727
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty));
710728
signed = false;
711729
}
712-
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
713-
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee);
730+
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
731+
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee);
714732
signed = false;
715733
}
716734
}
@@ -720,12 +738,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
720738
}
721739
}
722740

723-
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, ptrfield: PointerField,
741+
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &DiscrField,
724742
scrutinee: ValueRef) -> ValueRef {
725-
let llptrptr = match ptrfield {
726-
ThinPointer(field) => GEPi(bcx, scrutinee, &[0, field]),
727-
FatPointer(field) => GEPi(bcx, scrutinee, &[0, field, abi::FAT_PTR_ADDR])
728-
};
743+
let llptrptr = GEPi(bcx, scrutinee, discrfield[]);
729744
let llptr = Load(bcx, llptrptr);
730745
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
731746
ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)))
@@ -811,17 +826,10 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
811826
Store(bcx, C_null(llptrty), val)
812827
}
813828
}
814-
StructWrappedNullablePointer { ref nonnull, nndiscr, ptrfield, .. } => {
829+
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
815830
if discr != nndiscr {
816-
let (llptrptr, llptrty) = match ptrfield {
817-
ThinPointer(field) =>
818-
(GEPi(bcx, val, &[0, field]),
819-
type_of::type_of(bcx.ccx(), nonnull.fields[field])),
820-
FatPointer(field) => {
821-
let v = GEPi(bcx, val, &[0, field, abi::FAT_PTR_ADDR]);
822-
(v, val_ty(v).element_type())
823-
}
824-
};
831+
let llptrptr = GEPi(bcx, val, discrfield[]);
832+
let llptrty = val_ty(llptrptr).element_type();
825833
Store(bcx, C_null(llptrty), llptrptr)
826834
}
827835
}
@@ -1041,7 +1049,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
10411049
false)
10421050
} else {
10431051
let vals = nonnull.fields.iter().map(|&ty| {
1044-
// Always use null even if it's not the `ptrfield`th
1052+
// Always use null even if it's not the `discrfield`th
10451053
// field; see #8506.
10461054
C_null(type_of::sizing_type_of(ccx, ty))
10471055
}).collect::<Vec<ValueRef>>();
@@ -1121,9 +1129,8 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
11211129
#[inline]
11221130
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
11231131

1124-
/// Get the discriminant of a constant value. (Not currently used.)
1125-
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
1126-
-> Disr {
1132+
/// Get the discriminant of a constant value.
1133+
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr {
11271134
match *r {
11281135
CEnum(ity, _, _) => {
11291136
match ity {
@@ -1138,25 +1145,8 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
11381145
}
11391146
}
11401147
Univariant(..) => 0,
1141-
RawNullablePointer { nndiscr, .. } => {
1142-
if is_null(val) {
1143-
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
1144-
(1 - nndiscr) as Disr
1145-
} else {
1146-
nndiscr
1147-
}
1148-
}
1149-
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
1150-
let (idx, sub_idx) = match ptrfield {
1151-
ThinPointer(field) => (field, None),
1152-
FatPointer(field) => (field, Some(abi::FAT_PTR_ADDR))
1153-
};
1154-
if is_null(const_struct_field(ccx, val, idx, sub_idx)) {
1155-
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
1156-
(1 - nndiscr) as Disr
1157-
} else {
1158-
nndiscr
1159-
}
1148+
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1149+
ccx.sess().bug("const discrim access of non c-like enum")
11601150
}
11611151
}
11621152
}
@@ -1170,29 +1160,25 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
11701160
_discr: Disr, ix: uint) -> ValueRef {
11711161
match *r {
11721162
CEnum(..) => ccx.sess().bug("element access in C-like enum const"),
1173-
Univariant(..) => const_struct_field(ccx, val, ix, None),
1174-
General(..) => const_struct_field(ccx, val, ix + 1, None),
1163+
Univariant(..) => const_struct_field(ccx, val, ix),
1164+
General(..) => const_struct_field(ccx, val, ix + 1),
11751165
RawNullablePointer { .. } => {
11761166
assert_eq!(ix, 0);
11771167
val
1178-
}
1179-
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None)
1168+
},
1169+
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix)
11801170
}
11811171
}
11821172

11831173
/// Extract field of struct-like const, skipping our alignment padding.
1184-
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option<uint>)
1185-
-> ValueRef {
1174+
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint) -> ValueRef {
11861175
// Get the ix-th non-undef element of the struct.
11871176
let mut real_ix = 0; // actual position in the struct
11881177
let mut ix = ix; // logical index relative to real_ix
11891178
let mut field;
11901179
loop {
11911180
loop {
1192-
field = match sub_idx {
1193-
Some(si) => const_get_elt(ccx, val, &[real_ix, si as u32]),
1194-
None => const_get_elt(ccx, val, &[real_ix])
1195-
};
1181+
field = const_get_elt(ccx, val, &[real_ix]);
11961182
if !is_undef(field) {
11971183
break;
11981184
}

src/librustc_trans/trans/common.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,7 @@ pub fn is_undef(val: ValueRef) -> bool {
750750
}
751751
}
752752

753+
#[allow(dead_code)] // potentially useful
753754
pub fn is_null(val: ValueRef) -> bool {
754755
unsafe {
755756
llvm::LLVMIsNull(val) != False

src/librustc_trans/trans/debuginfo.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,14 +2292,14 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
22922292
},
22932293
adt::StructWrappedNullablePointer { nonnull: ref struct_def,
22942294
nndiscr,
2295-
ptrfield, ..} => {
2295+
ref discrfield, ..} => {
22962296
// Create a description of the non-null variant
22972297
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
22982298
describe_enum_variant(cx,
22992299
self.enum_type,
23002300
struct_def,
23012301
&*(*self.variants)[nndiscr as uint],
2302-
OptimizedDiscriminant(ptrfield),
2302+
OptimizedDiscriminant,
23032303
self.containing_scope,
23042304
self.span);
23052305

@@ -2315,10 +2315,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
23152315
// member's name.
23162316
let null_variant_index = (1 - nndiscr) as uint;
23172317
let null_variant_name = token::get_name((*self.variants)[null_variant_index].name);
2318-
let discrfield = match ptrfield {
2319-
adt::ThinPointer(field) => format!("{}", field),
2320-
adt::FatPointer(field) => format!("{}", field)
2321-
};
2318+
let discrfield = discrfield.iter()
2319+
.skip(1)
2320+
.map(|x| x.to_string())
2321+
.collect::<Vec<_>>().connect("$");
23222322
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
23232323
discrfield,
23242324
null_variant_name);
@@ -2367,7 +2367,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
23672367
#[deriving(Copy)]
23682368
enum EnumDiscriminantInfo {
23692369
RegularDiscriminant(DIType),
2370-
OptimizedDiscriminant(adt::PointerField),
2370+
OptimizedDiscriminant,
23712371
NoDiscriminant
23722372
}
23732373

0 commit comments

Comments
 (0)