about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-29 09:28:09 +0000
committerbors <bors@rust-lang.org>2020-11-29 09:28:09 +0000
commit760430e6fdd70cdb09b5b6d696905c0ee0ea27c8 (patch)
tree3807c43e5e80fb6daf02630212578b400258495a
parent3cbb56f80b2fbf5a3b405212665918dbffc44d39 (diff)
parent354c7d0ab800f70e995383d498fc1fc420baa209 (diff)
downloadrust-760430e6fdd70cdb09b5b6d696905c0ee0ea27c8.tar.gz
rust-760430e6fdd70cdb09b5b6d696905c0ee0ea27c8.zip
Auto merge of #78863 - KodrAus:feat/simd-array, r=oli-obk
Support repr(simd) on ADTs containing a single array field

This is a squash and rebase of `@gnzlbg's` #63531

I've never actually written code in the compiler before so just fumbled my way around until it would build 😅

I imagine there'll be some work we need to do in `rustc_codegen_cranelift` too for this now, but might need some input from `@bjorn3` to know what that is.

cc `@rust-lang/project-portable-simd`

-----

This PR allows using `#[repr(simd)]` on ADTs containing a single array field:

```rust
 #[repr(simd)] struct S0([f32; 4]);
 #[repr(simd)] struct S1<const N: usize>([f32; N]);
 #[repr(simd)] struct S2<T, const N: usize>([T; N]);
```

This should allow experimenting with portable packed SIMD abstractions on nightly that make use of const generics.
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs105
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs109
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs29
-rw-r--r--compiler/rustc_typeck/src/check/check.rs4
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs47
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs44
-rw-r--r--src/test/ui/error-codes/E0077.stderr2
-rw-r--r--src/test/ui/simd-type-generic-monomorphisation.rs4
-rw-r--r--src/test/ui/simd-type-generic-monomorphisation.stderr2
-rw-r--r--src/test/ui/simd-type.rs10
-rw-r--r--src/test/ui/simd-type.stderr20
-rw-r--r--src/test/ui/simd/simd-array-trait.rs41
-rw-r--r--src/test/ui/simd/simd-array-trait.stderr10
-rw-r--r--src/test/ui/simd/simd-array-type.rs42
-rw-r--r--src/test/ui/simd/simd-generics.rs28
-rw-r--r--src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs66
-rw-r--r--src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs61
17 files changed, 467 insertions, 157 deletions
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index ac423d01bf1..ec557b7a682 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -792,7 +792,7 @@ fn generic_simd_intrinsic(
             _ => return_error!("`{}` is not an integral type", in_ty),
         };
         require_simd!(arg_tys[1], "argument");
