Skip to content

Commit

Permalink
Don't use the undefined bytes of PrimVal::Bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Mar 8, 2018
1 parent 7218836 commit df283df
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 277 deletions.
2 changes: 1 addition & 1 deletion src/librustc/mir/interpret/mod.rs
Expand Up @@ -10,7 +10,7 @@ mod value;

pub use self::error::{EvalError, EvalResult, EvalErrorKind};

pub use self::value::{PrimVal, PrimValKind, Value, Pointer, bytes_to_f32, bytes_to_f64};
pub use self::value::{PrimVal, PrimValKind, Value, Pointer};

use std::collections::BTreeMap;
use std::fmt;
Expand Down
28 changes: 0 additions & 28 deletions src/librustc/mir/interpret/value.rs
Expand Up @@ -4,22 +4,6 @@ use ty::layout::{Align, HasDataLayout};
use ty;

use super::{EvalResult, MemoryPointer, PointerArithmetic};
use syntax::ast::FloatTy;
use rustc_const_math::ConstFloat;

pub fn bytes_to_f32(bits: u128) -> ConstFloat {
ConstFloat {
bits,
ty: FloatTy::F32,
}
}

pub fn bytes_to_f64(bits: u128) -> ConstFloat {
ConstFloat {
bits,
ty: FloatTy::F64,
}
}

/// A `Value` represents a single self-contained Rust value.
///
Expand Down Expand Up @@ -182,10 +166,6 @@ impl<'tcx> PrimVal {
PrimVal::Bytes(n as u128)
}

pub fn from_float(f: ConstFloat) -> Self {
PrimVal::Bytes(f.bits)
}

pub fn from_bool(b: bool) -> Self {
PrimVal::Bytes(b as u128)
}
Expand Down Expand Up @@ -260,14 +240,6 @@ impl<'tcx> PrimVal {
})
}

pub fn to_f32(self) -> EvalResult<'tcx, ConstFloat> {
self.to_bytes().map(bytes_to_f32)
}

pub fn to_f64(self) -> EvalResult<'tcx, ConstFloat> {
self.to_bytes().map(bytes_to_f64)
}

pub fn to_bool(self) -> EvalResult<'tcx, bool> {
match self.to_bytes()? {
0 => Ok(false),
Expand Down
32 changes: 28 additions & 4 deletions src/librustc/ty/mod.rs
Expand Up @@ -1845,10 +1845,34 @@ impl<'a, 'gcx, 'tcx> AdtDef {
..
}) => {
trace!("discriminants: {} ({:?})", b, repr_type);
discr = Discr {
val: b,
ty: repr_type.to_ty(tcx),
};
let ty = repr_type.to_ty(tcx);
if ty.is_signed() {
let (ty, param_env) = tcx
.lift_to_global(&(ty, param_env))
.unwrap_or_else(|| {
bug!("MIR: discriminants({:?}, {:?}) got \
type with inference types/regions",
ty, param_env);
});
let size = tcx.global_tcx()
.layout_of(param_env.and(ty))
.expect("int layout")
.size
.bits();
let val = b as i128;
// sign extend to i128
let amt = 128 - size;
let val = (val << amt) >> amt;
discr = Discr {
val: val as u128,
ty,
};
} else {
discr = Discr {
val: b,
ty,
};
}
}
_ => {
if !expr_did.is_local() {
Expand Down
38 changes: 11 additions & 27 deletions src/librustc_mir/build/expr/as_rvalue.rs
Expand Up @@ -22,7 +22,6 @@ use rustc::middle::region;
use rustc::ty::{self, Ty};
use rustc::mir::*;
use rustc::mir::interpret::{Value, PrimVal};
use syntax::ast;
use syntax_pos::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Expand Down Expand Up @@ -382,9 +381,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {

// Helper to get a `-1` value of the appropriate type
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let bits = self.hir.type_bit_size(ty);
let n = (!0u128) >> (128 - bits);
let literal = Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(-1i128 as u128))),
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
ty
})
};
Expand All @@ -394,31 +395,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {

// Helper to get the minimum value of the appropriate type
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = match ty.sty {
ty::TyInt(ity) => {
let ity = match ity {
ast::IntTy::Isize => self.hir.tcx().sess.target.isize_ty,
other => other,
};
let val = match ity {
ast::IntTy::I8 => i8::min_value() as i128,
ast::IntTy::I16 => i16::min_value() as i128,
ast::IntTy::I32 => i32::min_value() as i128,
ast::IntTy::I64 => i64::min_value() as i128,
ast::IntTy::I128 => i128::min_value() as i128,
ast::IntTy::Isize => unreachable!(),
};

Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
ty
})
}
}
_ => {
span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty)
}
assert!(ty.is_signed());
let bits = self.hir.type_bit_size(ty);
let n = 1 << (bits - 1);
let literal = Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
ty
})
};

self.literal_operand(span, ty, literal)
Expand Down
35 changes: 33 additions & 2 deletions src/librustc_mir/hair/cx/mod.rs
Expand Up @@ -149,13 +149,34 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
}
}

