Begin reducing mask API

This commit is contained in:
Caleb Zulawski 2021-04-18 19:26:07 +00:00
parent 5751179dc6
commit da42aa5403
8 changed files with 59 additions and 341 deletions

View file

@ -1,7 +1,7 @@
use crate::LanesAtMost32;
macro_rules! implement_mask_ops {
{ $($vector:ident => $mask:ident ($inner_mask_ty:ident, $inner_ty:ident),)* } => {
{ $($vector:ident => $mask:ident ($inner_ty:ident),)* } => {
$(
impl<const LANES: usize> crate::$vector<LANES>
where
@ -12,8 +12,7 @@ macro_rules! implement_mask_ops {
#[inline]
pub fn lanes_eq(self, other: Self) -> crate::$mask<LANES> {
unsafe {
crate::$inner_mask_ty::from_int_unchecked(crate::intrinsics::simd_eq(self, other))
.into()
crate::$mask::from_int_unchecked(crate::intrinsics::simd_eq(self, other))
}
}
@ -21,8 +20,7 @@ macro_rules! implement_mask_ops {
#[inline]
pub fn lanes_ne(self, other: Self) -> crate::$mask<LANES> {
unsafe {
crate::$inner_mask_ty::from_int_unchecked(crate::intrinsics::simd_ne(self, other))
.into()
crate::$mask::from_int_unchecked(crate::intrinsics::simd_ne(self, other))
}
}
@ -30,8 +28,7 @@ macro_rules! implement_mask_ops {
#[inline]
pub fn lanes_lt(self, other: Self) -> crate::$mask<LANES> {
unsafe {
crate::$inner_mask_ty::from_int_unchecked(crate::intrinsics::simd_lt(self, other))
.into()
crate::$mask::from_int_unchecked(crate::intrinsics::simd_lt(self, other))
}
}
@ -39,8 +36,7 @@ macro_rules! implement_mask_ops {
#[inline]
pub fn lanes_gt(self, other: Self) -> crate::$mask<LANES> {
unsafe {
crate::$inner_mask_ty::from_int_unchecked(crate::intrinsics::simd_gt(self, other))
.into()
crate::$mask::from_int_unchecked(crate::intrinsics::simd_gt(self, other))
}
}
@ -48,8 +44,7 @@ macro_rules! implement_mask_ops {
#[inline]
pub fn lanes_le(self, other: Self) -> crate::$mask<LANES> {
unsafe {
crate::$inner_mask_ty::from_int_unchecked(crate::intrinsics::simd_le(self, other))
.into()
crate::$mask::from_int_unchecked(crate::intrinsics::simd_le(self, other))
}
}
@ -57,8 +52,7 @@ macro_rules! implement_mask_ops {
#[inline]
pub fn lanes_ge(self, other: Self) -> crate::$mask<LANES> {
unsafe {
crate::$inner_mask_ty::from_int_unchecked(crate::intrinsics::simd_ge(self, other))
.into()
crate::$mask::from_int_unchecked(crate::intrinsics::simd_ge(self, other))
}
}
}
@ -67,18 +61,18 @@ macro_rules! implement_mask_ops {
}
implement_mask_ops! {
SimdI8 => Mask8 (SimdMask8, SimdI8),
SimdI16 => Mask16 (SimdMask16, SimdI16),
SimdI32 => Mask32 (SimdMask32, SimdI32),
SimdI64 => Mask64 (SimdMask64, SimdI64),
SimdIsize => MaskSize (SimdMaskSize, SimdIsize),
SimdI8 => Mask8 (SimdI8),
SimdI16 => Mask16 (SimdI16),
SimdI32 => Mask32 (SimdI32),
SimdI64 => Mask64 (SimdI64),
SimdIsize => MaskSize (SimdIsize),
SimdU8 => Mask8 (SimdMask8, SimdI8),
SimdU16 => Mask16 (SimdMask16, SimdI16),
SimdU32 => Mask32 (SimdMask32, SimdI32),
SimdU64 => Mask64 (SimdMask64, SimdI64),
SimdUsize => MaskSize (SimdMaskSize, SimdIsize),
SimdU8 => Mask8 (SimdI8),
SimdU16 => Mask16 (SimdI16),
SimdU32 => Mask32 (SimdI32),
SimdU64 => Mask64 (SimdI64),
SimdUsize => MaskSize (SimdIsize),
SimdF32 => Mask32 (SimdMask32, SimdI32),
SimdF64 => Mask64 (SimdMask64, SimdI64),
SimdF32 => Mask32 (SimdI32),
SimdF64 => Mask64 (SimdI64),
}

View file

@ -1,4 +1,4 @@
/// Implemented for bitmask sizes that are supported by the implementation.
/// Implemented for vectors that are supported by the implementation.
pub trait LanesAtMost32 {}
macro_rules! impl_for {
@ -28,5 +28,3 @@ impl_for! { SimdIsize }
impl_for! { SimdF32 }
impl_for! { SimdF64 }
impl_for! { BitMask }

View file

@ -4,14 +4,12 @@ use crate::LanesAtMost32;
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
#[repr(transparent)]
pub struct BitMask<const LANES: usize>(u64)
where
BitMask<LANES>: LanesAtMost32;
impl<const LANES: usize> BitMask<LANES>
where
Self: LanesAtMost32,
{
/// Construct a mask by setting all lanes to the given value.
#[inline]
pub fn splat(value: bool) -> Self {
if value {
Self(u64::MAX >> (64 - LANES))
@ -20,23 +18,13 @@ where
}
}
/// Tests the value of the specified lane.
///
/// # Panics
/// Panics if `lane` is greater than or equal to the number of lanes in the vector.
#[inline]
pub fn test(&self, lane: usize) -> bool {
assert!(lane < LANES, "lane index out of range");
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
(self.0 >> lane) & 0x1 > 0
}
/// Sets the value of the specified lane.
///
/// # Panics
/// Panics if `lane` is greater than or equal to the number of lanes in the vector.
#[inline]
pub fn set(&mut self, lane: usize, value: bool) {
assert!(lane < LANES, "lane index out of range");
pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
self.0 ^= ((value ^ self.test(lane)) as u64) << lane
}
}

View file

@ -1,18 +1,5 @@
//! Masks that take up full SIMD vector registers.
/// The error type returned when converting an integer to a mask fails.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromMaskError(());
impl core::fmt::Display for TryFromMaskError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"mask vector must have all bits set or unset in each lane"
)
}
}
macro_rules! define_mask {
{
$(#[$attr:meta])*
@ -27,6 +14,8 @@ macro_rules! define_mask {
where
crate::$type<LANES>: crate::LanesAtMost32;
impl_full_mask_reductions! { $name, $type }
impl<const LANES: usize> Copy for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -46,7 +35,6 @@ macro_rules! define_mask {
where
crate::$type<LANES>: crate::LanesAtMost32,
{
/// Construct a mask by setting all lanes to the given value.
pub fn splat(value: bool) -> Self {
Self(<crate::$type<LANES>>::splat(
if value {
@ -57,20 +45,12 @@ macro_rules! define_mask {
))
}
/// Tests the value of the specified lane.
///
/// # Panics
/// Panics if `lane` is greater than or equal to the number of lanes in the vector.
#[inline]
pub fn test(&self, lane: usize) -> bool {
assert!(lane < LANES, "lane index out of range");
self.0[lane] == -1
}
/// Sets the value of the specified lane.
///
/// # Panics
/// Panics if `lane` is greater than or equal to the number of lanes in the vector.
#[inline]
pub fn set(&mut self, lane: usize, value: bool) {
assert!(lane < LANES, "lane index out of range");
@ -81,56 +61,15 @@ macro_rules! define_mask {
}
}
/// Converts the mask to the equivalent integer representation, where -1 represents
/// "set" and 0 represents "unset".
#[inline]
pub fn to_int(self) -> crate::$type<LANES> {
self.0
}
/// Creates a mask from the equivalent integer representation, where -1 represents
/// "set" and 0 represents "unset".
///
/// Each provided lane must be either 0 or -1.
#[inline]
pub unsafe fn from_int_unchecked(value: crate::$type<LANES>) -> Self {
Self(value)
}
/// Creates a mask from the equivalent integer representation, where -1 represents
/// "set" and 0 represents "unset".
///
/// # Panics
/// Panics if any lane is not 0 or -1.
#[inline]
pub fn from_int(value: crate::$type<LANES>) -> Self {
use core::convert::TryInto;
value.try_into().unwrap()
}
}
impl<const LANES: usize> core::convert::From<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
fn from(value: bool) -> Self {
Self::splat(value)
}
}
impl<const LANES: usize> core::convert::TryFrom<crate::$type<LANES>> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Error = TryFromMaskError;
fn try_from(value: crate::$type<LANES>) -> Result<Self, Self::Error> {
let valid = (value.lanes_eq(crate::$type::<LANES>::splat(0)) | value.lanes_eq(crate::$type::<LANES>::splat(-1))).all();
if valid {
Ok(Self(value))
} else {
Err(TryFromMaskError(()))
}
}
}
impl<const LANES: usize> core::convert::From<$name<LANES>> for crate::$type<LANES>
@ -142,36 +81,6 @@ macro_rules! define_mask {
}
}
impl<const LANES: usize> core::convert::From<crate::BitMask<LANES>> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
crate::BitMask<LANES>: crate::LanesAtMost32,
{
fn from(value: crate::BitMask<LANES>) -> Self {
// TODO use an intrinsic to do this efficiently (with LLVM's sext instruction)
let mut mask = Self::splat(false);
for lane in 0..LANES {
mask.set(lane, value.test(lane));
}
mask
}
}
impl<const LANES: usize> core::convert::From<$name<LANES>> for crate::BitMask<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
crate::BitMask<LANES>: crate::LanesAtMost32,
{
fn from(value: $name<$lanes>) -> Self {
// TODO use an intrinsic to do this efficiently (with LLVM's trunc instruction)
let mut mask = Self::splat(false);
for lane in 0..LANES {
mask.set(lane, value.test(lane));
}
mask
}
}
impl<const LANES: usize> core::fmt::Debug for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -230,28 +139,6 @@ macro_rules! define_mask {
}
}
impl<const LANES: usize> core::ops::BitAnd<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Output = Self;
#[inline]
fn bitand(self, rhs: bool) -> Self {
self & Self::splat(rhs)
}
}
impl<const LANES: usize> core::ops::BitAnd<$name<LANES>> for bool
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Output = $name<LANES>;
#[inline]
fn bitand(self, rhs: $name<LANES>) -> $name<LANES> {
$name::<LANES>::splat(self) & rhs
}
}
impl<const LANES: usize> core::ops::BitOr for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -263,28 +150,6 @@ macro_rules! define_mask {
}
}
impl<const LANES: usize> core::ops::BitOr<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Output = Self;
#[inline]
fn bitor(self, rhs: bool) -> Self {
self | Self::splat(rhs)
}
}
impl<const LANES: usize> core::ops::BitOr<$name<LANES>> for bool
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Output = $name<LANES>;
#[inline]
fn bitor(self, rhs: $name<LANES>) -> $name<LANES> {
$name::<LANES>::splat(self) | rhs
}
}
impl<const LANES: usize> core::ops::BitXor for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -296,28 +161,6 @@ macro_rules! define_mask {
}
}
impl<const LANES: usize> core::ops::BitXor<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Output = Self;
#[inline]
fn bitxor(self, rhs: bool) -> Self::Output {
self ^ Self::splat(rhs)
}
}
impl<const LANES: usize> core::ops::BitXor<$name<LANES>> for bool
where
crate::$type<LANES>: crate::LanesAtMost32,
{
type Output = $name<LANES>;
#[inline]
fn bitxor(self, rhs: $name<LANES>) -> Self::Output {
$name::<LANES>::splat(self) ^ rhs
}
}
impl<const LANES: usize> core::ops::Not for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -339,16 +182,6 @@ macro_rules! define_mask {
}
}
impl<const LANES: usize> core::ops::BitAndAssign<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
#[inline]
fn bitand_assign(&mut self, rhs: bool) {
*self &= Self::splat(rhs);
}
}
impl<const LANES: usize> core::ops::BitOrAssign for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -359,16 +192,6 @@ macro_rules! define_mask {
}
}
impl<const LANES: usize> core::ops::BitOrAssign<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
#[inline]
fn bitor_assign(&mut self, rhs: bool) {
*self |= Self::splat(rhs);
}
}
impl<const LANES: usize> core::ops::BitXorAssign for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
@ -378,47 +201,35 @@ macro_rules! define_mask {
self.0 ^= rhs.0;
}
}
impl<const LANES: usize> core::ops::BitXorAssign<bool> for $name<LANES>
where
crate::$type<LANES>: crate::LanesAtMost32,
{
#[inline]
fn bitxor_assign(&mut self, rhs: bool) {
*self ^= Self::splat(rhs);
}
}
impl_full_mask_reductions! { $name, $type }
}
}
define_mask! {
/// A mask equivalent to [SimdI8](crate::SimdI8), where all bits in the lane must be either set
/// or unset.
struct SimdMask8<const LANES: usize>(crate::SimdI8<LANES>);
struct Mask8<const LANES: usize>(crate::SimdI8<LANES>);
}
define_mask! {
/// A mask equivalent to [SimdI16](crate::SimdI16), where all bits in the lane must be either set
/// or unset.
struct SimdMask16<const LANES: usize>(crate::SimdI16<LANES>);
struct Mask16<const LANES: usize>(crate::SimdI16<LANES>);
}
define_mask! {
/// A mask equivalent to [SimdI32](crate::SimdI32), where all bits in the lane must be either set
/// or unset.
struct SimdMask32<const LANES: usize>(crate::SimdI32<LANES>);
struct Mask32<const LANES: usize>(crate::SimdI32<LANES>);
}
define_mask! {
/// A mask equivalent to [SimdI64](crate::SimdI64), where all bits in the lane must be either set
/// or unset.
struct SimdMask64<const LANES: usize>(crate::SimdI64<LANES>);
struct Mask64<const LANES: usize>(crate::SimdI64<LANES>);
}
define_mask! {
/// A mask equivalent to [SimdIsize](crate::SimdIsize), where all bits in the lane must be either set
/// or unset.
struct SimdMaskSize<const LANES: usize>(crate::SimdIsize<LANES>);
struct MaskSize<const LANES: usize>(crate::SimdIsize<LANES>);
}