-        let v_len = arg_tys[1].simd_size(tcx);
+        let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         require!(
             // Allow masks for vectors with fewer than 8 elements to be
             // represented with a u8 or i8.
@@ -812,8 +812,6 @@ fn generic_simd_intrinsic(
     // every intrinsic below takes a SIMD vector as its first argument
     require_simd!(arg_tys[0], "input");
     let in_ty = arg_tys[0];
-    let in_elem = arg_tys[0].simd_type(tcx);
-    let in_len = arg_tys[0].simd_size(tcx);
 
     let comparison = match name {
         sym::simd_eq => Some(hir::BinOpKind::Eq),
@@ -825,14 +823,15 @@ fn generic_simd_intrinsic(
         _ => None,
     };
 
+    let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
     if let Some(cmp_op) = comparison {
         require_simd!(ret_ty, "return");
 
-        let out_len = ret_ty.simd_size(tcx);
+        let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
             "expected return type with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
+             found `{}` with length {}",
             in_len,
             in_ty,
             ret_ty,
@@ -842,7 +841,7 @@ fn generic_simd_intrinsic(
             bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
             "expected return type with integer elements, found `{}` with non-integer `{}`",
             ret_ty,
-            ret_ty.simd_type(tcx)
+            out_ty
         );
 
         return Ok(compare_simd_types(
@@ -862,7 +861,7 @@ fn generic_simd_intrinsic(
 
         require_simd!(ret_ty, "return");
 
-        let out_len = ret_ty.simd_size(tcx);
+        let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             out_len == n,
             "expected return type of length {}, found `{}` with length {}",
@@ -871,13 +870,13 @@ fn generic_simd_intrinsic(
             out_len
         );
         require!(
-            in_elem == ret_ty.simd_type(tcx),
+            in_elem == out_ty,
             "expected return element type `{}` (element of input `{}`), \
-                  found `{}` with element type `{}`",
+             found `{}` with element type `{}`",
             in_elem,
             in_ty,
             ret_ty,
-            ret_ty.simd_type(tcx)
+            out_ty
         );
 
         let total_len = u128::from(in_len) * 2;
@@ -946,7 +945,7 @@ fn generic_simd_intrinsic(
         let m_elem_ty = in_elem;
         let m_len = in_len;
         require_simd!(arg_tys[1], "argument");
-        let v_len = arg_tys[1].simd_size(tcx);
+        let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         require!(
             m_len == v_len,
             "mismatched lengths: mask length `{}` != other vector length `{}`",
@@ -1173,25 +1172,27 @@ fn generic_simd_intrinsic(
         require_simd!(ret_ty, "return");
 
         // Of the same length:
+        let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+        let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
         require!(
-            in_len == arg_tys[1].simd_size(tcx),
+            in_len == out_len,
             "expected {} argument with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
+             found `{}` with length {}",
             "second",
             in_len,
             in_ty,
             arg_tys[1],
-            arg_tys[1].simd_size(tcx)
+            out_len
         );
         require!(
-            in_len == arg_tys[2].simd_size(tcx),
+            in_len == out_len2,
             "expected {} argument with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
+             found `{}` with length {}",
             "third",
             in_len,
             in_ty,
             arg_tys[2],
-            arg_tys[2].simd_size(tcx)
+            out_len2
         );
 
         // The return type must match the first argument type
@@ -1215,39 +1216,40 @@ fn generic_simd_intrinsic(
 
         // The second argument must be a simd vector with an element type that's a pointer
         // to the element type of the first argument
-        let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() {
-            ty::RawPtr(p) if p.ty == in_elem => {
-                (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx)))
-            }
+        let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
+        let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
+        let (pointer_count, underlying_ty) = match element_ty1.kind() {
+            ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
             _ => {
                 require!(
                     false,
                     "expected element type `{}` of second argument `{}` \
-                                 to be a pointer to the element type `{}` of the first \
-                                 argument `{}`, found `{}` != `*_ {}`",
-                    arg_tys[1].simd_type(tcx),
+                        to be a pointer to the element type `{}` of the first \
+                        argument `{}`, found `{}` != `*_ {}`",
+                    element_ty1,
                     arg_tys[1],
                     in_elem,
                     in_ty,
-                    arg_tys[1].simd_type(tcx),
+                    element_ty1,
                     in_elem
                 );
                 unreachable!();
             }
         };
         assert!(pointer_count > 0);
-        assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
-        assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
+        assert_eq!(pointer_count - 1, ptr_count(element_ty0));
+        assert_eq!(underlying_ty, non_ptr(element_ty0));
 
         // The element type of the third argument must be a signed integer type of any width:
-        match arg_tys[2].simd_type(tcx).kind() {
+        let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
+        match element_ty2.kind() {
             ty::Int(_) => (),
             _ => {
                 require!(
                     false,
                     "expected element type `{}` of third argument `{}` \
                                  to be a signed integer type",
-                    arg_tys[2].simd_type(tcx),
+                    element_ty2,
                     arg_tys[2]
                 );
             }
@@ -1299,25 +1301,27 @@ fn generic_simd_intrinsic(
         require_simd!(arg_tys[2], "third");
 
         // Of the same length:
+        let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+        let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
         require!(
-            in_len == arg_tys[1].simd_size(tcx),
+            in_len == element_len1,
             "expected {} argument with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
+            found `{}` with length {}",
             "second",
             in_len,
             in_ty,
             arg_tys[1],
-            arg_tys[1].simd_size(tcx)
+            element_len1
         );
         require!(
-            in_len == arg_tys[2].simd_size(tcx),
+            in_len == element_len2,
             "expected {} argument with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
+            found `{}` with length {}",
             "third",
             in_len,
             in_ty,
             arg_tys[2],
-            arg_tys[2].simd_size(tcx)
+            element_len2
         );
 
         // This counts how many pointers
@@ -1338,39 +1342,42 @@ fn generic_simd_intrinsic(
 
         // The second argument must be a simd vector with an element type that's a pointer
         // to the element type of the first argument
-        let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() {
+        let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
+        let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
+        let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
+        let (pointer_count, underlying_ty) = match element_ty1.kind() {
             ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => {
-                (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx)))
+                (ptr_count(element_ty1), non_ptr(element_ty1))
             }
             _ => {
                 require!(
                     false,
                     "expected element type `{}` of second argument `{}` \
-                                 to be a pointer to the element type `{}` of the first \
-                                 argument `{}`, found `{}` != `*mut {}`",
-                    arg_tys[1].simd_type(tcx),
+                        to be a pointer to the element type `{}` of the first \
+                        argument `{}`, found `{}` != `*mut {}`",
+                    element_ty1,
                     arg_tys[1],
                     in_elem,
                     in_ty,
-                    arg_tys[1].simd_type(tcx),
+                    element_ty1,
                     in_elem
                 );
                 unreachable!();
             }
         };
         assert!(pointer_count > 0);
-        assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
-        assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
+        assert_eq!(pointer_count - 1, ptr_count(element_ty0));
+        assert_eq!(underlying_ty, non_ptr(element_ty0));
 
         // The element type of the third argument must be a signed integer type of any width:
-        match arg_tys[2].simd_type(tcx).kind() {
+        match element_ty2.kind() {
             ty::Int(_) => (),
             _ => {
                 require!(
                     false,
                     "expected element type `{}` of third argument `{}` \
-                                 to be a signed integer type",
-                    arg_tys[2].simd_type(tcx),
+                         be a signed integer type",
+                    element_ty2,
                     arg_tys[2]
                 );
             }
@@ -1567,7 +1574,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
 
     if name == sym::simd_cast {
         require_simd!(ret_ty, "return");
-        let out_len = ret_ty.simd_size(tcx);
+        let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
             "expected return type with length {} (same as input type `{}`), \
@@ -1578,8 +1585,6 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
             out_len
         );
         // casting cares about nominal type, not just structural type
-        let out_elem = ret_ty.simd_type(tcx);
-
         if in_elem == out_elem {
             return Ok(args[0].immediate());
         }
@@ -1695,7 +1700,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
                 return_error!(
                     "expected element type `{}` of vector type `{}` \
                      to be a signed or unsigned integer type",
-                    arg_tys[0].simd_type(tcx),
+                    arg_tys[0].simd_size_and_type(bx.tcx()).1,
                     arg_tys[0]
                 );
             }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index fa0711193df..8bdc7efa0bb 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -631,30 +631,106 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             }
 
             // SIMD vector types.
-            ty::Adt(def, ..) if def.repr.simd() => {
-                let element = self.layout_of(ty.simd_type(tcx))?;
-                let count = ty.simd_size(tcx);
-                assert!(count > 0);
-                let scalar = match element.abi {
-                    Abi::Scalar(ref scalar) => scalar.clone(),
-                    _ => {
+            ty::Adt(def, substs) if def.repr.simd() => {
+                // Supported SIMD vectors are homogeneous ADTs with at least one field:
+                //
+                // * #[repr(simd)] struct S(T, T, T, T);
+                // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T }
+                // * #[repr(simd)] struct S([T; 4])
+                //
+                // where T is a primitive scalar (integer/float/pointer).
+
+                // SIMD vectors with zero fields are not supported.
+                // (should be caught by typeck)
+                if def.non_enum_variant().fields.is_empty() {
+                    tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+                }
+
+                // Type of the first ADT field:
+                let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs);
+
+                // Heterogeneous SIMD vectors are not supported:
+                // (should be caught by typeck)
+                for fi in &def.non_enum_variant().fields {
+                    if fi.ty(tcx, substs) != f0_ty {
+                        tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty));
+                    }
+                }
+
+                // The element type and number of elements of the SIMD vector
+                // are obtained from:
+                //
+                // * the element type and length of the single array field, if
+                // the first field is of array type, or
+                //
+                // * the homogenous field type and the number of fields.
+                let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() {
+                    // First ADT field is an array:
+
+                    // SIMD vectors with multiple array fields are not supported:
+                    // (should be caught by typeck)
+                    if def.non_enum_variant().fields.len() != 1 {
                         tcx.sess.fatal(&format!(
-                            "monomorphising SIMD type `{}` with \
-                                                 a non-machine element type `{}`",
-                            ty, element.ty
+                            "monomorphising SIMD type `{}` with more than one array field",
+                            ty
                         ));
                     }
+
+                    // Extract the number of elements from the layout of the array field:
+                    let len = if let Ok(TyAndLayout {
+                        layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
+                        ..
+                    }) = self.layout_of(f0_ty)
+                    {
+                        count
+                    } else {
+                        return Err(LayoutError::Unknown(ty));
+                    };
+
+                    (*e_ty, *len, true)
+                } else {
+                    // First ADT field is not an array:
+                    (f0_ty, def.non_enum_variant().fields.len() as _, false)
                 };
-                let size =
-                    element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
+
+                // SIMD vectors of zero length are not supported.
+                //
+                // Can't be caught in typeck if the array length is generic.
+                if e_len == 0 {
+                    tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+                }
+
+                // Compute the ABI of the element type:
+                let e_ly = self.layout_of(e_ty)?;
+                let e_abi = if let Abi::Scalar(ref scalar) = e_ly.abi {
+                    scalar.clone()
+                } else {
+                    // This error isn't caught in typeck, e.g., if
+                    // the element type of the vector is generic.
+                    tcx.sess.fatal(&format!(
+                        "monomorphising SIMD type `{}` with a non-primitive-scalar \
+                        (integer/float/pointer) element type `{}`",
+                        ty, e_ty
+                    ))
+                };
+
+                // Compute the size and alignment of the vector:
+                let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?;
                 let align = dl.vector_align(size);
                 let size = size.align_to(align.abi);
 
+                // Compute the placement of the vector fields:
+                let fields = if is_array {
+                    FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] }
+                } else {
+                    FieldsShape::Array { stride: e_ly.size, count: e_len }
+                };
+
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: VariantIdx::new(0) },
-                    fields: FieldsShape::Array { stride: element.size, count },
-                    abi: Abi::Vector { element: scalar, count },
-                    largest_niche: element.largest_niche.clone(),
+                    fields,
+                    abi: Abi::Vector { element: e_abi, count: e_len },
+                    largest_niche: e_ly.largest_niche.clone(),
                     size,
                     align,
                 })
@@ -2121,9 +2197,6 @@ where
 
             ty::Tuple(tys) => tys[i].expect_ty(),
 
-            // SIMD vector types.
-            ty::Adt(def, ..) if def.repr.simd() => this.ty.simd_type(tcx),
-
             // ADTs.
             ty::Adt(def, substs) => {
                 match this.variants {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index c906b8ac901..78994c6e1c7 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1956,27 +1956,22 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
-    pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        match self.kind() {
-            Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs),
-            _ => bug!("`simd_type` called on invalid type"),
-        }
-    }
-
-    pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 {
-        // Parameter currently unused, but probably needed in the future to
-        // allow `#[repr(simd)] struct Simd<T, const N: usize>([T; N]);`.
-        match self.kind() {
-            Adt(def, _) => def.non_enum_variant().fields.len() as u64,
-            _ => bug!("`simd_size` called on invalid type"),
-        }
-    }
-
     pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
         match self.kind() {
             Adt(def, substs) => {
                 let variant = def.non_enum_variant();
-                (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs))
+                let f0_ty = variant.fields[0].ty(tcx, substs);
+
+                match f0_ty.kind() {
+                    Array(f0_elem_ty, f0_len) => {
+                        // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
+                        // The way we evaluate the `N` in `[T; N]` here only works since we use
+                        // `simd_size_and_type` post-monomorphization. It will probably start to ICE
+                        // if we use it in generic code. See the `simd-array-trait` ui test.
+                        (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty)
+                    }
+                    _ => (variant.fields.len() as u64, f0_ty),
+                }
             }
             _ => bug!("`simd_size_and_type` called on invalid type"),
         }
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 55c815b21ad..489d836298f 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1098,12 +1098,14 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             match e.kind() {
                 ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
                 _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
+                ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ }
                 _ => {
                     struct_span_err!(
                         tcx.sess,
                         sp,
                         E0077,
-                        "SIMD vector element type should be machine type"
+                        "SIMD vector element type should be a \
+                         primitive scalar (integer/float/pointer) type"
                     )
                     .emit();
                     return;
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs
new file mode 100644
index 00000000000..b5b0b1330a6
--- /dev/null
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs
@@ -0,0 +1,47 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct M(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct S<const N: usize>([f32; N]);
+
+extern "platform-intrinsic" {
+    fn simd_extract<T, U>(x: T, idx: u32) -> U;
+    fn simd_insert<T, U>(x: T, idx: u32, b: U) -> T;
+}
+
+// CHECK-LABEL: @extract_m
+#[no_mangle]
+pub unsafe fn extract_m(v: M, i: u32) -> f32  {
+    // CHECK: extractelement <4 x float> %{{v|_3}}, i32 %i
+    simd_extract(v, i)
+}
+
+// CHECK-LABEL: @extract_s
+#[no_mangle]
+pub unsafe fn extract_s(v: S<4>, i: u32) -> f32  {
+    // CHECK: extractelement <4 x float> %{{v|_3}}, i32 %i
+    simd_extract(v, i)
+}
+
+// CHECK-LABEL: @insert_m
+#[no_mangle]
+pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M  {
+    // CHECK: insertelement <4 x float> %{{v|_4}}, float %j, i32 %i
+    simd_insert(v, i, j)
+}
+
+// CHECK-LABEL: @insert_s
+#[no_mangle]
+pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4>  {
+    // CHECK: insertelement <4 x float> %{{v|_4}}, float %j, i32 %i
+    simd_insert(v, i, j)
+}
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
new file mode 100644
index 00000000000..56466a78d5a
--- /dev/null
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -0,0 +1,44 @@
+// ignore-tidy-linelength
+// compile-flags: -C no-prepopulate-passes
+// min-llvm-version 8.0
+
+#![crate_type = "lib"]
+
+#![allow(non_camel_case_types)]
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct S<const N: usize>([f32; N]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct T([f32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct U(f32, f32, f32, f32);
+
+// CHECK-LABEL: @build_array_s
+#[no_mangle]
+pub fn build_array_s(x: [f32; 4]) -> S<4> {
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{[0-9]+}}(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %{{[0-9]+}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{[0-9]+}}(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %{{[0-9]+}}, i{{[0-9]+}} 16, i1 false)
+    S::<4>(x)
+}
+
+// CHECK-LABEL: @build_array_t
+#[no_mangle]
+pub fn build_array_t(x: [f32; 4]) -> T {
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{[0-9]+}}(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %{{[0-9]+}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{[0-9]+}}(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %{{[0-9]+}}, i{{[0-9]+}} 16, i1 false)
+    T(x)
+}
+
+// CHECK-LABEL: @build_array_u
+#[no_mangle]
+pub fn build_array_u(x: [f32; 4]) -> U {
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{[0-9]+}}(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %{{[0-9]+}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{[0-9]+}}(i8* {{.*}} %{{[0-9]+}}, i8* {{.*}} %{{[0-9]+}}, i{{[0-9]+}} 16, i1 false)
+    unsafe { std::mem::transmute(x) }
+}
diff --git a/src/test/ui/error-codes/E0077.stderr b/src/test/ui/error-codes/E0077.stderr
index 4f85d175ce6..1938a9a272a 100644
--- a/src/test/ui/error-codes/E0077.stderr
+++ b/src/test/ui/error-codes/E0077.stderr
@@ -1,4 +1,4 @@
-error[E0077]: SIMD vector element type should be machine type
+error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type
   --> $DIR/E0077.rs:4:1
    |
 LL | struct Bad(String);
diff --git a/src/test/ui/simd-type-generic-monomorphisation.rs b/src/test/ui/simd-type-generic-monomorphisation.rs
index fc5e23f4986..0275f0ce4c1 100644
--- a/src/test/ui/simd-type-generic-monomorphisation.rs
+++ b/src/test/ui/simd-type-generic-monomorphisation.rs
@@ -2,7 +2,9 @@
 
 #![feature(repr_simd, platform_intrinsics)]
 
-// error-pattern:monomorphising SIMD type `Simd2<X>` with a non-machine element type `X`
+// ignore-tidy-linelength
+
+// error-pattern:monomorphising SIMD type `Simd2<X>` with a non-primitive-scalar (integer/float/pointer) element type `X`
 
 struct X(Vec<i32>);
 #[repr(simd)]
diff --git a/src/test/ui/simd-type-generic-monomorphisation.stderr b/src/test/ui/simd-type-generic-monomorphisation.stderr
index 2a74506e80e..7f23893ac85 100644
--- a/src/test/ui/simd-type-generic-monomorphisation.stderr
+++ b/src/test/ui/simd-type-generic-monomorphisation.stderr
@@ -1,4 +1,4 @@
-error: monomorphising SIMD type `Simd2<X>` with a non-machine element type `X`
+error: monomorphising SIMD type `Simd2<X>` with a non-primitive-scalar (integer/float/pointer) element type `X`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/simd-type.rs b/src/test/ui/simd-type.rs
index 9e4b7e76560..a320df85138 100644
--- a/src/test/ui/simd-type.rs
+++ b/src/test/ui/simd-type.rs
@@ -1,10 +1,20 @@
 #![feature(repr_simd)]
 #![allow(non_camel_case_types)]
 
+// ignore-tidy-linelength
+
 #[repr(simd)]
 struct empty; //~ ERROR SIMD vector cannot be empty
 
 #[repr(simd)]
 struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous
 
+struct Foo;
+
+#[repr(simd)]
+struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type
+
+#[repr(simd)]
+struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type
+
 fn main() {}
diff --git a/src/test/ui/simd-type.stderr b/src/test/ui/simd-type.stderr
index 0c4242f46b7..23004c78591 100644
--- a/src/test/ui/simd-type.stderr
+++ b/src/test/ui/simd-type.stderr
@@ -1,16 +1,28 @@
 error[E0075]: SIMD vector cannot be empty
-  --> $DIR/simd-type.rs:5:1
+  --> $DIR/simd-type.rs:7:1
    |
 LL | struct empty;
    | ^^^^^^^^^^^^^
 
 error[E0076]: SIMD vector should be homogeneous
-  --> $DIR/simd-type.rs:8:1
+  --> $DIR/simd-type.rs:10:1
    |
 LL | struct i64f64(i64, f64);
    | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type
 
-error: aborting due to 2 previous errors
+error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type
+  --> $DIR/simd-type.rs:15:1
+   |
+LL | struct FooV(Foo, Foo);
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type
+  --> $DIR/simd-type.rs:18:1
+   |
+LL | struct FooV2([Foo; 2]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0075, E0076.
+Some errors have detailed explanations: E0075, E0076, E0077.
 For more information about an error, try `rustc --explain E0075`.
diff --git a/src/test/ui/simd/simd-array-trait.rs b/src/test/ui/simd/simd-array-trait.rs
new file mode 100644
index 00000000000..d6ed5f61a00
--- /dev/null
+++ b/src/test/ui/simd/simd-array-trait.rs
@@ -0,0 +1,41 @@
+// Figuring out the size of a vector type that depends on traits doesn't ICE
+
+#![allow(dead_code)]
+
+// pretty-expanded FIXME #23616
+
+#![feature(repr_simd, platform_intrinsics, const_generics)]
+#![allow(non_camel_case_types, incomplete_features)]
+
+pub trait Simd {
+    type Lane: Clone + Copy;
+    const SIZE: usize;
+}
+
+pub struct i32x4;
+impl Simd for i32x4 {
+    type Lane = i32;
+    const SIZE: usize = 4;
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct T<S: Simd>([S::Lane; S::SIZE]);
+//~^ ERROR constant expression depends on a generic parameter
+
+extern "platform-intrinsic" {
+    fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
+    fn simd_extract<T, E>(x: T, idx: u32) -> E;
+}
+
+pub fn main() {
+    let mut t = T::<i32x4>([0; 4]);
+    unsafe {
+        for i in 0_i32..4 {
+            t = simd_insert(t, i as u32, i);
+        }
+        for i in 0_i32..4 {
+            assert_eq!(i, simd_extract(t, i as u32));
+        }
+    }
+}
diff --git a/src/test/ui/simd/simd-array-trait.stderr b/src/test/ui/simd/simd-array-trait.stderr
new file mode 100644
index 00000000000..c100e020c54
--- /dev/null
+++ b/src/test/ui/simd/simd-array-trait.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/simd-array-trait.rs:23:23
+   |
+LL | pub struct T<S: Simd>([S::Lane; S::SIZE]);
+   |                       ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/simd/simd-array-type.rs b/src/test/ui/simd/simd-array-type.rs
new file mode 100644
index 00000000000..e84186a42ad
--- /dev/null
+++ b/src/test/ui/simd/simd-array-type.rs
@@ -0,0 +1,42 @@
+// run-pass
+#![allow(dead_code)]
+
+// pretty-expanded FIXME #23616
+
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct S([i32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct T<const N: usize>([i32; N]);
+
+extern "platform-intrinsic" {
+    fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
+    fn simd_extract<T, E>(x: T, idx: u32) -> E;
+}
+
+pub fn main() {
+    let mut s = S([0; 4]);
+
+    unsafe {
+        for i in 0_i32..4 {
+            s = simd_insert(s, i as u32, i);
+        }
+        for i in 0_i32..4 {
+            assert_eq!(i, simd_extract(s, i as u32));
+        }
+    }
+
+    let mut t = T::<4>([0; 4]);
+    unsafe {
+        for i in 0_i32..4 {
+            t = simd_insert(t, i as u32, i);
+        }
+        for i in 0_i32..4 {
+            assert_eq!(i, simd_extract(t, i as u32));
+        }
+    }
+}
diff --git a/src/test/ui/simd/simd-generics.rs b/src/test/ui/simd/simd-generics.rs
index ab6caee9d7b..dedca6276cd 100644
--- a/src/test/ui/simd/simd-generics.rs
+++ b/src/test/ui/simd/simd-generics.rs
@@ -1,9 +1,6 @@
 // run-pass
 #![allow(non_camel_case_types)]
-
-
-
-#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
 
 use std::ops;
 
@@ -11,6 +8,11 @@ use std::ops;
 #[derive(Copy, Clone)]
 struct f32x4(f32, f32, f32, f32);
 
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct S<const N: usize>([f32; N]);
+
+
 extern "platform-intrinsic" {
     fn simd_add<T>(x: T, y: T) -> T;
 }
@@ -23,10 +25,19 @@ impl ops::Add for f32x4 {
     type Output = f32x4;
 
     fn add(self, rhs: f32x4) -> f32x4 {
-        unsafe {simd_add(self, rhs)}
+        unsafe { simd_add(self, rhs) }
     }
 }
 
+impl ops::Add for S<4> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        unsafe { simd_add(self, rhs) }
+    }
+}
+
+
 pub fn main() {
     let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32);
 
@@ -36,4 +47,11 @@ pub fn main() {
     assert_eq!(y, 4.0f32);
     assert_eq!(z, 6.0f32);
     assert_eq!(w, 8.0f32);
+
+    let lr2 = S::<4>([1.0f32, 2.0f32, 3.0f32, 4.0f32]);
+    let [x, y, z, w] = add(lr2, lr2).0;
+    assert_eq!(x, 2.0f32);
+    assert_eq!(y, 4.0f32);
+    assert_eq!(z, 6.0f32);
+    assert_eq!(w, 8.0f32);
 }
diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs
index b7b3ec99781..4c459fa4bc8 100644
--- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs
+++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs
@@ -2,15 +2,15 @@
 // ignore-emscripten
 
 #![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
 
 #[repr(simd)]
 #[derive(Copy, Clone, PartialEq, Debug)]
 struct u32x4(pub u32, pub u32, pub u32, pub u32);
 
 #[repr(simd)]
-#[derive(Copy, Clone, PartialEq, Debug)]
-struct i32x4(pub i32, pub i32, pub i32, pub i32);
+#[derive(Copy, Clone)]
+struct I32<const N: usize>([i32; N]);
 
 extern "platform-intrinsic" {
     fn simd_saturating_add<T>(x: T, y: T) -> T;
@@ -51,41 +51,41 @@ fn main() {
         const MIN: i32 = i32::MIN;
         const MAX: i32 = i32::MAX;
 
-        let a = i32x4(1, 2, 3, 4);
-        let b = i32x4(2, 4, 6, 8);
-        let c = i32x4(-1, -2, -3, -4);
-        let d = i32x4(-2, -4, -6, -8);
+        let a = I32::<4>([1, 2, 3, 4]);
+        let b = I32::<4>([2, 4, 6, 8]);
+        let c = I32::<4>([-1, -2, -3, -4]);
+        let d = I32::<4>([-2, -4, -6, -8]);
 
-        let max = i32x4(MAX, MAX, MAX, MAX);
-        let max1 = i32x4(MAX - 1, MAX - 1, MAX - 1, MAX - 1);
-        let min = i32x4(MIN, MIN, MIN, MIN);
-        let min1 = i32x4(MIN + 1, MIN + 1, MIN + 1, MIN + 1);
+        let max = I32::<4>([MAX, MAX, MAX, MAX]);
+        let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]);
+        let min = I32::<4>([MIN, MIN, MIN, MIN]);
+        let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]);
 
-        let z = i32x4(0, 0, 0, 0);
+        let z = I32::<4>([0, 0, 0, 0]);
 
         unsafe {
-            assert_eq!(simd_saturating_add(z, z), z);
-            assert_eq!(simd_saturating_add(z, a), a);
-            assert_eq!(simd_saturating_add(b, z), b);
-            assert_eq!(simd_saturating_add(a, a), b);
-            assert_eq!(simd_saturating_add(a, max), max);
-            assert_eq!(simd_saturating_add(max, b), max);
-            assert_eq!(simd_saturating_add(max1, a), max);
-            assert_eq!(simd_saturating_add(min1, z), min1);
-            assert_eq!(simd_saturating_add(min, z), min);
-            assert_eq!(simd_saturating_add(min1, c), min);
-            assert_eq!(simd_saturating_add(min, c), min);
-            assert_eq!(simd_saturating_add(min1, d), min);
-            assert_eq!(simd_saturating_add(min, d), min);
+            assert_eq!(simd_saturating_add(z, z).0, z.0);
+            assert_eq!(simd_saturating_add(z, a).0, a.0);
+            assert_eq!(simd_saturating_add(b, z).0, b.0);
+            assert_eq!(simd_saturating_add(a, a).0, b.0);
+            assert_eq!(simd_saturating_add(a, max).0, max.0);
+            assert_eq!(simd_saturating_add(max, b).0, max.0);
+            assert_eq!(simd_saturating_add(max1, a).0, max.0);
+            assert_eq!(simd_saturating_add(min1, z).0, min1.0);
+            assert_eq!(simd_saturating_add(min, z).0, min.0);
+            assert_eq!(simd_saturating_add(min1, c).0, min.0);
+            assert_eq!(simd_saturating_add(min, c).0, min.0);
+            assert_eq!(simd_saturating_add(min1, d).0, min.0);
+            assert_eq!(simd_saturating_add(min, d).0, min.0);
 
-            assert_eq!(simd_saturating_sub(b, z), b);
-            assert_eq!(simd_saturating_sub(b, a), a);
-            assert_eq!(simd_saturating_sub(a, a), z);
-            assert_eq!(simd_saturating_sub(a, b), c);
-            assert_eq!(simd_saturating_sub(z, max), min1);
-            assert_eq!(simd_saturating_sub(min1, z), min1);
-            assert_eq!(simd_saturating_sub(min1, a), min);
-            assert_eq!(simd_saturating_sub(min1, b), min);
+            assert_eq!(simd_saturating_sub(b, z).0, b.0);
+            assert_eq!(simd_saturating_sub(b, a).0, a.0);
+            assert_eq!(simd_saturating_sub(a, a).0, z.0);
+            assert_eq!(simd_saturating_sub(a, b).0, c.0);
+            assert_eq!(simd_saturating_sub(z, max).0, min1.0);
+            assert_eq!(simd_saturating_sub(min1, z).0, min1.0);
+            assert_eq!(simd_saturating_sub(min1, a).0, min.0);
+            assert_eq!(simd_saturating_sub(min1, b).0, min.0);
         }
     }
 }
diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs
index b67c0ad1eb2..5b0ff88432e 100644
--- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs
+++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs
@@ -3,7 +3,7 @@
 
 // ignore-emscripten FIXME(#45351) hits an LLVM assert
 
-#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
@@ -11,7 +11,7 @@ struct i32x4(pub i32, pub i32, pub i32, pub i32);
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
-struct u32x4(pub u32, pub u32, pub u32, pub u32);
+struct U32<const N: usize>([u32; N]);
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
@@ -25,6 +25,15 @@ macro_rules! all_eq {
     }}
 }
 
+macro_rules! all_eq_ {
+    ($a: expr, $b: expr) => {{
+        let a = $a;
+        let b = $b;
+        assert!(a.0 == b.0);
+    }}
+}
+
+
 extern "platform-intrinsic" {
     fn simd_add<T>(x: T, y: T) -> T;
     fn simd_sub<T>(x: T, y: T) -> T;
@@ -40,81 +49,81 @@ extern "platform-intrinsic" {
 
 fn main() {
     let x1 = i32x4(1, 2, 3, 4);
-    let y1 = u32x4(1, 2, 3, 4);
+    let y1 = U32::<4>([1, 2, 3, 4]);
     let z1 = f32x4(1.0, 2.0, 3.0, 4.0);
     let x2 = i32x4(2, 3, 4, 5);
-    let y2 = u32x4(2, 3, 4, 5);
+    let y2 = U32::<4>([2, 3, 4, 5]);
     let z2 = f32x4(2.0, 3.0, 4.0, 5.0);
 
     unsafe {
         all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9));
         all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9));
-        all_eq!(simd_add(y1, y2), u32x4(3, 5, 7, 9));
-        all_eq!(simd_add(y2, y1), u32x4(3, 5, 7, 9));
+        all_eq_!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9]));
+        all_eq_!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9]));
         all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0));
         all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0));
 
         all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20));
         all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20));
