about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2021-09-11 14:47:28 +0000
committerCaleb Zulawski <caleb.zulawski@gmail.com>2021-09-11 14:55:14 +0000
commit1b3fe755ea3d39a1875f627fab5def4eae03e912 (patch)
treea2fc1b6f1ffd29360478062716f30da422eb7945
parentb69fe57261086e70aea9d5b58819a1794bf7c121 (diff)
downloadrust-1b3fe755ea3d39a1875f627fab5def4eae03e912.tar.gz
rust-1b3fe755ea3d39a1875f627fab5def4eae03e912.zip
Allow simd_shuffle to accept vectors of any length
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs25
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0439.md4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs7
-rw-r--r--compiler/rustc_typeck/src/errors.rs8
-rw-r--r--src/test/ui/error-codes/E0439.rs8
-rw-r--r--src/test/ui/error-codes/E0439.stderr9
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs33
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr21
-rw-r--r--src/test/ui/simd/shuffle-not-out-of-bounds.rs10
-rw-r--r--src/test/ui/simd/shuffle-not-out-of-bounds.stderr8
-rw-r--r--src/test/ui/simd/shuffle.rs24
12 files changed, 125 insertions, 33 deletions
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 1aa52d975e9..f6219b06d2d 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -918,12 +918,29 @@ fn generic_simd_intrinsic(
     }
 
     if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
-        let n: u64 = stripped.parse().unwrap_or_else(|_| {
-            span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
-        });
+        // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
+        // If there is no suffix, use the index array length.
+        let n: u64 = if stripped.is_empty() {
+            // Make sure this is actually an array, since typeck only checks the length-suffixed
+            // version of this intrinsic.
+            match args[2].layout.ty.kind() {
+                ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
+                    len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
+                        span_bug!(span, "could not evaluate shuffle index array length")
+                    })
+                }
+                _ => return_error!(
+                    "simd_shuffle index must be an array of `u32`, got `{}`",
+                    args[2].layout.ty
+                ),
+            }
+        } else {
+            stripped.parse().unwrap_or_else(|_| {
+                span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
+            })
+        };
 
         require_simd!(ret_ty, "return");
-
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             out_len == n,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md
index 3e663df866c..24268aef222 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0439.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0439.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 The length of the platform-intrinsic function `simd_shuffle` wasn't specified.
 
 Erroneous code example:
 
-```compile_fail,E0439
+```ignore (no longer emitted)
 #![feature(platform_intrinsics)]
 
 extern "platform-intrinsic" {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 24023163cc3..e96005ec7b6 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1210,6 +1210,7 @@ symbols! {
         simd_select_bitmask,
         simd_shl,
         simd_shr,
+        simd_shuffle,
         simd_sub,
         simd_trunc,
         simd_xor,
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 664954b0eb7..ff7a26853b1 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -2,7 +2,7 @@
 //! intrinsics that the compiler exposes.
 
 use crate::errors::{
-    SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
+    UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
     WrongNumberOfGenericArgumentsToIntrinsic,
 };
 use crate::require_same_types;
@@ -468,6 +468,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         | sym::simd_reduce_max
         | sym::simd_reduce_min_nanless
         | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
+        sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)),
         name if name.as_str().starts_with("simd_shuffle") => {
             match name.as_str()["simd_shuffle".len()..].parse() {
                 Ok(n) => {
@@ -475,7 +476,9 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
                     (2, params, param(1))
                 }
                 Err(_) => {
-                    tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name });
+                    let msg =
+                        format!("unrecognized platform-specific intrinsic function: `{}`", name);
+                    tcx.sess.struct_span_err(it.span, &msg).emit();
                     return;
                 }
             }
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 1e6a240b2f8..47077779616 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -122,14 +122,6 @@ pub struct AssocTypeBindingNotAllowed {
 }
 
 #[derive(SessionDiagnostic)]
-#[error = "E0439"]
-pub struct SimdShuffleMissingLength {
-    #[message = "invalid `simd_shuffle`, needs length: `{name}`"]
-    pub span: Span,
-    pub name: Symbol,
-}
-
-#[derive(SessionDiagnostic)]
 #[error = "E0436"]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[message = "functional record update syntax requires a struct"]
