diff --git a/src/cast.rs b/src/cast.rs index b50684283c84..2b3194a59940 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -20,9 +20,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { F32 => self.cast_float(val.to_f32()? as f64, dest_ty), F64 => self.cast_float(val.to_f64()?, dest_ty), - I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits() as i64, dest_ty), + I8 | I16 | I32 | I64 => self.cast_signed_int(val.to_i64()?, dest_ty), - Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits(), dest_ty, false), + Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.to_u64()?, dest_ty, false), FnPtr | Ptr => self.cast_ptr(val.to_ptr()?, dest_ty), } diff --git a/src/eval_context.rs b/src/eval_context.rs index c1774099b8c5..7696a70f379a 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -1093,10 +1093,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> { match ty.sty { - ty::TyBool if val.bits() > 1 => Err(EvalError::InvalidBool), + ty::TyBool if val.to_bytes()? > 1 => Err(EvalError::InvalidBool), - ty::TyChar if ::std::char::from_u32(val.bits() as u32).is_none() - => Err(EvalError::InvalidChar(val.bits() as u32 as u64)), + ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() + => Err(EvalError::InvalidChar(val.to_bytes()? as u32 as u64)), _ => Ok(()), } diff --git a/src/memory.rs b/src/memory.rs index 90fbf04c73d4..d65bf7f14500 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -77,8 +77,7 @@ impl Pointer { pub fn to_int<'tcx>(&self) -> EvalResult<'tcx, u64> { match self.alloc_id { - NEVER_ALLOC_ID | - ZST_ALLOC_ID => Ok(self.offset), + NEVER_ALLOC_ID => Ok(self.offset), _ => Err(EvalError::ReadPointerAsBytes), } } diff --git a/src/operator.rs b/src/operator.rs index 4ef1ee86ce0e..1cf929b88668 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -139,16 +139,38 @@ pub fn binary_op<'tcx>( use rustc::mir::BinOp::*; use value::PrimValKind::*; - // If the pointers are into the same allocation, fall through to the more general match - // later, which will do comparisons on the `bits` fields, which are the pointer offsets - // in this case. - let left_ptr = left.to_ptr()?; - let right_ptr = right.to_ptr()?; - if left_ptr.alloc_id != right_ptr.alloc_id { - return Ok((unrelated_ptr_ops(bin_op, left_ptr, right_ptr)?, false)); + // FIXME(solson): Temporary hack. It will go away when we get rid of Pointer's ability to store + // plain bytes, and leave that to PrimVal::Bytes. + fn normalize(val: PrimVal) -> PrimVal { + if let PrimVal::Ptr(ptr) = val { + if let Ok(bytes) = ptr.to_int() { + return PrimVal::Bytes(bytes); + } + } + val } + let (left, right) = (normalize(left), normalize(right)); - let (l, r) = (left.bits(), right.bits()); + let (l, r) = match (left, right) { + (PrimVal::Bytes(left_bytes), PrimVal::Bytes(right_bytes)) => (left_bytes, right_bytes), + + (PrimVal::Ptr(left_ptr), PrimVal::Ptr(right_ptr)) => { + if left_ptr.alloc_id == right_ptr.alloc_id { + // If the pointers are into the same allocation, fall through to the more general + // match later, which will do comparisons on the pointer offsets. + (left_ptr.offset, right_ptr.offset) + } else { + return Ok((unrelated_ptr_ops(bin_op, left_ptr, right_ptr)?, false)); + } + } + + (PrimVal::Ptr(ptr), PrimVal::Bytes(bytes)) | + (PrimVal::Bytes(bytes), PrimVal::Ptr(ptr)) => { + return Ok((unrelated_ptr_ops(bin_op, ptr, Pointer::from_int(bytes))?, false)); + } + + (PrimVal::Undef, _) | (_, PrimVal::Undef) => return Err(EvalError::ReadUndefBytes), + }; // These ops can have an RHS with a different numeric type. if bin_op == Shl || bin_op == Shr { @@ -165,11 +187,11 @@ pub fn binary_op<'tcx>( // Cast to `u32` because `overflowing_sh{l,r}` only take `u32`, then apply the bitmask // to ensure it's within the valid shift value range. - let r = (right.bits() as u32) & (type_bits - 1); + let masked_shift_width = (r as u32) & (type_bits - 1); return match bin_op { - Shl => int_shift!(left_kind, overflowing_shl, l, r), - Shr => int_shift!(left_kind, overflowing_shr, l, r), + Shl => int_shift!(left_kind, overflowing_shl, l, masked_shift_width), + Shr => int_shift!(left_kind, overflowing_shr, l, masked_shift_width), _ => bug!("it has already been checked that this is a shift op"), }; } @@ -253,26 +275,28 @@ pub fn unary_op<'tcx>( use rustc::mir::UnOp::*; use value::PrimValKind::*; - let bits = match (un_op, val_kind) { - (Not, Bool) => !bits_to_bool(val.bits()) as u64, + let bytes = val.to_bytes()?; - (Not, U8) => !(val.bits() as u8) as u64, - (Not, U16) => !(val.bits() as u16) as u64, - (Not, U32) => !(val.bits() as u32) as u64, - (Not, U64) => !val.bits(), + let result_bytes = match (un_op, val_kind) { + (Not, Bool) => !bits_to_bool(bytes) as u64, - (Not, I8) => !(val.bits() as i8) as u64, - (Not, I16) => !(val.bits() as i16) as u64, - (Not, I32) => !(val.bits() as i32) as u64, - (Not, I64) => !(val.bits() as i64) as u64, + (Not, U8) => !(bytes as u8) as u64, + (Not, U16) => !(bytes as u16) as u64, + (Not, U32) => !(bytes as u32) as u64, + (Not, U64) => !bytes, - (Neg, I8) => -(val.bits() as i8) as u64, - (Neg, I16) => -(val.bits() as i16) as u64, - (Neg, I32) => -(val.bits() as i32) as u64, - (Neg, I64) => -(val.bits() as i64) as u64, + (Not, I8) => !(bytes as i8) as u64, + (Not, I16) => !(bytes as i16) as u64, + (Not, I32) => !(bytes as i32) as u64, + (Not, I64) => !(bytes as i64) as u64, - (Neg, F32) => f32_to_bits(-bits_to_f32(val.bits())), - (Neg, F64) => f64_to_bits(-bits_to_f64(val.bits())), + (Neg, I8) => -(bytes as i8) as u64, + (Neg, I16) => -(bytes as i16) as u64, + (Neg, I32) => -(bytes as i32) as u64, + (Neg, I64) => -(bytes as i64) as u64, + + (Neg, F32) => f32_to_bits(-bits_to_f32(bytes)), + (Neg, F64) => f64_to_bits(-bits_to_f64(bytes)), _ => { let msg = format!("unimplemented unary op: {:?}, {:?}", un_op, val); @@ -280,5 +304,5 @@ pub fn unary_op<'tcx>( } }; - Ok(PrimVal::Bytes(bits)) + Ok(PrimVal::Bytes(result_bytes)) } diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index af99d47dda77..a25d10d05aea 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let ty = substs.type_at(0); let num = self.value_to_primval(arg_vals[0], ty)?; let kind = self.ty_to_primval_kind(ty)?; - let num = numeric_intrinsic(intrinsic_name, num, kind); + let num = numeric_intrinsic(intrinsic_name, num, kind)?; self.write_primval(dest, num, ty)?; } @@ -501,33 +501,40 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } -macro_rules! integer_intrinsic { - ($name:expr, $val:expr, $kind:expr, $method:ident) => ({ - let val = $val; +fn numeric_intrinsic<'tcx>( + name: &str, + val: PrimVal, + kind: PrimValKind +) -> EvalResult<'tcx, PrimVal> { + macro_rules! integer_intrinsic { + ($name:expr, $val:expr, $kind:expr, $method:ident) => ({ + let val = $val; + let bytes = val.to_bytes()?; - use value::PrimValKind::*; - let bits = match $kind { - I8 => (val.bits() as i8).$method() as u64, - U8 => (val.bits() as u8).$method() as u64, - I16 => (val.bits() as i16).$method() as u64, - U16 => (val.bits() as u16).$method() as u64, - I32 => (val.bits() as i32).$method() as u64, - U32 => (val.bits() as u32).$method() as u64, - I64 => (val.bits() as i64).$method() as u64, - U64 => (val.bits() as u64).$method() as u64, - _ => bug!("invalid `{}` argument: {:?}", $name, val), - }; + use value::PrimValKind::*; + let result_bytes = match $kind { + I8 => (bytes as i8).$method() as u64, + U8 => (bytes as u8).$method() as u64, + I16 => (bytes as i16).$method() as u64, + U16 => (bytes as u16).$method() as u64, + I32 => (bytes as i32).$method() as u64, + U32 => (bytes as u32).$method() as u64, + I64 => (bytes as i64).$method() as u64, + U64 => bytes.$method() as u64, + _ => bug!("invalid `{}` argument: {:?}", $name, val), + }; - PrimVal::Bytes(bits) - }); -} + PrimVal::Bytes(result_bytes) + }); + } -fn numeric_intrinsic(name: &str, val: PrimVal, kind: PrimValKind) -> PrimVal { - match name { + let result_val = match name { "bswap" => integer_intrinsic!("bswap", val, kind, swap_bytes), "ctlz" => integer_intrinsic!("ctlz", val, kind, leading_zeros), "ctpop" => integer_intrinsic!("ctpop", val, kind, count_ones), "cttz" => integer_intrinsic!("cttz", val, kind, trailing_zeros), _ => bug!("not a numeric intrinsic: {}", name), - } + }; + + Ok(result_val) } diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 7a67f56debf5..b4cad215b77a 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -53,7 +53,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { for (index, const_val) in values.iter().enumerate() { let val = self.const_to_value(const_val)?; let prim = self.value_to_primval(val, discr_ty)?; - if discr_prim.bits() == prim.bits() { + if discr_prim.to_bytes()? == prim.to_bytes()? { target_block = targets[index]; break; } diff --git a/src/value.rs b/src/value.rs index a4b4f18ee2fa..05acb68436dc 100644 --- a/src/value.rs +++ b/src/value.rs @@ -117,16 +117,6 @@ impl<'a, 'tcx: 'a> Value { } impl<'tcx> PrimVal { - // FIXME(solson): Remove this. It's a temporary function to aid refactoring, but it shouldn't - // stick around with this name. - pub fn bits(self) -> u64 { - match self { - PrimVal::Bytes(b) => b, - PrimVal::Ptr(p) => p.offset, - PrimVal::Undef => panic!(".bits()() on PrimVal::Undef"), - } - } - pub fn from_u64(n: u64) -> Self { PrimVal::Bytes(n) } @@ -151,7 +141,7 @@ impl<'tcx> PrimVal { PrimVal::Bytes(c as u64) } - fn to_bytes(self) -> EvalResult<'tcx, u64> { + pub fn to_bytes(self) -> EvalResult<'tcx, u64> { match self { PrimVal::Bytes(b) => Ok(b), PrimVal::Ptr(p) => p.to_int(),