]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/operator.rs
make floating point casts nicer with generics
[rust.git] / src / librustc_mir / interpret / operator.rs
index ca93007788e0342ef9a8bb54931f90aa99b510a6..db7da9359de7b7762bfc153120bdce4bd56dc699 100644 (file)
@@ -1,9 +1,8 @@
 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;
-use rustc::mir::interpret::{EvalResult, Scalar};
+use rustc::mir::interpret::{InterpResult, Scalar};
 
 use super::{InterpretCx, PlaceTy, Immediate, Machine, ImmTy};
 
@@ -17,7 +16,7 @@ pub fn binop_with_overflow(
         left: ImmTy<'tcx, M::PointerTag>,
         right: ImmTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         let (val, overflowed) = self.binary_op(op, left, right)?;
         let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
         self.write_immediate(val, dest)
@@ -31,7 +30,7 @@ pub fn binop_ignore_overflow(
         left: ImmTy<'tcx, M::PointerTag>,
         right: ImmTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         let (val, _overflowed) = self.binary_op(op, left, right)?;
         self.write_scalar(val, dest)
     }
@@ -43,7 +42,7 @@ fn binary_char_op(
         bin_op: mir::BinOp,
         l: char,
         r: char,
-    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
+    ) -> (Scalar<M::PointerTag>, bool) {
         use rustc::mir::BinOp::*;
 
         let res = match bin_op {
@@ -55,7 +54,7 @@ fn binary_char_op(
             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 +62,7 @@ fn binary_bool_op(
         bin_op: mir::BinOp,
         l: bool,
         r: bool,
-    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
+    ) -> (Scalar<M::PointerTag>, bool) {
         use rustc::mir::BinOp::*;
 
         let res = match bin_op {
@@ -78,46 +77,32 @@ fn binary_bool_op(
             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<F: Float + Into<Scalar<M::PointerTag>>>(
         &self,
         bin_op: mir::BinOp,
-        fty: FloatTy,
-        // passing in raw bits
-        l: u128,
-        r: u128,
-    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
+        l: F,
+        r: F,
+    ) -> (Scalar<M::PointerTag>, bool) {
         use rustc::mir::BinOp::*;
 
-        macro_rules! float_math {
-            ($ty:path, $size:expr) => {{
-                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),
-                    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 => bitify(l + r),
-                    Sub => bitify(l - r),
-                    Mul => bitify(l * r),
-                    Div => bitify(l / r),
-                    Rem => bitify(l % r),
-                    _ => bug!("invalid float op: `{:?}`", bin_op),
-                };
-                return Ok((val, false));
-            }};
-        }
-        match fty {
-            FloatTy::F32 => float_math!(Single, 4),
-            FloatTy::F64 => float_math!(Double, 8),
-        }
+        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(
@@ -128,7 +113,7 @@ fn binary_int_op(
         left_layout: TyLayout<'tcx>,
         r: u128,
         right_layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
+    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         use rustc::mir::BinOp::*;
 
         // Shift ops can have an RHS with a different numeric type.
@@ -279,35 +264,42 @@ pub fn binary_op(
         bin_op: mir::BinOp,
         left: ImmTy<'tcx, M::PointerTag>,
         right: ImmTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
+    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
             bin_op, *left, left.layout.ty, *right, right.layout.ty);
 
         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.
-                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() ||
@@ -329,10 +321,8 @@ pub fn unary_op(
         &self,
         un_op: mir::UnOp,
         val: ImmTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
         use rustc::mir::UnOp::*;
-        use rustc_apfloat::ieee::{Single, Double};
-        use rustc_apfloat::Float;
 
         let layout = val.layout;
         let val = val.to_scalar()?;
@@ -348,13 +338,12 @@ pub fn unary_op(
                 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());