diff --git a/src/test/ui/error-codes/E0439.rs b/src/test/ui/error-codes/E0439.rs
deleted file mode 100644
index 86e9cb55a9c..00000000000
--- a/src/test/ui/error-codes/E0439.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(platform_intrinsics)]
-
-extern "platform-intrinsic" {
-    fn simd_shuffle<A,B>(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439
-}
-
-fn main () {
-}
diff --git a/src/test/ui/error-codes/E0439.stderr b/src/test/ui/error-codes/E0439.stderr
deleted file mode 100644
index 8021f7d3951..00000000000
--- a/src/test/ui/error-codes/E0439.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0439]: invalid `simd_shuffle`, needs length: `simd_shuffle`
-  --> $DIR/E0439.rs:4:5
-   |
-LL |     fn simd_shuffle<A,B>(a: A, b: A, c: [u32; 8]) -> B;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0439`.
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs
new file mode 100644
index 00000000000..9611780ac07
--- /dev/null
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs
@@ -0,0 +1,33 @@
+// build-fail
+
+// Test that the simd_shuffle intrinsic produces ok-ish error
+// messages when misused.
+
+#![feature(repr_simd, platform_intrinsics)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct Simd<T, const N: usize>([T; N]);
+
+extern "platform-intrinsic" {
+    fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+}
+
+fn main() {
+    const I: [u32; 2] = [0; 2];
+    const I2: [f32; 2] = [0.; 2];
+    let v = Simd::<u32, 4>([0; 4]);
+
+    unsafe {
+        let _: Simd<u32, 2> = simd_shuffle(v, v, I);
+
+        let _: Simd<u32, 4> = simd_shuffle(v, v, I);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+
+        let _: Simd<f32, 2> = simd_shuffle(v, v, I);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+
+        let _: Simd<u32, 2> = simd_shuffle(v, v, I2);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+    }
+}
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr
new file mode 100644
index 00000000000..9eeb000fd26
--- /dev/null
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr
@@ -0,0 +1,21 @@
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd<u32, 4_usize>` with length 4
+  --> $DIR/simd-intrinsic-generic-shuffle.rs:24:31
+   |
+LL |         let _: Simd<u32, 4> = simd_shuffle(v, v, I);
+   |                               ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd<u32, 4_usize>`), found `Simd<f32, 2_usize>` with element type `f32`
+  --> $DIR/simd-intrinsic-generic-shuffle.rs:27:31
+   |
+LL |         let _: Simd<f32, 2> = simd_shuffle(v, v, I);
+   |                               ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be an array of `u32`, got `[f32; 2]`
+  --> $DIR/simd-intrinsic-generic-shuffle.rs:30:31
+   |
+LL |         let _: Simd<u32, 2> = simd_shuffle(v, v, I2);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.rs b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
index 8a533453e75..aae6ce4663f 100644
--- a/src/test/ui/simd/shuffle-not-out-of-bounds.rs
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
@@ -188,4 +188,14 @@ fn main() {
          48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
          32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
          16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+
+    extern "platform-intrinsic" {
+        fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+    }
+    let v = u8x2(0, 0);
+    const I: [u32; 2] = [4, 4];
+    unsafe {
+        let _: u8x2 = simd_shuffle(v, v, I);
+        //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
+    }
 }
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
index 07253a4ae46..737fb5e6e51 100644
--- a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
@@ -71,6 +71,12 @@ LL | |          16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 6 previous errors
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
+  --> $DIR/shuffle-not-out-of-bounds.rs:198:23
+   |
+LL |         let _: u8x2 = simd_shuffle(v, v, I);
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/simd/shuffle.rs b/src/test/ui/simd/shuffle.rs
new file mode 100644
index 00000000000..3592adfdc6a
--- /dev/null
+++ b/src/test/ui/simd/shuffle.rs
@@ -0,0 +1,24 @@
+//run-pass
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct Simd<T, const N: usize>([T; N]);
+
+fn main() {
+    const I1: [u32; 4] = [0, 2, 4, 6];
+    const I2: [u32; 2] = [1, 5];
+    let a = Simd::<u8, 4>([0, 1, 2, 3]);
+    let b = Simd::<u8, 4>([4, 5, 6, 7]);
+    unsafe {
+        let x: Simd<u8, 4> = simd_shuffle(a, b, I1);
+        assert_eq!(x.0, [0, 2, 4, 6]);
+
+        let y: Simd<u8, 2> = simd_shuffle(a, b, I2);
+        assert_eq!(y.0, [1, 5]);
+    }
+}