]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/intrinsics.rs
Add a `const_eval` helper to `InterpCx`
[rust.git] / src / librustc_mir / interpret / intrinsics.rs
index 67f0aed243da1f20bd46fc23e61d5d59451925c0..eb7657f780c56da4538df6e62f9f3c8e1b45fa48 100644 (file)
@@ -2,21 +2,20 @@
 //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
 //! and miri.
 
-use syntax_pos::symbol::{sym, Symbol};
-use syntax_pos::Span;
+use rustc::hir::def_id::DefId;
+use rustc::mir::{
+    self,
+    interpret::{ConstValue, InterpResult, Scalar},
+    BinOp,
+};
 use rustc::ty;
 use rustc::ty::layout::{LayoutOf, Primitive, Size};
 use rustc::ty::subst::SubstsRef;
-use rustc::hir::def_id::DefId;
 use rustc::ty::TyCtxt;
-use rustc::mir::{
-    self, BinOp,
-    interpret::{InterpResult, Scalar, GlobalId, ConstValue}
-};
+use syntax_pos::symbol::{sym, Symbol};
+use syntax_pos::Span;
 
-use super::{
-    Machine, PlaceTy, OpTy, InterpCx, ImmTy,
-};
+use super::{ImmTy, InterpCx, Machine, OpTy, PlaceTy};
 
 mod caller_location;
 mod type_name;
@@ -63,11 +62,9 @@ fn numeric_intrinsic<'tcx, Tag>(
                 }),
                 ty: tcx.mk_static_str(),
             })
-        },
+        }
         sym::needs_drop => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
-        sym::size_of |
-        sym::min_align_of |
-        sym::pref_align_of => {
+        sym::size_of | sym::min_align_of | sym::pref_align_of => {
             let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
             let n = match name {
                 sym::pref_align_of => layout.align.pref.bytes(),
@@ -76,12 +73,10 @@ fn numeric_intrinsic<'tcx, Tag>(
                 _ => bug!(),
             };
             ty::Const::from_usize(tcx, n)
-        },
-        sym::type_id => ty::Const::from_bits(
-            tcx,
-            tcx.type_id_hash(tp_ty).into(),
-            param_env.and(tcx.types.u64),
-        ),
+        }
+        sym::type_id => {
+            ty::Const::from_bits(tcx, tcx.type_id_hash(tp_ty).into(), param_env.and(tcx.types.u64))
+        }
         other => bug!("`{}` is not a zero arg intrinsic", other),
     })
 }
@@ -105,7 +100,7 @@ pub fn emulate_intrinsic(
             None => match intrinsic_name {
                 sym::transmute => throw_ub!(Unreachable),
                 _ => return Ok(false),
-            }
+            },
         };
 
         // Keep the patterns in this match ordered the same as the list in
@@ -117,22 +112,18 @@ pub fn emulate_intrinsic(
                 self.write_scalar(location.ptr, dest)?;
             }
 