pub fn type_bit_size(
&self,
ty: Ty<'tcx>,
) -> u64 {
let tcx = self.tcx.global_tcx();
let (ty, param_env) = self
.tcx
.lift_to_global(&(ty, self.param_env))
.unwrap_or_else(|| {
bug!("MIR: Cx::const_eval_literal({:?}, {:?}) got \
type with inference types/regions",
ty, self.param_env);
});
tcx
.layout_of(param_env.and(ty))
.expect("int layout")
.size
.bits()
}

pub fn const_eval_literal(
&mut self,
lit: &'tcx ast::LitKind,
ty: Ty<'tcx>,
sp: Span,
neg: bool,
) -> Literal<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
let tcx = self.tcx.global_tcx();

let parse_float = |num: &str, fty| -> ConstFloat {
Expand All @@ -165,6 +186,15 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
})
};

let clamp = |n| {
let size = self.type_bit_size(ty);
trace!("clamp {} with size {} and amt {}", n, size, 128 - size);
let amt = 128 - size;
let result = (n << amt) >> amt;
trace!("clamp result: {}", result);
result
};

use rustc::mir::interpret::*;
let lit = match *lit {
LitKind::Str(ref s, _) => {
Expand All @@ -185,9 +215,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
Value::ByVal(PrimVal::Bytes(n as u128))
let n = clamp(n as u128);
Value::ByVal(PrimVal::Bytes(n))
},
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)),
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
LitKind::Float(n, fty) => {
let n = n.as_str();
let mut f = parse_float(&n, fty);
Expand Down
105 changes: 39 additions & 66 deletions src/librustc_mir/interpret/cast.rs
Expand Up @@ -14,75 +14,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
let src_kind = self.ty_to_primval_kind(src_ty)?;

match val {
PrimVal::Undef => Ok(PrimVal::Undef),
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
val @ PrimVal::Bytes(_) => {
use rustc::mir::interpret::PrimValKind::*;
match src_kind {
F32 => self.cast_from_float(val.to_f32()?, dest_ty),
F64 => self.cast_from_float(val.to_f64()?, dest_ty),

I8 | I16 | I32 | I64 | I128 => {
self.cast_from_signed_int(val.to_i128()?, dest_ty)
}

Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
self.cast_from_int(val.to_u128()?, dest_ty, false)
}
PrimVal::Bytes(b) => {
match src_ty.sty {
TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
_ => self.cast_from_int(b, src_ty, dest_ty),
}
}
}
}

fn cast_from_signed_int(&self, val: i128, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
self.cast_from_int(val as u128, ty, val < 0)
}

fn int_to_int(&self, v: i128, ty: IntTy) -> u128 {
match ty {
IntTy::I8 => v as i8 as u128,
IntTy::I16 => v as i16 as u128,
IntTy::I32 => v as i32 as u128,
IntTy::I64 => v as i64 as u128,
IntTy::I128 => v as u128,
IntTy::Isize => {
let ty = self.tcx.sess.target.isize_ty;
self.int_to_int(v, ty)
}
}
}
fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 {
match ty {
UintTy::U8 => v as u8 as u128,
UintTy::U16 => v as u16 as u128,
UintTy::U32 => v as u32 as u128,
UintTy::U64 => v as u64 as u128,
UintTy::U128 => v,
UintTy::Usize => {
let ty = self.tcx.sess.target.usize_ty;
self.int_to_uint(v, ty)
}
}
}

fn cast_from_int(
&self,
v: u128,
ty: Ty<'tcx>,
negative: bool,
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
trace!("cast_from_int: {}, {}, {}", v, ty, negative);
trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casts to bool are not permitted by rustc, no need to handle them here.
TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))),
TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))),
match dest_ty.sty {
TyInt(_) | TyUint(_) => {
let v = self.sign_extend(v, src_ty)?;
let v = self.truncate(v, dest_ty)?;
Ok(PrimVal::Bytes(v))
}

TyFloat(fty) if negative => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
TyFloat(fty) if src_ty.is_signed() => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),

TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
Expand All @@ -91,31 +53,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),

_ => err!(Unimplemented(format!("int to {:?} cast", ty))),
// Casts to bool are not permitted by rustc, no need to handle them here.
_ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
}
}

fn cast_from_float(&self, val: ConstFloat, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
use rustc_apfloat::FloatConvert;
match dest_ty.sty {
// float -> uint
TyUint(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
match val.ty {
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(val.bits).to_u128(width).value)),
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(val.bits).to_u128(width).value)),
match fty {
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
}
},

// float -> int
TyInt(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
match val.ty {
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(val.bits).to_i128(width).value)),
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(val.bits).to_i128(width).value)),
match fty {
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
}
},

TyFloat(fty) => Ok(PrimVal::from_float(val.convert(fty))),
_ => err!(Unimplemented(format!("float to {:?} cast", ty))),
// f64 -> f32
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
},
// f32 -> f64
TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
},
// identity cast
TyFloat(_) => Ok(PrimVal::Bytes(bits)),
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
}
}

Expand Down

0 comments on commit df283df

Please sign in to comment.