fix null optimizations for smaller than pointer enums

fixes #76
This commit is contained in:
Oliver 'ker' Schneider 2016-11-11 13:10:47 +01:00
parent 1c40fb0da1
commit d42a7d021d
3 changed files with 32 additions and 17 deletions

View File

@ -203,10 +203,6 @@ fn usize_primval(&self, n: u64) -> PrimVal {
PrimVal::from_uint_with_size(n, self.memory.pointer_size())
}
fn isize_primval(&self, n: i64) -> PrimVal {
PrimVal::from_int_with_size(n, self.memory.pointer_size())
}
fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
// FIXME: cache these allocs
let ptr = self.memory.allocate(s.len(), 1)?;
@ -523,7 +519,8 @@ fn eval_rvalue_into_lvalue(
self.write_value(value, dest, value_ty)?;
} else {
assert_eq!(operands.len(), 0);
let zero = self.isize_primval(0);
let value_size = self.type_size(dest_ty).expect("pointer types are sized");
let zero = PrimVal::from_int_with_size(0, value_size);
self.write_primval(dest, zero)?;
}
} else {
@ -541,13 +538,14 @@ fn eval_rvalue_into_lvalue(
let operand_ty = self.operand_ty(operand);
assert_eq!(self.type_size(operand_ty), Some(0));
}
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
// FIXME(solson)
let dest = self.force_allocation(dest)?.to_ptr();
let dest = dest.offset(offset.bytes() as isize);
try!(self.memory.write_isize(dest, 0));
let dest_size = self.type_size(ty).unwrap_or(self.memory.pointer_size());
try!(self.memory.write_int(dest, 0, dest_size));
}
} else {
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
@ -694,7 +692,7 @@ fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
}
}
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<'tcx, Size> {
fn nonnull_offset_and_ty(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
// Skip the constant 0 at the start meant for LLVM GEP.
let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
@ -709,10 +707,10 @@ fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> Eval
_ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
};
self.field_path_offset(inner_ty, path)
self.field_path_offset_and_ty(inner_ty, path)
}
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, Size> {
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
let mut offset = Size::from_bytes(0);
// Skip the initial 0 intended for LLVM GEP.
@ -722,7 +720,7 @@ fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
}
Ok(offset)
Ok((offset, ty))
}
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {

View File

@ -263,14 +263,17 @@ fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalRes
self.memory.read_int(adt_ptr, discr_size as usize)? as u64
}
RawNullablePointer { nndiscr, .. } => {
self.read_nonnull_discriminant_value(adt_ptr, nndiscr)?
RawNullablePointer { nndiscr, value } => {
let discr_size = value.size(&self.tcx.data_layout).bytes() as usize;
self.read_nonnull_discriminant_value(adt_ptr, nndiscr, discr_size)?
}
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield)?;
let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
let nonnull = adt_ptr.offset(offset.bytes() as isize);
self.read_nonnull_discriminant_value(nonnull, nndiscr)?
// only the pointer part of a fat pointer is used for this space optimization
let discr_size = self.type_size(ty).unwrap_or(self.memory.pointer_size());
self.read_nonnull_discriminant_value(nonnull, nndiscr, discr_size)?
}
// The discriminant_value intrinsic returns 0 for non-sum types.
@ -281,8 +284,8 @@ fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalRes
Ok(discr_val)
}
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<'tcx, u64> {
let not_null = match self.memory.read_usize(ptr) {
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64, discr_size: usize) -> EvalResult<'tcx, u64> {
let not_null = match self.memory.read_uint(ptr, discr_size) {
Ok(0) => false,
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
Err(e) => return Err(e),

View File

@ -0,0 +1,14 @@
#![allow(dead_code)]
enum E {
A = 1,
B = 2,
C = 3,
}
fn main() {
let enone = None::<E>;
if let Some(..) = enone {
panic!();
}
}