View file

@ -1,25 +1,24 @@
//! Types and traits associated with masking lanes of vectors.
//! Types representing
#![allow(non_camel_case_types)]
mod full_masks;
pub use full_masks::*;
mod bitmask;
pub use bitmask::*;
#[cfg_attr(not(all(target_arch = "x86_64", target_feature = "avx512f")), path = "full_masks.rs")]
#[cfg_attr(all(target_arch = "x86_64", target_feature = "avx512f"), path = "bitmask.rs")]
mod mask_impl;
use crate::{LanesAtMost32, SimdI16, SimdI32, SimdI64, SimdI8, SimdIsize};
macro_rules! define_opaque_mask {
{
$(#[$attr:meta])*
struct $name:ident<const $lanes:ident: usize>($inner_ty:ident<$lanes2:ident>);
struct $name:ident<const $lanes:ident: usize>($inner_ty:ty);
@bits $bits_ty:ident
} => {
$(#[$attr])*
#[allow(non_camel_case_types)]
pub struct $name<const LANES: usize>($inner_ty<LANES>) where $bits_ty<LANES>: LanesAtMost32;
pub struct $name<const LANES: usize>($inner_ty) where $bits_ty<LANES>: LanesAtMost32;
impl_opaque_mask_reductions! { $name, $inner_ty, $bits_ty }
impl_opaque_mask_reductions! { $name, $bits_ty }
impl<const LANES: usize> $name<LANES>
where
@ -27,7 +26,7 @@ macro_rules! define_opaque_mask {
{
/// Construct a mask by setting all lanes to the given value.
pub fn splat(value: bool) -> Self {
Self(<$inner_ty<LANES>>::splat(value))
Self(<$inner_ty>::splat(value))
}
/// Converts an array to a SIMD vector.
@ -52,6 +51,16 @@ macro_rules! define_opaque_mask {
array
}
/// Converts a vector of integers to a mask, where 0 represents `false` and -1
/// represents `true`.
///
/// # Safety
/// All lanes must be either 0 or -1.
#[inline]
pub unsafe fn from_int_unchecked(value: $bits_ty<LANES>) -> Self {
Self(<$inner_ty>::from_int_unchecked(value))
}
/// Tests the value of the specified lane.
///
/// # Panics
@ -71,44 +80,6 @@ macro_rules! define_opaque_mask {
}
}
impl<const LANES: usize> From<BitMask<LANES>> for $name<LANES>
where
$bits_ty<LANES>: LanesAtMost32,
BitMask<LANES>: LanesAtMost32,
{
fn from(value: BitMask<LANES>) -> Self {
Self(value.into())
}
}
impl<const LANES: usize> From<$name<LANES>> for crate::BitMask<LANES>
where
$bits_ty<LANES>: LanesAtMost32,
BitMask<LANES>: LanesAtMost32,
{
fn from(value: $name<LANES>) -> Self {
value.0.into()
}
}
impl<const LANES: usize> From<$inner_ty<LANES>> for $name<LANES>
where
$bits_ty<LANES>: LanesAtMost32,
{
fn from(value: $inner_ty<LANES>) -> Self {
Self(value)
}
}
impl<const LANES: usize> From<$name<LANES>> for $inner_ty<LANES>
where
$bits_ty<LANES>: LanesAtMost32,
{
fn from(value: $name<LANES>) -> Self {
value.0
}
}
// vector/array conversion
impl<const LANES: usize> From<[bool; LANES]> for $name<LANES>
where
@ -130,7 +101,7 @@ macro_rules! define_opaque_mask {
impl<const LANES: usize> Copy for $name<LANES>
where
$inner_ty<LANES>: Copy,
$inner_ty: Copy,
$bits_ty<LANES>: LanesAtMost32,
{}
@ -359,7 +330,7 @@ define_opaque_mask! {
/// Mask for vectors with `LANES` 8-bit elements.
///
/// The layout of this type is unspecified.
struct Mask8<const LANES: usize>(SimdMask8<LANES>);
struct Mask8<const LANES: usize>(mask_impl::Mask8<LANES>);
@bits SimdI8
}
@ -367,7 +338,7 @@ define_opaque_mask! {
/// Mask for vectors with `LANES` 16-bit elements.
///
/// The layout of this type is unspecified.
struct Mask16<const LANES: usize>(SimdMask16<LANES>);
struct Mask16<const LANES: usize>(mask_impl::Mask16<LANES>);
@bits SimdI16
}
@ -375,7 +346,7 @@ define_opaque_mask! {
/// Mask for vectors with `LANES` 32-bit elements.
///
/// The layout of this type is unspecified.
struct Mask32<const LANES: usize>(SimdMask32<LANES>);
struct Mask32<const LANES: usize>(mask_impl::Mask32<LANES>);
@bits SimdI32
}
@ -383,7 +354,7 @@ define_opaque_mask! {
/// Mask for vectors with `LANES` 64-bit elements.
///
/// The layout of this type is unspecified.
struct Mask64<const LANES: usize>(SimdMask64<LANES>);
struct Mask64<const LANES: usize>(mask_impl::Mask64<LANES>);
@bits SimdI64
}
@ -391,7 +362,7 @@ define_opaque_mask! {
/// Mask for vectors with `LANES` pointer-width elements.
///
/// The layout of this type is unspecified.
struct MaskSize<const LANES: usize>(SimdMaskSize<LANES>);
struct MaskSize<const LANES: usize>(mask_impl::MaskSize<LANES>);
@bits SimdIsize
}

View file

@ -103,18 +103,16 @@ macro_rules! impl_float_reductions {
}
macro_rules! impl_full_mask_reductions {
{ $name:ident, $inner:ident } => {
impl<const LANES: usize> crate::$name<LANES>
{ $name:ident, $bits_ty:ident } => {
impl<const LANES: usize> $name<LANES>
where
crate::$inner<LANES>: crate::LanesAtMost32
crate::$bits_ty<LANES>: crate::LanesAtMost32
{
/// Returns true if any lane is set, or false otherwise.
#[inline]
pub fn any(self) -> bool {
unsafe { crate::intrinsics::simd_reduce_any(self.to_int()) }
}
/// Returns true if all lanes are set, or false otherwise.
#[inline]
pub fn all(self) -> bool {
unsafe { crate::intrinsics::simd_reduce_all(self.to_int()) }
@ -124,10 +122,10 @@ macro_rules! impl_full_mask_reductions {
}
macro_rules! impl_opaque_mask_reductions {
{ $name:ident, $inner:ident, $bits_ty:ident } => {
{ $name:ident, $bits_ty:ident } => {
impl<const LANES: usize> $name<LANES>
where
$bits_ty<LANES>: crate::LanesAtMost32
crate::$bits_ty<LANES>: crate::LanesAtMost32
{
/// Returns true if any lane is set, or false otherwise.
#[inline]
@ -143,20 +141,3 @@ macro_rules! impl_opaque_mask_reductions {
}
}
}
impl<const LANES: usize> crate::BitMask<LANES>
where
crate::BitMask<LANES>: crate::LanesAtMost32,
{
/// Returns true if any lane is set, or false otherwise.
#[inline]
pub fn any(self) -> bool {
self != Self::splat(false)
}
/// Returns true if all lanes are set, or false otherwise.
#[inline]
pub fn all(self) -> bool {
self == Self::splat(true)
}
}

View file

@ -1,30 +1,9 @@
use core::convert::TryFrom;
use core_simd::{BitMask, Mask8, SimdI8, SimdMask8};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test_configure!(run_in_browser);
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn mask_format_round_trip() {
let ints = SimdI8::from_array([-1, 0, 0, -1]);
let simd_mask = SimdMask8::try_from(ints).unwrap();
let bitmask = BitMask::from(simd_mask);
let opaque_mask = Mask8::from(bitmask);
let simd_mask_returned = SimdMask8::from(opaque_mask);
let ints_returned = SimdI8::from(simd_mask_returned);
assert_eq!(ints_returned, ints);
}
macro_rules! test_mask_api {
{ $name:ident } => {
#[allow(non_snake_case)]
@ -83,6 +62,4 @@ macro_rules! test_mask_api {
mod mask_api {
test_mask_api! { Mask8 }
test_mask_api! { SimdMask8 }
test_mask_api! { BitMask }
}

View file

@ -281,7 +281,6 @@ macro_rules! test_lanes {
core_simd::SimdIsize<$lanes>: core_simd::LanesAtMost32,
core_simd::SimdF32<$lanes>: core_simd::LanesAtMost32,
core_simd::SimdF64<$lanes>: core_simd::LanesAtMost32,
core_simd::BitMask<$lanes>: core_simd::LanesAtMost32,
$body
#[cfg(target_arch = "wasm32")]
@ -351,7 +350,6 @@ macro_rules! test_lanes_panic {
core_simd::SimdIsize<$lanes>: core_simd::LanesAtMost32,
core_simd::SimdF32<$lanes>: core_simd::LanesAtMost32,
core_simd::SimdF64<$lanes>: core_simd::LanesAtMost32,
core_simd::BitMask<$lanes>: core_simd::LanesAtMost32,
$body
#[test]