librustc: Traverse arbitrarily deep for nullable enum opt.
This commit is contained in:
parent
3e6b29f8ad
commit
e954fc4385
@ -43,14 +43,13 @@
|
||||
|
||||
#![allow(unsigned_negation)]
|
||||
|
||||
pub use self::PointerField::*;
|
||||
pub use self::Repr::*;
|
||||
|
||||
use std::num::Int;
|
||||
use std::rc::Rc;
|
||||
|
||||
use llvm::{ValueRef, True, IntEQ, IntNE};
|
||||
use back::abi;
|
||||
use back::abi::FAT_PTR_ADDR;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use trans::_match;
|
||||
@ -71,7 +70,6 @@ use util::ppaux::ty_to_string;
|
||||
|
||||
type Hint = attr::ReprAttr;
|
||||
|
||||
|
||||
/// Representations.
|
||||
#[deriving(Eq, PartialEq, Show)]
|
||||
pub enum Repr<'tcx> {
|
||||
@ -101,7 +99,7 @@ pub enum Repr<'tcx> {
|
||||
nullfields: Vec<Ty<'tcx>>
|
||||
},
|
||||
/// Two cases distinguished by a nullable pointer: the case with discriminant
|
||||
/// `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th
|
||||
/// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
|
||||
/// field is known to be nonnull due to its type; if that field is null, then
|
||||
/// it represents the other case, which is inhabited by at most one value
|
||||
/// (and all other fields are undefined/unused).
|
||||
@ -112,7 +110,7 @@ pub enum Repr<'tcx> {
|
||||
StructWrappedNullablePointer {
|
||||
nonnull: Struct<'tcx>,
|
||||
nndiscr: Disr,
|
||||
ptrfield: PointerField,
|
||||
discrfield: DiscrField,
|
||||
nullfields: Vec<Ty<'tcx>>,
|
||||
}
|
||||
}
|
||||
@ -230,18 +228,20 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
let st = mk_struct(cx, cases[discr].tys[],
|
||||
false, t);
|
||||
match cases[discr].find_ptr(cx) {
|
||||
Some(ThinPointer(_)) if st.fields.len() == 1 => {
|
||||
Some(ref pf) if pf.len() == 1 && st.fields.len() == 1 => {
|
||||
return RawNullablePointer {
|
||||
nndiscr: discr as Disr,
|
||||
nnty: st.fields[0],
|
||||
nullfields: cases[1 - discr].tys.clone()
|
||||
};
|
||||
}
|
||||
Some(ptrfield) => {
|
||||
Some(pf) => {
|
||||
let mut discrfield = vec![0];
|
||||
discrfield.extend(pf.into_iter());
|
||||
return StructWrappedNullablePointer {
|
||||
nndiscr: discr as Disr,
|
||||
nonnull: st,
|
||||
ptrfield: ptrfield,
|
||||
discrfield: discrfield,
|
||||
nullfields: cases[1 - discr].tys.clone()
|
||||
};
|
||||
}
|
||||
@ -335,49 +335,67 @@ struct Case<'tcx> {
|
||||
tys: Vec<Ty<'tcx>>
|
||||
}
|
||||
|
||||
/// This represents the (GEP) indices to follow to get to the discriminant field
|
||||
pub type DiscrField = Vec<uint>;
|
||||
|
||||
#[deriving(Copy, Eq, PartialEq, Show)]
|
||||
pub enum PointerField {
|
||||
ThinPointer(uint),
|
||||
FatPointer(uint)
|
||||
fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Option<DiscrField> {
|
||||
match ty.sty {
|
||||
// &T/&mut T/Box<T> could either be a thin or fat pointer depending on T
|
||||
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty {
|
||||
// &[T] and &str are a pointer and length pair
|
||||
ty::ty_vec(_, None) | ty::ty_str => Some(vec![FAT_PTR_ADDR]),
|
||||
|
||||
ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]),
|
||||
|
||||
// Any other &T is just a pointer
|
||||
_ => Some(vec![])
|
||||
},
|
||||
|
||||
// Functions are just pointers
|
||||
ty::ty_bare_fn(..) => Some(vec![]),
|
||||
|
||||
// Closures are a pair of pointers: the code and environment
|
||||
ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]),
|
||||
|
||||
// Perhaps one of the fields of this struct is non-null
|
||||
// let's recurse and find out
|
||||
ty::ty_struct(def_id, ref substs) => {
|
||||
let fields = ty::lookup_struct_fields(tcx, def_id);
|
||||
for (j, field) in fields.iter().enumerate() {
|
||||
let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs);
|
||||
match find_discr_field_candidate(tcx, field_ty) {
|
||||
Some(v) => {
|
||||
let mut discrfield = vec![j];
|
||||
discrfield.extend(v.into_iter());
|
||||
return Some(discrfield);
|
||||
}
|
||||
None => continue
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
|
||||
// Anything else is not a pointer
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Case<'tcx> {
|
||||
fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>)
|
||||
-> bool {
|
||||
fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool {
|
||||
mk_struct(cx, self.tys[], false, scapegoat).size == 0
|
||||
}
|
||||
|
||||
fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<PointerField> {
|
||||
fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<DiscrField> {
|
||||
for (i, &ty) in self.tys.iter().enumerate() {
|
||||
match ty.sty {
|
||||
// &T/&mut T/Box<T> could either be a thin or fat pointer depending on T
|
||||
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty {
|
||||
// &[T] and &str are a pointer and length pair
|
||||
ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i)),
|
||||
|
||||
// &Trait is a pair of pointers: the actual object and a vtable
|
||||
ty::ty_trait(..) => return Some(FatPointer(i)),
|
||||
|
||||
ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => {
|
||||
return Some(FatPointer(i))
|
||||
}
|
||||
|
||||
// Any other &T is just a pointer
|
||||
_ => return Some(ThinPointer(i))
|
||||
},
|
||||
|
||||
// Functions are just pointers
|
||||
ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
|
||||
|
||||
// Closures are a pair of pointers: the code and environment
|
||||
ty::ty_closure(..) => return Some(FatPointer(i)),
|
||||
|
||||
// Anything else is not a pointer
|
||||
_ => continue
|
||||
match find_discr_field_candidate(cx.tcx(), ty) {
|
||||
Some(v) => {
|
||||
let mut discrfield = vec![i];
|
||||
discrfield.extend(v.into_iter());
|
||||
return Some(discrfield);
|
||||
}
|
||||
None => continue
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -709,8 +727,8 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
|
||||
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty));
|
||||
signed = false;
|
||||
}
|
||||
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
|
||||
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee);
|
||||
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
||||
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee);
|
||||
signed = false;
|
||||
}
|
||||
}
|
||||
@ -720,12 +738,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, ptrfield: PointerField,
|
||||
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &DiscrField,
|
||||
scrutinee: ValueRef) -> ValueRef {
|
||||
let llptrptr = match ptrfield {
|
||||
ThinPointer(field) => GEPi(bcx, scrutinee, &[0, field]),
|
||||
FatPointer(field) => GEPi(bcx, scrutinee, &[0, field, abi::FAT_PTR_ADDR])
|
||||
};
|
||||
let llptrptr = GEPi(bcx, scrutinee, discrfield[]);
|
||||
let llptr = Load(bcx, llptrptr);
|
||||
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
|
||||
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>,
|
||||
Store(bcx, C_null(llptrty), val)
|
||||
}
|
||||
}
|
||||
StructWrappedNullablePointer { ref nonnull, nndiscr, ptrfield, .. } => {
|
||||
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
||||
if discr != nndiscr {
|
||||
let (llptrptr, llptrty) = match ptrfield {
|
||||
ThinPointer(field) =>
|
||||
(GEPi(bcx, val, &[0, field]),
|
||||
type_of::type_of(bcx.ccx(), nonnull.fields[field])),
|
||||
FatPointer(field) => {
|
||||
let v = GEPi(bcx, val, &[0, field, abi::FAT_PTR_ADDR]);
|
||||
(v, val_ty(v).element_type())
|
||||
}
|
||||
};
|
||||
let llptrptr = GEPi(bcx, val, discrfield[]);
|
||||
let llptrty = val_ty(llptrptr).element_type();
|
||||
Store(bcx, C_null(llptrty), llptrptr)
|
||||
}
|
||||
}
|
||||
@ -1041,7 +1049,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
|
||||
false)
|
||||
} else {
|
||||
let vals = nonnull.fields.iter().map(|&ty| {
|
||||
// Always use null even if it's not the `ptrfield`th
|
||||
// Always use null even if it's not the `discrfield`th
|
||||
// field; see #8506.
|
||||
C_null(type_of::sizing_type_of(ccx, ty))
|
||||
}).collect::<Vec<ValueRef>>();
|
||||
@ -1121,9 +1129,8 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
|
||||
#[inline]
|
||||
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
|
||||
|
||||
/// Get the discriminant of a constant value. (Not currently used.)
|
||||
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
|
||||
-> Disr {
|
||||
/// Get the discriminant of a constant value.
|
||||
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr {
|
||||
match *r {
|
||||
CEnum(ity, _, _) => {
|
||||
match ity {
|
||||
@ -1138,25 +1145,8 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
|
||||
}
|
||||
}
|
||||
Univariant(..) => 0,
|
||||
RawNullablePointer { nndiscr, .. } => {
|
||||
if is_null(val) {
|
||||
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
|
||||
(1 - nndiscr) as Disr
|
||||
} else {
|
||||
nndiscr
|
||||
}
|
||||
}
|
||||
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
|
||||
let (idx, sub_idx) = match ptrfield {
|
||||
ThinPointer(field) => (field, None),
|
||||
FatPointer(field) => (field, Some(abi::FAT_PTR_ADDR))
|
||||
};
|
||||
if is_null(const_struct_field(ccx, val, idx, sub_idx)) {
|
||||
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
|
||||
(1 - nndiscr) as Disr
|
||||
} else {
|
||||
nndiscr
|
||||
}
|
||||
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
|
||||
ccx.sess().bug("const discrim access of non c-like enum")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1170,29 +1160,25 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
|
||||
_discr: Disr, ix: uint) -> ValueRef {
|
||||
match *r {
|
||||
CEnum(..) => ccx.sess().bug("element access in C-like enum const"),
|
||||
Univariant(..) => const_struct_field(ccx, val, ix, None),
|
||||
General(..) => const_struct_field(ccx, val, ix + 1, None),
|
||||
Univariant(..) => const_struct_field(ccx, val, ix),
|
||||
General(..) => const_struct_field(ccx, val, ix + 1),
|
||||
RawNullablePointer { .. } => {
|
||||
assert_eq!(ix, 0);
|
||||
val
|
||||
}
|
||||
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None)
|
||||
},
|
||||
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract field of struct-like const, skipping our alignment padding.
|
||||
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option<uint>)
|
||||
-> ValueRef {
|
||||
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint) -> ValueRef {
|
||||
// Get the ix-th non-undef element of the struct.
|
||||
let mut real_ix = 0; // actual position in the struct
|
||||
let mut ix = ix; // logical index relative to real_ix
|
||||
let mut field;
|
||||
loop {
|
||||
loop {
|
||||
field = match sub_idx {
|
||||
Some(si) => const_get_elt(ccx, val, &[real_ix, si as u32]),
|
||||
None => const_get_elt(ccx, val, &[real_ix])
|
||||
};
|
||||
field = const_get_elt(ccx, val, &[real_ix]);
|
||||
if !is_undef(field) {
|
||||
break;
|
||||
}
|
||||
|
@ -750,6 +750,7 @@ pub fn is_undef(val: ValueRef) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // potentially useful
|
||||
pub fn is_null(val: ValueRef) -> bool {
|
||||
unsafe {
|
||||
llvm::LLVMIsNull(val) != False
|
||||
|
@ -2292,14 +2292,14 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
},
|
||||
adt::StructWrappedNullablePointer { nonnull: ref struct_def,
|
||||
nndiscr,
|
||||
ptrfield, ..} => {
|
||||
ref discrfield, ..} => {
|
||||
// Create a description of the non-null variant
|
||||
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
struct_def,
|
||||
&*(*self.variants)[nndiscr as uint],
|
||||
OptimizedDiscriminant(ptrfield),
|
||||
OptimizedDiscriminant,
|
||||
self.containing_scope,
|
||||
self.span);
|
||||
|
||||
@ -2315,10 +2315,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
// member's name.
|
||||
let null_variant_index = (1 - nndiscr) as uint;
|
||||
let null_variant_name = token::get_name((*self.variants)[null_variant_index].name);
|
||||
let discrfield = match ptrfield {
|
||||
adt::ThinPointer(field) => format!("{}", field),
|
||||
adt::FatPointer(field) => format!("{}", field)
|
||||
};
|
||||
let discrfield = discrfield.iter()
|
||||
.skip(1)
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>().connect("$");
|
||||
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
|
||||
discrfield,
|
||||
null_variant_name);
|
||||
@ -2367,7 +2367,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
|
||||
#[deriving(Copy)]
|
||||
enum EnumDiscriminantInfo {
|
||||
RegularDiscriminant(DIType),
|
||||
OptimizedDiscriminant(adt::PointerField),
|
||||
OptimizedDiscriminant,
|
||||
NoDiscriminant
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user