]> git.lizzy.rs Git - rust.git/blobdiff - src/shims/intrinsics.rs
rustup: more flexible write_bytes avoids allocations and removes itertools dependency
[rust.git] / src / shims / intrinsics.rs
index 4e957f792b7513721902d334d126f742c76d28d8..5ef7fba7f59083b093902b40a094b4b2fe851d95 100644 (file)
@@ -1,3 +1,5 @@
+use std::iter;
+
 use rustc_apfloat::Float;
 use rustc::mir;
 use rustc::mir::interpret::{InterpResult, PointerArithmetic};
@@ -5,7 +7,7 @@
 use rustc::ty;
 
 use crate::{
-    PlaceTy, OpTy, ImmTy, Immediate, Scalar, Tag,
+    PlaceTy, OpTy, Immediate, Scalar, Tag,
     OperatorEvalContextExt
 };
 
@@ -28,8 +30,8 @@ fn call_intrinsic(
         // (as opposed to through a place), we have to remember to erase any tag
         // that might still hang around!
 
-        let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str();
-        match intrinsic_name.get() {
+        let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str();
+        match intrinsic_name {
             "arith_offset" => {
                 let offset = this.read_scalar(args[1])?.to_isize(this)?;
                 let ptr = this.read_scalar(args[0])?.not_undef()?;
@@ -68,7 +70,7 @@ fn call_intrinsic(
                 // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
                 // be 8-aligned).
                 let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
-                this.memory().check_ptr_access(place.ptr, place.layout.size, align)?;
+                this.memory.check_ptr_access(place.ptr, place.layout.size, align)?;
 
                 this.write_scalar(val, dest)?;
             }
@@ -83,12 +85,15 @@ fn call_intrinsic(
                 // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
                 // be 8-aligned).
                 let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
-                this.memory().check_ptr_access(place.ptr, place.layout.size, align)?;
+                this.memory.check_ptr_access(place.ptr, place.layout.size, align)?;
 
                 this.write_scalar(val, place.into())?;
             }
 
-            "atomic_fence_acq" => {
+            "atomic_fence_acq" |
+            "atomic_fence_rel" |
+            "atomic_fence_acqrel" |
+            "atomic_fence" => {
                 // we are inherently singlethreaded and singlecored, this is a nop
             }
 
@@ -101,7 +106,7 @@ fn call_intrinsic(
                 // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
                 // be 8-aligned).
                 let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
-                this.memory().check_ptr_access(place.ptr, place.layout.size, align)?;
+                this.memory.check_ptr_access(place.ptr, place.layout.size, align)?;
 
                 this.write_scalar(old, dest)?; // old value is returned
                 this.write_scalar(new, place.into())?;
@@ -117,10 +122,10 @@ fn call_intrinsic(
                 // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
                 // be 8-aligned).
                 let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
-                this.memory().check_ptr_access(place.ptr, place.layout.size, align)?;
+                this.memory.check_ptr_access(place.ptr, place.layout.size, align)?;
 
                 // binary_op will bail if either of them is not a scalar
-                let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?;
+                let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0;
                 let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into());
                 this.write_immediate(res, dest)?; // old value is returned
                 // update ptr depending on comparison
@@ -170,7 +175,7 @@ fn call_intrinsic(
                 // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
                 // be 8-aligned).
                 let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
-                this.memory().check_ptr_access(place.ptr, place.layout.size, align)?;
+                this.memory.check_ptr_access(place.ptr, place.layout.size, align)?;
 
                 this.write_immediate(*old, dest)?; // old value is returned
                 let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() {
@@ -183,13 +188,13 @@ fn call_intrinsic(
                     _ => bug!(),
                 };
                 // Atomics wrap around on overflow.
-                let (val, _overflowed) = this.binary_op(op, old, rhs)?;
+                let val = this.binary_op(op, old, rhs)?;
                 let val = if neg {
-                    this.unary_op(mir::UnOp::Not, ImmTy::from_scalar(val, old.layout))?
+                    this.unary_op(mir::UnOp::Not, val)?
                 } else {
                     val
                 };
-                this.write_scalar(val, place.into())?;
+                this.write_immediate(*val, place.into())?;
             }
 
             "breakpoint" => unimplemented!(), // halt miri
@@ -204,12 +209,12 @@ fn call_intrinsic(
 
                 let size = Size::from_bytes(count * elem_size);
                 let src = this.read_scalar(args[0])?.not_undef()?;
-                let src = this.memory().check_ptr_access(src, size, elem_align)?;
+                let src = this.memory.check_ptr_access(src, size, elem_align)?;
                 let dest = this.read_scalar(args[1])?.not_undef()?;
-                let dest = this.memory().check_ptr_access(dest, size, elem_align)?;
+                let dest = this.memory.check_ptr_access(dest, size, elem_align)?;
 
                 if let (Some(src), Some(dest)) = (src, dest) {
-                    this.memory_mut().copy(
+                    this.memory.copy(
                         src,
                         dest,
                         size,
@@ -228,7 +233,7 @@ fn call_intrinsic(
             "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => {
                 // FIXME: Using host floats.
                 let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
-                let f = match intrinsic_name.get() {
+                let f = match intrinsic_name {
                     "sinf32" => f.sin(),
                     "fabsf32" => f.abs(),
                     "cosf32" => f.cos(),
@@ -251,7 +256,7 @@ fn call_intrinsic(
             "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => {
                 // FIXME: Using host floats.
                 let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
-                let f = match intrinsic_name.get() {
+                let f = match intrinsic_name {
                     "sinf64" => f.sin(),
                     "fabsf64" => f.abs(),
                     "cosf64" => f.cos(),
@@ -273,7 +278,7 @@ fn call_intrinsic(
             "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
                 let a = this.read_immediate(args[0])?;
                 let b = this.read_immediate(args[1])?;
-                let op = match intrinsic_name.get() {
+                let op = match intrinsic_name {
                     "fadd_fast" => mir::BinOp::Add,
                     "fsub_fast" => mir::BinOp::Sub,
                     "fmul_fast" => mir::BinOp::Mul,
@@ -287,7 +292,7 @@ fn call_intrinsic(
             "minnumf32" | "maxnumf32" => {
                 let a = this.read_scalar(args[0])?.to_f32()?;
                 let b = this.read_scalar(args[1])?.to_f32()?;
-                let res = if intrinsic_name.get().starts_with("min") {
+                let res = if intrinsic_name.starts_with("min") {
                     a.min(b)
                 } else {
                     a.max(b)
@@ -298,7 +303,7 @@ fn call_intrinsic(
             "minnumf64" | "maxnumf64" => {
                 let a = this.read_scalar(args[0])?.to_f64()?;
                 let b = this.read_scalar(args[1])?.to_f64()?;
-                let res = if intrinsic_name.get().starts_with("min") {
+                let res = if intrinsic_name.starts_with("min") {
                     a.min(b)
                 } else {
                     a.max(b)
@@ -312,7 +317,7 @@ fn call_intrinsic(
                 let a = this.read_immediate(args[0])?;
                 let b = this.read_immediate(args[1])?;
                 // check x % y != 0
-                if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 {
+                if this.overflowing_binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 {
                     // Check if `b` is -1, which is the "min_value / -1" case.
                     let minus1 = Scalar::from_int(-1, dest.layout.size);
                     return Err(if b.to_scalar().unwrap() == minus1 {
@@ -353,10 +358,8 @@ fn call_intrinsic(
                         _ => {
                             // Do it in memory
                             let mplace = this.force_allocation(dest)?;
-                            assert!(mplace.meta.is_none());
-                            // not a zst, must be valid pointer
-                            let ptr = mplace.ptr.to_ptr()?;
-                            this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?;
+                            mplace.meta.unwrap_none(); // must be sized
+                            this.memory.write_bytes(mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize))?;
                         }
                     }
                 }
@@ -509,15 +512,15 @@ fn call_intrinsic(
             "unchecked_add" | "unchecked_sub" | "unchecked_mul" => {
                 let l = this.read_immediate(args[0])?;
                 let r = this.read_immediate(args[1])?;
-                let op = match intrinsic_name.get() {
+                let op = match intrinsic_name {
                     "unchecked_add" => mir::BinOp::Add,
                     "unchecked_sub" => mir::BinOp::Sub,
                     "unchecked_mul" => mir::BinOp::Mul,
                     _ => bug!(),
                 };
-                let (res, overflowed) = this.binary_op(op, l, r)?;
+                let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?;
                 if overflowed {
-                    throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get());
+                    throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name);
                 }
                 this.write_scalar(res, dest)?;
             }
@@ -543,9 +546,10 @@ fn call_intrinsic(
                         _ => {
                             // Do it in memory
                             let mplace = this.force_allocation(dest)?;
-                            assert!(mplace.meta.is_none());
+                            mplace.meta.unwrap_none();
                             let ptr = mplace.ptr.to_ptr()?;
-                            this.memory_mut()
+                            // We know the return place is in-bounds
+                            this.memory
                                 .get_mut(ptr.alloc_id)?
                                 .mark_definedness(ptr, dest.layout.size, false);
                         }
@@ -560,16 +564,7 @@ fn call_intrinsic(
                 let ptr = this.read_scalar(args[0])?.not_undef()?;
                 let count = this.read_scalar(args[2])?.to_usize(this)?;
                 let byte_count = ty_layout.size * count;
-                match this.memory().check_ptr_access(ptr, byte_count, ty_layout.align.abi)? {
-                    Some(ptr) => {
-                        this.memory_mut()
-                            .get_mut(ptr.alloc_id)?
-                            .write_repeat(tcx, ptr, val_byte, byte_count)?;
-                    }
-                    None => {
-                        // Size is 0, nothing to do.
-                    }
-                }
+                this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?;
             }
 
             name => throw_unsup_format!("unimplemented intrinsic: {}", name),