Skip to content

Commit

Permalink
#265: Move comparisons to traits
Browse files Browse the repository at this point in the history
A simpler variant of #206.

* Comparisons are moved to `SimdPartialEq`, `SimdPartialOrd`, and `SimdOrd`.  The function names are prefixed with `simd_` to disambiguate from the regular `PartialEq` etc functions.  With the functions on traits instead of `Simd` directly, shadowing the function names doesn't work very well.
* Floating point `Ord`-like functions are put into a `SimdFloat` trait.  The intention is that eventually (some time after this PR) all floating point functions will be moved from `Simd` to `SimdFloat`, and the same goes for future `SimdInt`/`SimdUint` traits.
  • Loading branch information
workingjubilee authored Apr 4, 2022
2 parents c2fbead + 60486e0 commit 1ec010d
Show file tree
Hide file tree
Showing 11 changed files with 412 additions and 230 deletions.
120 changes: 0 additions & 120 deletions crates/core_simd/src/comparisons.rs

This file was deleted.

73 changes: 73 additions & 0 deletions crates/core_simd/src/eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};

/// Parallel `PartialEq`.
pub trait SimdPartialEq {
/// The mask type returned by each comparison.
type Mask;

/// Test if each lane is equal to the corresponding lane in `other`.
#[must_use = "method returns a new mask and does not mutate the original value"]
fn simd_eq(self, other: Self) -> Self::Mask;

/// Test if each lane is equal to the corresponding lane in `other`.
#[must_use = "method returns a new mask and does not mutate the original value"]
fn simd_ne(self, other: Self) -> Self::Mask;
}

macro_rules! impl_number {
{ $($number:ty),* } => {
$(
impl<const LANES: usize> SimdPartialEq for Simd<$number, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Mask<<$number as SimdElement>::Mask, LANES>;

#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
}
}
)*
}
}

impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }

macro_rules! impl_mask {
{ $($integer:ty),* } => {
$(
impl<const LANES: usize> SimdPartialEq for Mask<$integer, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Self;

#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Self::from_int_unchecked(intrinsics::simd_eq(self.to_int(), other.to_int())) }
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Self::from_int_unchecked(intrinsics::simd_ne(self.to_int(), other.to_int())) }
}
}
)*
}
}

impl_mask! { i8, i16, i32, i64, isize }
4 changes: 2 additions & 2 deletions crates/core_simd/src/masks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod mask_impl;
mod to_bitmask;
pub use to_bitmask::ToBitMask;

use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount};
use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount};
use core::cmp::Ordering;
use core::{fmt, mem};

Expand Down Expand Up @@ -56,7 +56,7 @@ macro_rules! impl_element {
where
LaneCount<LANES>: SupportedLaneCount,
{
(value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all()
(value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all()
}

fn eq(self, other: Self) -> bool { self == other }
Expand Down
5 changes: 4 additions & 1 deletion crates/core_simd/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ pub(crate) mod intrinsics;
#[cfg(feature = "generic_const_exprs")]
mod to_bytes;

mod comparisons;
mod eq;
mod fmt;
mod iter;
mod lane_count;
mod masks;
mod math;
mod ops;
mod ord;
mod round;
mod select;
mod vector;
Expand All @@ -25,8 +26,10 @@ mod vendor;
pub mod simd {
pub(crate) use crate::core_simd::intrinsics;

pub use crate::core_simd::eq::*;
pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
pub use crate::core_simd::masks::*;
pub use crate::core_simd::ord::*;
pub use crate::core_simd::swizzle::*;
pub use crate::core_simd::vector::*;
}
10 changes: 5 additions & 5 deletions crates/core_simd/src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
use crate::simd::{LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount};
use core::ops::{Add, Mul};
use core::ops::{BitAnd, BitOr, BitXor};
use core::ops::{Div, Rem, Sub};
Expand Down Expand Up @@ -74,18 +74,18 @@ macro_rules! int_divrem_guard {
$simd_call:ident
},
$int:ident ) => {
if $rhs.lanes_eq(Simd::splat(0)).any() {
if $rhs.simd_eq(Simd::splat(0 as _)).any() {
panic!($zero);
} else {
// Prevent otherwise-UB overflow on the MIN / -1 case.
let rhs = if <$int>::MIN != 0 {
// This should, at worst, optimize to a few branchless logical ops
// Ideally, this entire conditional should evaporate
// Fire LLVM and implement those manually if it doesn't get the hint
($lhs.lanes_eq(Simd::splat(<$int>::MIN))
($lhs.simd_eq(Simd::splat(<$int>::MIN))
// type inference can break here, so cut an SInt to size
& $rhs.lanes_eq(Simd::splat(-1i64 as _)))
.select(Simd::splat(1), $rhs)
& $rhs.simd_eq(Simd::splat(-1i64 as _)))
.select(Simd::splat(1 as _), $rhs)
} else {
// Nice base case to make it easy to const-fold away the other branch.
$rhs
Expand Down
Loading

0 comments on commit 1ec010d

Please sign in to comment.