about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs47
-rw-r--r--src/test/ui/simd/intrinsic/generic-bitmask.rs10
-rw-r--r--src/test/ui/simd/intrinsic/generic-bitmask.stderr10
-rw-r--r--src/test/ui/simd/simd-bitmask.rs28
4 files changed, 73 insertions, 22 deletions
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e63fb22829a..246c94968a3 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, symbol::kw, Span, Symbol};
-use rustc_target::abi::{self, HasDataLayout, Primitive};
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive};
 use rustc_target::spec::{HasTargetSpec, PanicStrategy};
 
 use std::cmp::Ordering;
@@ -1056,16 +1056,13 @@ fn generic_simd_intrinsic(
 
     if name == sym::simd_bitmask {
         // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
-        // vector mask and returns an unsigned integer containing the most
-        // significant bit (MSB) of each lane.
-
-        // If the vector has less than 8 lanes, a u8 is returned with zeroed
-        // trailing bits.
+        // vector mask and returns the most significant bit (MSB) of each lane in the form
+        // of either:
+        // * an unsigned integer
+        // * an array of `u8`
+        // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
         let expected_int_bits = in_len.max(8);
-        match ret_ty.kind() {
-            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (),
-            _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits),
-        }
+        let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 1) as u64);
 
         // Integer vector <i{in_bitwidth} x in_len>:
         let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
@@ -1095,8 +1092,34 @@ fn generic_simd_intrinsic(
         let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
         // Bitcast <i1 x N> to iN:
         let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
-        // Zero-extend iN to the bitmask type:
-        return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+
+        match ret_ty.kind() {
+            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
+                // Zero-extend iN to the bitmask type:
+                return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+            }
+            ty::Array(elem, len)
+                if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+                    && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+                        == Some(expected_bytes) =>
+            {
+                // Zero-extend iN to the array lengh:
+                let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
+
+                // Convert the integer to a byte array
+                let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
+                bx.store(ze, ptr, Align::ONE);
+                let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
+                let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
+                return Ok(bx.load(array_ty, ptr, Align::ONE));
+            }
+            _ => return_error!(
+                "cannot return `{}`, expected `u{}` or `[u8; {}]`",
+                ret_ty,
+                expected_int_bits,
+                expected_bytes
+            ),
+        }
     }
 
     fn simd_simple_float_intrinsic(
diff --git a/src/test/ui/simd/intrinsic/generic-bitmask.rs b/src/test/ui/simd/intrinsic/generic-bitmask.rs
index 92c4e67dfdd..9a23dae77b9 100644
--- a/src/test/ui/simd/intrinsic/generic-bitmask.rs
+++ b/src/test/ui/simd/intrinsic/generic-bitmask.rs
@@ -51,19 +51,19 @@ fn main() {
         let _: u64 = simd_bitmask(m64);
 
         let _: u16 = simd_bitmask(m2);
-        //~^ ERROR bitmask `u16`, expected `u8`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u16 = simd_bitmask(m8);
-        //~^ ERROR bitmask `u16`, expected `u8`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u32 = simd_bitmask(m16);
-        //~^ ERROR bitmask `u32`, expected `u16`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u64 = simd_bitmask(m32);
-        //~^ ERROR bitmask `u64`, expected `u32`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u128 = simd_bitmask(m64);
-        //~^ ERROR bitmask `u128`, expected `u64`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
    }
 }
diff --git a/src/test/ui/simd/intrinsic/generic-bitmask.stderr b/src/test/ui/simd/intrinsic/generic-bitmask.stderr
index 5aaae68cafb..0de3f8eead8 100644
--- a/src/test/ui/simd/intrinsic/generic-bitmask.stderr
+++ b/src/test/ui/simd/intrinsic/generic-bitmask.stderr
@@ -1,28 +1,28 @@
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]`
   --> $DIR/generic-bitmask.rs:53:22
    |
 LL |         let _: u16 = simd_bitmask(m2);
    |                      ^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]`
   --> $DIR/generic-bitmask.rs:56:22
    |
 LL |         let _: u16 = simd_bitmask(m8);
    |                      ^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u32`, expected `u16`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u32`, expected `u16` or `[u8; 2]`
   --> $DIR/generic-bitmask.rs:59:22
    |
 LL |         let _: u32 = simd_bitmask(m16);
    |                      ^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u64`, expected `u32`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u64`, expected `u32` or `[u8; 4]`
   --> $DIR/generic-bitmask.rs:62:22
    |
 LL |         let _: u64 = simd_bitmask(m32);
    |                      ^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u128`, expected `u64`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u128`, expected `u64` or `[u8; 8]`
   --> $DIR/generic-bitmask.rs:65:23
    |
 LL |         let _: u128 = simd_bitmask(m64);
diff --git a/src/test/ui/simd/simd-bitmask.rs b/src/test/ui/simd/simd-bitmask.rs
new file mode 100644
index 00000000000..5ee539e5d8d
--- /dev/null
+++ b/src/test/ui/simd/simd-bitmask.rs
@@ -0,0 +1,28 @@
+//run-pass
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_bitmask<T, U>(v: T) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct Simd<T, const N: usize>([T; N]);
+
+fn main() {
+    unsafe {
+        let v = Simd::<i8, 4>([-1, 0, -1, 0]);
+        let i: u8 = simd_bitmask(v);
+        let a: [u8; 1] = simd_bitmask(v);
+
+        assert_eq!(i, 0b0101);
+        assert_eq!(a, [0b0101]);
+
+        let v = Simd::<i8, 16>([0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0]);
+        let i: u16 = simd_bitmask(v);
+        let a: [u8; 2] = simd_bitmask(v);
+
+        assert_eq!(i, 0b0101000000001100);
+        assert_eq!(a, [0b1100, 0b01010000]);
+    }
+}