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::{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 @@ macro_rules! require_simd { 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 : let (i_xn, in_elem_bitwidth) = match in_elem.kind() { @@ -1095,8 +1092,34 @@ macro_rules! require_simd { let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len)); // Bitcast 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(v: T) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct Simd([T; N]); + +fn main() { + unsafe { + let v = Simd::([-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::([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]); + } +}