-        all_eq!(simd_mul(y1, y2), u32x4(2, 6, 12, 20));
-        all_eq!(simd_mul(y2, y1), u32x4(2, 6, 12, 20));
+        all_eq_!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20]));
+        all_eq_!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20]));
         all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0));
         all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0));
 
         all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1));
         all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1));
-        all_eq!(simd_sub(y2, y1), u32x4(1, 1, 1, 1));
-        all_eq!(simd_sub(y1, y2), u32x4(!0, !0, !0, !0));
+        all_eq_!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1]));
+        all_eq_!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0]));
         all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0));
         all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0));
 
         all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1));
         all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1);
-        all_eq!(simd_div(y1, y1), u32x4(1, 1, 1, 1));
-        all_eq!(simd_div(u32x4(2, 4, 6, 8), u32x4(2, 2, 2, 2)), y1);
+        all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1]));
+        all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1);
         all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0));
         all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0));
         all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0));
 
         all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0));
         all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1));
-        all_eq!(simd_rem(y1, y1), u32x4(0, 0, 0, 0));
-        all_eq!(simd_rem(y2, y1), u32x4(0, 1, 1, 1));
+        all_eq_!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0]));
+        all_eq_!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1]));
         all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0));
         all_eq!(simd_rem(z1, z2), z1);
         all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0));
 
         all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5));
         all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4));
