From 3836573ae4610f75d41d467e35d855efd6b000b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jun 2019 23:30:33 +0200 Subject: [PATCH 1/7] Scalar: only convert to/from soft-float types, not to/from hard-floats --- src/librustc/mir/interpret/value.rs | 19 +++++++----- src/librustc_mir/hair/constant.rs | 11 +++---- src/librustc_mir/interpret/cast.rs | 42 ++++++++++---------------- src/librustc_mir/interpret/operator.rs | 20 ++++++------ 4 files changed, 41 insertions(+), 51 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 454a4e2111a9c..1909f3cb998be 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,5 +1,6 @@ use std::fmt; use rustc_macros::HashStable; +use rustc_apfloat::{Float, ieee::{Double, Single}}; use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef}; use crate::ty::PlaceholderConst; @@ -292,12 +293,12 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn from_f32(f: f32) -> Self { + pub fn from_f32(f: Single) -> Self { Scalar::Raw { data: f.to_bits() as u128, size: 4 } } #[inline] - pub fn from_f64(f: f64) -> Self { + pub fn from_f64(f: Double) -> Self { Scalar::Raw { data: f.to_bits() as u128, size: 8 } } @@ -427,13 +428,15 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn to_f32(self) -> InterpResult<'static, f32> { - Ok(f32::from_bits(self.to_u32()?)) + pub fn to_f32(self) -> InterpResult<'static, Single> { + // Going through `u32` to check size and truncation. + Ok(Single::from_bits(self.to_u32()? as u128)) } #[inline] - pub fn to_f64(self) -> InterpResult<'static, f64> { - Ok(f64::from_bits(self.to_u64()?)) + pub fn to_f64(self) -> InterpResult<'static, Double> { + // Going through `u64` to check size and truncation. + Ok(Double::from_bits(self.to_u64()? as u128)) } } @@ -517,12 +520,12 @@ impl<'tcx, Tag> ScalarMaybeUndef { } #[inline(always)] - pub fn to_f32(self) -> InterpResult<'tcx, f32> { + pub fn to_f32(self) -> InterpResult<'tcx, Single> { self.not_undef()?.to_f32() } #[inline(always)] - pub fn to_f64(self) -> InterpResult<'tcx, f64> { + pub fn to_f64(self) -> InterpResult<'tcx, Double> { self.not_undef()?.to_f64() } diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index b5604f4cb0f8e..37a2e79dae91f 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -69,8 +69,7 @@ fn parse_float<'tcx>( ) -> Result, ()> { let num = num.as_str(); use rustc_apfloat::ieee::{Single, Double}; - use rustc_apfloat::Float; - let (data, size) = match fty { + let scalar = match fty { ast::FloatTy::F32 => { num.parse::().map_err(|_| ())?; let mut f = num.parse::().unwrap_or_else(|e| { @@ -79,19 +78,19 @@ fn parse_float<'tcx>( if neg { f = -f; } - (f.to_bits(), 4) + Scalar::from_f32(f) } ast::FloatTy::F64 => { num.parse::().map_err(|_| ())?; let mut f = num.parse::().unwrap_or_else(|e| { - panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) + panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e) }); if neg { f = -f; } - (f.to_bits(), 8) + Scalar::from_f64(f) } }; - Ok(ConstValue::Scalar(Scalar::from_uint(data, Size::from_bytes(size)))) + Ok(ConstValue::Scalar(scalar)) } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 5bc8b931ae867..4395f0c947b15 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -166,21 +166,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ok(Scalar::from_uint(v, dest_layout.size)) } - Float(FloatTy::F32) if signed => Ok(Scalar::from_uint( - Single::from_i128(v as i128).value.to_bits(), - Size::from_bits(32) + Float(FloatTy::F32) if signed => Ok(Scalar::from_f32( + Single::from_i128(v as i128).value )), - Float(FloatTy::F64) if signed => Ok(Scalar::from_uint( - Double::from_i128(v as i128).value.to_bits(), - Size::from_bits(64) + Float(FloatTy::F64) if signed => Ok(Scalar::from_f64( + Double::from_i128(v as i128).value )), - Float(FloatTy::F32) => Ok(Scalar::from_uint( - Single::from_u128(v).value.to_bits(), - Size::from_bits(32) + Float(FloatTy::F32) => Ok(Scalar::from_f32( + Single::from_u128(v).value )), - Float(FloatTy::F64) => Ok(Scalar::from_uint( - Double::from_u128(v).value.to_bits(), - Size::from_bits(64) + Float(FloatTy::F64) => Ok(Scalar::from_f64( + Double::from_u128(v).value )), Char => { @@ -223,22 +219,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ok(Scalar::from_int(v, Size::from_bits(width as u64))) }, // f64 -> f32 - Float(FloatTy::F32) if fty == FloatTy::F64 => { - Ok(Scalar::from_uint( - Single::to_bits(Double::from_bits(bits).convert(&mut false).value), - Size::from_bits(32), - )) - }, + Float(FloatTy::F32) if fty == FloatTy::F64 => + Ok(Scalar::from_f32(Double::from_bits(bits).convert(&mut false).value)), // f32 -> f64 - Float(FloatTy::F64) if fty == FloatTy::F32 => { - Ok(Scalar::from_uint( - Double::to_bits(Single::from_bits(bits).convert(&mut false).value), - Size::from_bits(64), - )) - }, + Float(FloatTy::F64) if fty == FloatTy::F32 => + Ok(Scalar::from_f64(Single::from_bits(bits).convert(&mut false).value)), // identity cast - Float(FloatTy:: F64) => Ok(Scalar::from_uint(bits, Size::from_bits(64))), - Float(FloatTy:: F32) => Ok(Scalar::from_uint(bits, Size::from_bits(32))), + Float(FloatTy::F64) if fty == FloatTy::F64 => + Ok(Scalar::from_uint(bits, Size::from_bits(64))), + Float(FloatTy::F32) if fty == FloatTy::F32 => + Ok(Scalar::from_uint(bits, Size::from_bits(32))), _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))), } } diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 4f13eeb6fa450..fa4597c825ace 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::{self, layout::{Size, TyLayout}}; +use rustc::ty::{self, layout::TyLayout}; use syntax::ast::FloatTy; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; @@ -92,11 +92,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> use rustc::mir::BinOp::*; macro_rules! float_math { - ($ty:path, $size:expr) => {{ + ($ty:path, $from_float:ident) => {{ let l = <$ty>::from_bits(l); let r = <$ty>::from_bits(r); - let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| - Scalar::from_uint(res.value.to_bits(), Size::from_bytes($size)); let val = match bin_op { Eq => Scalar::from_bool(l == r), Ne => Scalar::from_bool(l != r), @@ -104,19 +102,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Le => Scalar::from_bool(l <= r), Gt => Scalar::from_bool(l > r), Ge => Scalar::from_bool(l >= r), - Add => bitify(l + r), - Sub => bitify(l - r), - Mul => bitify(l * r), - Div => bitify(l / r), - Rem => bitify(l % r), + Add => Scalar::$from_float((l + r).value), + Sub => Scalar::$from_float((l - r).value), + Mul => Scalar::$from_float((l * r).value), + Div => Scalar::$from_float((l / r).value), + Rem => Scalar::$from_float((l % r).value), _ => bug!("invalid float op: `{:?}`", bin_op), }; return Ok((val, false)); }}; } match fty { - FloatTy::F32 => float_math!(Single, 4), - FloatTy::F64 => float_math!(Double, 8), + FloatTy::F32 => float_math!(Single, from_f32), + FloatTy::F64 => float_math!(Double, from_f64), } } From 0803d75eb6083111504e9bae4fa6baf9104928fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jun 2019 23:53:10 +0200 Subject: [PATCH 2/7] offer ways to directly construct a Scalar from unsigned integers --- src/librustc/mir/interpret/value.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 1909f3cb998be..8d4d61764833a 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -280,6 +280,26 @@ impl<'tcx, Tag> Scalar { Scalar::Raw { data: i, size: size.bytes() as u8 } } + #[inline] + pub fn from_u8(i: u8) -> Self { + Scalar::Raw { data: i as u128, size: 1 } + } + + #[inline] + pub fn from_u16(i: u16) -> Self { + Scalar::Raw { data: i as u128, size: 2 } + } + + #[inline] + pub fn from_u32(i: u32) -> Self { + Scalar::Raw { data: i as u128, size: 4 } + } + + #[inline] + pub fn from_u64(i: u64) -> Self { + Scalar::Raw { data: i as u128, size: 8 } + } + #[inline] pub fn from_int(i: impl Into, size: Size) -> Self { let i = i.into(); @@ -294,12 +314,14 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_f32(f: Single) -> Self { - Scalar::Raw { data: f.to_bits() as u128, size: 4 } + // We trust apfloat to give us properly truncated data + Scalar::Raw { data: f.to_bits(), size: 4 } } #[inline] pub fn from_f64(f: Double) -> Self { - Scalar::Raw { data: f.to_bits() as u128, size: 8 } + // We trust apfloat to give us properly truncated data + Scalar::Raw { data: f.to_bits(), size: 8 } } #[inline] From 0012af695eb81f2ab5dfb787383df5415e8cfba1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 00:41:20 +0200 Subject: [PATCH 3/7] trait-ize binary_float_op --- src/librustc/mir/interpret/value.rs | 14 +++++ src/librustc_mir/interpret/operator.rs | 79 ++++++++++++-------------- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 8d4d61764833a..35663c4f01488 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -132,6 +132,20 @@ impl fmt::Display for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Single) -> Self { + Scalar::from_f32(f) + } +} + +impl From for Scalar { + #[inline(always)] + fn from(f: Double) -> Self { + Scalar::from_f64(f) + } +} + impl<'tcx> Scalar<()> { #[inline(always)] fn check_data(data: u128, size: u8) { diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index fa4597c825ace..dd04a8b3c3056 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -43,7 +43,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> bin_op: mir::BinOp, l: char, r: char, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> (Scalar, bool) { use rustc::mir::BinOp::*; let res = match bin_op { @@ -55,7 +55,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ge => l >= r, _ => bug!("Invalid operation on char: {:?}", bin_op), }; - return Ok((Scalar::from_bool(res), false)); + return (Scalar::from_bool(res), false); } fn binary_bool_op( @@ -63,7 +63,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> bin_op: mir::BinOp, l: bool, r: bool, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> (Scalar, bool) { use rustc::mir::BinOp::*; let res = match bin_op { @@ -78,44 +78,32 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> BitXor => l ^ r, _ => bug!("Invalid operation on bool: {:?}", bin_op), }; - return Ok((Scalar::from_bool(res), false)); + return (Scalar::from_bool(res), false); } - fn binary_float_op( + fn binary_float_op>>( &self, bin_op: mir::BinOp, - fty: FloatTy, - // passing in raw bits - l: u128, - r: u128, - ) -> InterpResult<'tcx, (Scalar, bool)> { + l: F, + r: F, + ) -> (Scalar, bool) { use rustc::mir::BinOp::*; - macro_rules! float_math { - ($ty:path, $from_float:ident) => {{ - let l = <$ty>::from_bits(l); - let r = <$ty>::from_bits(r); - let val = match bin_op { - Eq => Scalar::from_bool(l == r), - Ne => Scalar::from_bool(l != r), - Lt => Scalar::from_bool(l < r), - Le => Scalar::from_bool(l <= r), - Gt => Scalar::from_bool(l > r), - Ge => Scalar::from_bool(l >= r), - Add => Scalar::$from_float((l + r).value), - Sub => Scalar::$from_float((l - r).value), - Mul => Scalar::$from_float((l * r).value), - Div => Scalar::$from_float((l / r).value), - Rem => Scalar::$from_float((l % r).value), - _ => bug!("invalid float op: `{:?}`", bin_op), - }; - return Ok((val, false)); - }}; - } - match fty { - FloatTy::F32 => float_math!(Single, from_f32), - FloatTy::F64 => float_math!(Double, from_f64), - } + let val = match bin_op { + Eq => Scalar::from_bool(l == r), + Ne => Scalar::from_bool(l != r), + Lt => Scalar::from_bool(l < r), + Le => Scalar::from_bool(l <= r), + Gt => Scalar::from_bool(l > r), + Ge => Scalar::from_bool(l >= r), + Add => (l + r).value.into(), + Sub => (l - r).value.into(), + Mul => (l * r).value.into(), + Div => (l / r).value.into(), + Rem => (l % r).value.into(), + _ => bug!("invalid float op: `{:?}`", bin_op), + }; + return (val, false); } fn binary_int_op( @@ -284,21 +272,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> match left.layout.ty.sty { ty::Char => { assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar()?.to_char()?; - let right = right.to_scalar()?.to_char()?; - self.binary_char_op(bin_op, left, right) + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) } ty::Bool => { assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar()?.to_bool()?; - let right = right.to_scalar()?.to_bool()?; - self.binary_bool_op(bin_op, left, right) + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_bits()?; - let right = right.to_bits()?; - self.binary_float_op(bin_op, fty, left, right) + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match fty { + FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?), + FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?), + }) } _ => { // Must be integer(-like) types. Don't forget about == on fn pointers. From 8316cecf697d106e0132081b7df5409faac5e4d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 00:51:47 +0200 Subject: [PATCH 4/7] make unary float negation slightly nicer --- src/librustc_mir/interpret/operator.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index dd04a8b3c3056..eb45bb0e2771b 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -1,7 +1,6 @@ use rustc::mir; use rustc::ty::{self, layout::TyLayout}; use syntax::ast::FloatTy; -use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc::mir::interpret::{InterpResult, Scalar}; @@ -335,13 +334,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ok(Scalar::from_bool(res)) } ty::Float(fty) => { - let val = val.to_bits(layout.size)?; let res = match (un_op, fty) { - (Neg, FloatTy::F32) => Single::to_bits(-Single::from_bits(val)), - (Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)), + (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), + (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), _ => bug!("Invalid float op {:?}", un_op) }; - Ok(Scalar::from_uint(res, layout.size)) + Ok(res) } _ => { assert!(layout.ty.is_integral()); From de7bcca6e4a5e2f999b6c4d1f06dac6074ad3e50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 11:35:41 +0200 Subject: [PATCH 5/7] Apply suggestions from code review Co-Authored-By: Mazdak Farrokhzad --- src/librustc/mir/interpret/value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 35663c4f01488..23c37676f3659 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -328,13 +328,13 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_f32(f: Single) -> Self { - // We trust apfloat to give us properly truncated data + // We trust apfloat to give us properly truncated data. Scalar::Raw { data: f.to_bits(), size: 4 } } #[inline] pub fn from_f64(f: Double) -> Self { - // We trust apfloat to give us properly truncated data + // We trust apfloat to give us properly truncated data. Scalar::Raw { data: f.to_bits(), size: 8 } } From 2ad303eb07e51ce0c4f9dd6a253ab4e938ab65f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 12:31:19 +0200 Subject: [PATCH 6/7] make floating point casts nicer with generics --- src/librustc/ty/sty.rs | 8 +++ src/librustc_mir/interpret/cast.rs | 68 +++++++++++++------------- src/librustc_mir/interpret/operator.rs | 12 +++-- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ddc4bd3f9f6c3..5cc46b21fca1f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2035,6 +2035,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] + pub fn is_fn_ptr(&self) -> bool { + match self.sty { + FnPtr(_) => true, + _ => false, + } + } + pub fn is_impl_trait(&self) -> bool { match self.sty { Opaque(..) => true, diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 4395f0c947b15..7a0c98bc44c37 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -5,11 +5,11 @@ use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::symbol::sym; use rustc_apfloat::ieee::{Single, Double}; +use rustc_apfloat::{Float, FloatConvert}; use rustc::mir::interpret::{ Scalar, InterpResult, Pointer, PointerArithmetic, InterpError, }; use rustc::mir::CastKind; -use rustc_apfloat::Float; use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate}; @@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ok(()) } - pub(super) fn cast_scalar( + fn cast_scalar( &self, val: Scalar, src_layout: TyLayout<'tcx>, @@ -135,12 +135,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> use rustc::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty); - match val.to_bits_or_ptr(src_layout.size, self) { - Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), - Ok(data) => { - match src_layout.ty.sty { - Float(fty) => self.cast_from_float(data, fty, dest_layout.ty), - _ => self.cast_from_int(data, src_layout, dest_layout), + match src_layout.ty.sty { + // Floating point + Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty), + Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty), + // Integer(-like), including fn ptr casts + _ => { + assert!( + src_layout.ty.is_bool() || src_layout.ty.is_char() || + src_layout.ty.is_integral() || src_layout.ty.is_region_ptr() || + src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr(), + "Unexpected cast from type {:?}", src_layout.ty + ); + match val.to_bits_or_ptr(src_layout.size, self) { + Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), + Ok(data) => self.cast_from_int(data, src_layout, dest_layout), } } } @@ -148,10 +157,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> fn cast_from_int( &self, - v: u128, + v: u128, // raw bits src_layout: TyLayout<'tcx>, dest_layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, Scalar> { + // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); let v = if signed { self.sign_extend(v, src_layout) @@ -190,46 +200,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } } - fn cast_from_float( + fn cast_from_float( &self, - bits: u128, - fty: FloatTy, + f: F, dest_ty: Ty<'tcx> - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> + where F: Float + Into> + FloatConvert + FloatConvert + { use rustc::ty::TyKind::*; - use rustc_apfloat::FloatConvert; match dest_ty.sty { // float -> uint Uint(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); - let v = match fty { - FloatTy::F32 => Single::from_bits(bits).to_u128(width).value, - FloatTy::F64 => Double::from_bits(bits).to_u128(width).value, - }; + let v = f.to_u128(width).value; // This should already fit the bit width Ok(Scalar::from_uint(v, Size::from_bits(width as u64))) }, // float -> int Int(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); - let v = match fty { - FloatTy::F32 => Single::from_bits(bits).to_i128(width).value, - FloatTy::F64 => Double::from_bits(bits).to_i128(width).value, - }; + let v = f.to_i128(width).value; Ok(Scalar::from_int(v, Size::from_bits(width as u64))) }, - // f64 -> f32 - Float(FloatTy::F32) if fty == FloatTy::F64 => - Ok(Scalar::from_f32(Double::from_bits(bits).convert(&mut false).value)), - // f32 -> f64 - Float(FloatTy::F64) if fty == FloatTy::F32 => - Ok(Scalar::from_f64(Single::from_bits(bits).convert(&mut false).value)), - // identity cast - Float(FloatTy::F64) if fty == FloatTy::F64 => - Ok(Scalar::from_uint(bits, Size::from_bits(64))), - Float(FloatTy::F32) if fty == FloatTy::F32 => - Ok(Scalar::from_uint(bits, Size::from_bits(32))), - _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))), + // float -> f32 + Float(FloatTy::F32) => + Ok(Scalar::from_f32(f.convert(&mut false).value)), + // float -> f64 + Float(FloatTy::F64) => + Ok(Scalar::from_f64(f.convert(&mut false).value)), + // That's it. + _ => bug!("invalid float to {:?} cast", dest_ty), } } diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index eb45bb0e2771b..db7da9359de7b 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -292,10 +292,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } _ => { // Must be integer(-like) types. Don't forget about == on fn pointers. - assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() || - left.layout.ty.is_fn()); - assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() || - right.layout.ty.is_fn()); + assert!( + left.layout.ty.is_integral() || + left.layout.ty.is_unsafe_ptr() || left.layout.ty.is_fn_ptr(), + "Unexpected LHS type {:?} for BinOp {:?}", left.layout.ty, bin_op); + assert!( + right.layout.ty.is_integral() || + right.layout.ty.is_unsafe_ptr() || right.layout.ty.is_fn_ptr(), + "Unexpected RHS type {:?} for BinOp {:?}", right.layout.ty, bin_op); // Handle operations that support pointer values if left.to_scalar_ptr()?.is_ptr() || From 8dfc8db235e205c60b56e0753996399a6f66f3e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 13:53:44 +0200 Subject: [PATCH 7/7] forgot about multivariant enum casts --- src/librustc_mir/interpret/cast.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 7a0c98bc44c37..6392e0996aec2 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -139,12 +139,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> // Floating point Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty), Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty), - // Integer(-like), including fn ptr casts + // Integer(-like), including fn ptr casts and casts from enums that + // are represented as integers (this excludes univariant enums, which + // are handled in `cast` directly). _ => { assert!( - src_layout.ty.is_bool() || src_layout.ty.is_char() || - src_layout.ty.is_integral() || src_layout.ty.is_region_ptr() || - src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr(), + src_layout.ty.is_bool() || src_layout.ty.is_char() || + src_layout.ty.is_enum() || src_layout.ty.is_integral() || + src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr() || + src_layout.ty.is_region_ptr(), "Unexpected cast from type {:?}", src_layout.ty ); match val.to_bits_or_ptr(src_layout.size, self) {