-            sym::min_align_of |
-            sym::pref_align_of |
-            sym::needs_drop |
-            sym::size_of |
-            sym::type_id |
-            sym::type_name => {
-                let gid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                let val = self.tcx.const_eval(self.param_env.and(gid))?;
-                let val = self.eval_const_to_op(val, None)?;
+            sym::min_align_of
+            | sym::pref_align_of
+            | sym::needs_drop
+            | sym::size_of
+            | sym::type_id
+            | sym::type_name => {
+                let gid = GlobalId { instance, promoted: None };
+                let val = self.const_eval(gid)?;
                 self.copy_op(val, dest)?;
             }
 
-            sym::ctpop
+            sym::ctpop
             | sym::cttz
             | sym::cttz_nonzero
             | sym::ctlz
@@ -158,7 +149,7 @@ pub fn emulate_intrinsic(
                 let out_val = numeric_intrinsic(intrinsic_name, bits, kind)?;
                 self.write_scalar(out_val, dest)?;
             }
-            sym::wrapping_add
+            sym::wrapping_add
             | sym::wrapping_sub
             | sym::wrapping_mul
             | sym::add_with_overflow
@@ -173,7 +164,7 @@ pub fn emulate_intrinsic(
                     sym::add_with_overflow => (BinOp::Add, false),
                     sym::sub_with_overflow => (BinOp::Sub, false),
                     sym::mul_with_overflow => (BinOp::Mul, false),
-                    _ => bug!("Already checked for int ops")
+                    _ => bug!("Already checked for int ops"),
                 };
                 if ignore_overflow {
                     self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?;
@@ -185,11 +176,8 @@ pub fn emulate_intrinsic(
                 let l = self.read_immediate(args[0])?;
                 let r = self.read_immediate(args[1])?;
                 let is_add = intrinsic_name == sym::saturating_add;
-                let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
-                    BinOp::Add
-                } else {
-                    BinOp::Sub
-                }, l, r)?;
+                let (val, overflowed, _ty) =
+                    self.overflowing_binary_op(if is_add { BinOp::Add } else { BinOp::Sub }, l, r)?;
                 let val = if overflowed {
                     let num_bits = l.layout.size.bits();
                     if l.layout.abi.is_signed() {
@@ -198,24 +186,30 @@ pub fn emulate_intrinsic(
                         // the fact that the operation has overflowed (if either is 0 no
                         // overflow can occur)
                         let first_term: u128 = self.force_bits(l.to_scalar()?, l.layout.size)?;
-                        let first_term_positive = first_term & (1 << (num_bits-1)) == 0;
+                        let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
                         if first_term_positive {
                             // Negative overflow not possible since the positive first term
                             // can only increase an (in range) negative term for addition
                             // or corresponding negated positive term for subtraction
-                            Scalar::from_uint((1u128 << (num_bits - 1)) - 1,  // max positive
-                                Size::from_bits(num_bits))
+                            Scalar::from_uint(
+                                (1u128 << (num_bits - 1)) - 1, // max positive
+                                Size::from_bits(num_bits),
+                            )
                         } else {
                             // Positive overflow not possible for similar reason
                             // max negative
                             Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
                         }
-                    } else {  // unsigned
+                    } else {
+                        // unsigned
                         if is_add {
                             // max unsigned
-                            Scalar::from_uint(u128::max_value() >> (128 - num_bits),
-                                Size::from_bits(num_bits))
-                        } else {  // underflow to 0
+                            Scalar::from_uint(
+                                u128::max_value() >> (128 - num_bits),
+                                Size::from_bits(num_bits),
+                            )
+                        } else {
+                            // underflow to 0
                             Scalar::from_uint(0u128, Size::from_bits(num_bits))
                         }
                     }
@@ -230,7 +224,7 @@ pub fn emulate_intrinsic(
                 let bin_op = match intrinsic_name {
                     sym::unchecked_shl => BinOp::Shl,
                     sym::unchecked_shr => BinOp::Shr,
-                    _ => bug!("Already checked for int ops")
+                    _ => bug!("Already checked for int ops"),
                 };
                 let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
                 if overflowed {
@@ -281,8 +275,12 @@ pub fn emulate_intrinsic(
                     if a == b && a != 0 {
                         self.write_scalar(Scalar::from_int(0, isize_layout.size), dest)?;
                         true
-                    } else { false }
-                } else { false };
+                    } else {
+                        false
+                    }
+                } else {
+                    false
+                };
 
                 if !done {
                     // General case: we need two pointers.
@@ -297,9 +295,8 @@ pub fn emulate_intrinsic(
                     let usize_layout = self.layout_of(self.tcx.types.usize)?;
                     let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout);
                     let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout);
-                    let (val, _overflowed, _ty) = self.overflowing_binary_op(
-                        BinOp::Sub, a_offset, b_offset,
-                    )?;
+                    let (val, _overflowed, _ty) =
+                        self.overflowing_binary_op(BinOp::Sub, a_offset, b_offset)?;
                     let pointee_layout = self.layout_of(substs.type_at(0))?;
                     let val = ImmTy::from_scalar(val, isize_layout);
                     let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
@@ -318,7 +315,9 @@ pub fn emulate_intrinsic(
                 assert!(
                     index < len,
                     "Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
-                    index, e_ty, len
+                    index,
+                    e_ty,
+                    len
                 );
                 assert_eq!(
                     input.layout, dest.layout,
@@ -333,11 +332,7 @@ pub fn emulate_intrinsic(
 
                 for i in 0..len {
                     let place = self.place_field(dest, i)?;
-                    let value = if i == index {
-                        elem
-                    } else {
-                        self.operand_field(input, i)?
-                    };
+                    let value = if i == index { elem } else { self.operand_field(input, i)? };
                     self.copy_op(value, place)?;
                 }
             }
@@ -347,7 +342,9 @@ pub fn emulate_intrinsic(
                 assert!(
                     index < len,
                     "index `{}` is out-of-bounds of vector type `{}` with length `{}`",
-                    index, e_ty, len
+                    index,
+                    e_ty,
+                    len
                 );
                 assert_eq!(
                     e_ty, dest.layout.ty,
@@ -432,11 +429,7 @@ pub fn exact_div(
             if b_scalar == minus1 {
                 throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented")
             } else {
-                throw_ub_format!(
-                    "exact_div: {} cannot be divided by {} without remainder",
-                    a,
-                    b,
-                )
+                throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b,)
             }
         }
         self.binop_ignore_overflow(BinOp::Div, a, b, dest)