-        all_eq!(simd_shl(y1, y2), u32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5));
-        all_eq!(simd_shl(y2, y1), u32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4));
+        all_eq_!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5]));
+        all_eq_!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4]));
 
         // test right-shift by assuming left-shift is correct
         all_eq!(simd_shr(simd_shl(x1, x2), x2), x1);
         all_eq!(simd_shr(simd_shl(x2, x1), x1), x2);
-        all_eq!(simd_shr(simd_shl(y1, y2), y2), y1);
-        all_eq!(simd_shr(simd_shl(y2, y1), y1), y2);
+        all_eq_!(simd_shr(simd_shl(y1, y2), y2), y1);
+        all_eq_!(simd_shr(simd_shl(y2, y1), y1), y2);
 
         // ensure we get logical vs. arithmetic shifts correct
         let (a, b, c, d) = (-12, -123, -1234, -12345);
         all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4));
-        all_eq!(simd_shr(u32x4(a as u32, b as u32, c as u32, d as u32), y1),
-                u32x4((a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4));
+        all_eq_!(simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1),
+                U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4]));
 
         all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4));
         all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4));
-        all_eq!(simd_and(y1, y2), u32x4(0, 2, 0, 4));
-        all_eq!(simd_and(y2, y1), u32x4(0, 2, 0, 4));
+        all_eq_!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4]));
+        all_eq_!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4]));
 
         all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5));
         all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5));
-        all_eq!(simd_or(y1, y2), u32x4(3, 3, 7, 5));
-        all_eq!(simd_or(y2, y1), u32x4(3, 3, 7, 5));
+        all_eq_!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5]));
+        all_eq_!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5]));
 
         all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1));
         all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1));
-        all_eq!(simd_xor(y1, y2), u32x4(3, 1, 7, 1));
-        all_eq!(simd_xor(y2, y1), u32x4(3, 1, 7, 1));
+        all_eq_!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1]));
+        all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1]));
 
     }
 }