about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgnzlbg <gonzalobg88@gmail.com>2019-09-24 16:14:43 +0200
committergnzlbg <gonzalobg88@gmail.com>2019-09-24 16:14:43 +0200
commit03ac54aed6f728ab4e5e18a10b5c3887782924cf (patch)
tree91f65ab848d03a9bf61f4fa849e0b296537f1bdf
parentef906d0e3c50ba0833c5a135d705ab4f6bd93aea (diff)
downloadrust-03ac54aed6f728ab4e5e18a10b5c3887782924cf.tar.gz
rust-03ac54aed6f728ab4e5e18a10b5c3887782924cf.zip
Add const-eval support for SIMD types, insert, and extract
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs20
-rw-r--r--src/librustc_mir/interpret/operand.rs15
-rw-r--r--src/librustc_mir/interpret/place.rs34
-rw-r--r--src/librustc_mir/interpret/terminator.rs4
-rw-r--r--src/test/ui/consts/const-eval/const_eval-simd.rs24
-rw-r--r--src/test/ui/consts/const-eval/const_eval-simd.stderr48
6 files changed, 143 insertions, 2 deletions
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index ec09e69ec85..0ede0681905 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -239,7 +239,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             "transmute" => {
                 self.copy_op_transmute(args[0], dest)?;
             }
-
+            "simd_insert" => {
+                let mut vector = self.read_vector(args[0])?;
+                let index = self.read_scalar(args[1])?.to_u32()? as usize;
+                let scalar = self.read_immediate(args[2])?;
+                if vector[index].layout.size == scalar.layout.size {
+                    vector[index] = scalar;
+                } else {
+                    throw_ub_format!(
+                        "Inserting `{:?}` with size `{}` to a vector element place of size `{}`",
+                        scalar, scalar.layout.size.bytes(), vector[index].layout.size.bytes()
+                    );
+                }
+                self.write_vector(vector, dest)?;
+            }
+            "simd_extract" => {
+                let index = self.read_scalar(args[1])?.to_u32()? as _;
+                let scalar = self.read_immediate(self.operand_field(args[0], index)?)?;
+                self.write_immediate(*scalar, dest)?;
+            }
             _ => return Ok(false),
         }
 
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index dd214c4a031..184e2ee9516 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -335,6 +335,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
+    /// Read vector from operand `op`
+    pub fn read_vector(&self, op: OpTy<'tcx, M::PointerTag>)
+                       -> InterpResult<'tcx, Vec<ImmTy<'tcx, M::PointerTag>>> {
+        if let layout::Abi::Vector { count, .. } = op.layout.abi {
+            assert_ne!(count, 0);
+            let mut scalars = Vec::new();
+            for index in 0..count {
+                scalars.push(self.read_immediate(self.operand_field(op, index as _)?)?);
+            }
+            Ok(scalars)
+        } else {
+            bug!("type is not a vector: {:?}, abi: {:?}", op.layout.ty, op.layout.abi);
+        }
+    }
+
     /// Read a scalar from a place
     pub fn read_scalar(
         &self,
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index c3660fb7a2e..9154e2666c5 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -696,6 +696,40 @@ where
         Ok(())
     }
 
+    /// Writes the `scalar` to the `index`-th element of the `vector`.
+    pub fn write_scalar_to_vector(
+        &mut self,
+        scalar: ImmTy<'tcx, M::PointerTag>,
+        vector: PlaceTy<'tcx, M::PointerTag>,
+        index: usize,
+    ) -> InterpResult<'tcx> {
+        let index = index as u64;
+        let place = self.place_field(vector, index)?;
+        self.write_immediate(*scalar, place)?;
+        Ok(())
+    }
+
+    /// Writes the `scalars` to the `vector`.
+    pub fn write_vector(
+        &mut self,
+        scalars: Vec<ImmTy<'tcx, M::PointerTag>>,
+        vector: PlaceTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx> {
+        assert_ne!(scalars.len(), 0);
+        match vector.layout.ty.sty {
+            ty::Adt(def, ..) if def.repr.simd() => {
+                let tcx = &*self.tcx;
+                let count = vector.layout.ty.simd_size(*tcx);
+                assert_eq!(count, scalars.len());
+                for index in 0..scalars.len() {
+                    self.write_scalar_to_vector(scalars[index], vector, index)?;
+                }
+            }
+            _ => bug!("not a vector"),
+        }
+        Ok(())
+    }
+
     /// Write an `Immediate` to memory.
     #[inline(always)]
     pub fn write_immediate_to_mplace(
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 8310ef02f96..a324c585124 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -249,7 +249,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         match instance.def {
             ty::InstanceDef::Intrinsic(..) => {
-                if caller_abi != Abi::RustIntrinsic {
+                if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = caller_abi {
+                    // ok
+                } else {
                     throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))
                 }
                 // The intrinsic itself cannot diverge, so if we got here without a return
diff --git a/src/test/ui/consts/const-eval/const_eval-simd.rs b/src/test/ui/consts/const-eval/const_eval-simd.rs
new file mode 100644
index 00000000000..a0f088cc636
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_eval-simd.rs
@@ -0,0 +1,24 @@
+// run-pass
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(repr_simd)]
+#![feature(platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)] struct i8x1(i8);
+
+extern "platform-intrinsic" {
+    fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
+    fn simd_extract<T, U>(x: T, idx: u32) -> U;
+}
+
+const fn foo(x: i8x1) -> i8 {
+    unsafe { simd_insert(x, 0_u32, 42_i8) }.0
+}
+
+fn main() {
+    const V: i8x1 = i8x1(13);
+    const X: i8 = foo(V);
+    const Y: i8 = unsafe { simd_extract(V, 0) };
+    assert_eq!(X, 42);
+    assert_eq!(Y, 13);
+}
diff --git a/src/test/ui/consts/const-eval/const_eval-simd.stderr b/src/test/ui/consts/const-eval/const_eval-simd.stderr
new file mode 100644
index 00000000000..7fc068718b0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_eval-simd.stderr
@@ -0,0 +1,48 @@
+warning: skipping const checks
+  --> $DIR/const_eval-simd.rs:22:5
+   |
+LL |     assert_eq!(X, 42);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_eval-simd.rs:22:5
+   |
+LL |     assert_eq!(X, 42);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_eval-simd.rs:22:5
+   |
+LL |     assert_eq!(X, 42);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_eval-simd.rs:23:5
+   |
+LL |     assert_eq!(Y, 13);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_eval-simd.rs:23:5
+   |
+LL |     assert_eq!(Y, 13);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_eval-simd.rs:23:5
+   |
+LL |     assert_eq!(Y, 13);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+