Skip to content

Commit

Permalink
Add abs_diff function to SimdInt and SimdUint traits
Browse files Browse the repository at this point in the history
Implement `abs_diff` for signed and unsigned integer vectors
Add tests for testing all `i8`s and `u8`s against the scalar `abs_diff`
  • Loading branch information
okaneco committed Aug 25, 2024
1 parent 283acf4 commit ba197ea
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 3 deletions.
27 changes: 25 additions & 2 deletions crates/core_simd/src/simd/num/int.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::sealed::Sealed;
use crate::simd::{
cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
SupportedLaneCount,
};

Expand Down Expand Up @@ -70,11 +70,27 @@ pub trait SimdInt: Copy + Sealed {
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
/// # use simd::prelude::*;
/// use core::i32::{MIN, MAX};
/// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
/// let xs = Simd::from_array([MIN, MIN + 1, -5, 0]);
/// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
/// ```
fn abs(self) -> Self;

/// Lanewise absolute difference.
/// Every element becomes the absolute difference of `self` and `second`.
///
/// # Examples
/// ```
/// # #![feature(portable_simd)]
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
/// # use simd::prelude::*;
/// use core::i32::{MIN, MAX};
/// let a = Simd::from_array([MIN, MAX, 100, -100]);
/// let b = Simd::from_array([MAX, MIN, -80, -120]);
/// assert_eq!(a.abs_diff(b), Simd::from_array([u32::MAX, u32::MAX, 180, 20]));
/// ```
fn abs_diff(self, second: Self) -> Self::Unsigned;

/// Lanewise saturating absolute value, implemented in Rust.
/// As abs(), except the MIN value becomes MAX instead of itself.
///
Expand Down Expand Up @@ -259,6 +275,13 @@ macro_rules! impl_trait {
(self^m) - m
}

#[inline]
fn abs_diff(self, second: Self) -> Self::Unsigned {
let max = self.simd_max(second);
let min = self.simd_min(second);
(max - min).cast()
}

#[inline]
fn saturating_abs(self) -> Self {
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
Expand Down
25 changes: 24 additions & 1 deletion crates/core_simd/src/simd/num/uint.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::sealed::Sealed;
use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
use crate::simd::{cmp::SimdOrd, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};

/// Operations on SIMD vectors of unsigned integers.
pub trait SimdUint: Copy + Sealed {
Expand Down Expand Up @@ -57,6 +57,22 @@ pub trait SimdUint: Copy + Sealed {
/// assert_eq!(sat, Simd::splat(0));
fn saturating_sub(self, second: Self) -> Self;

/// Lanewise absolute difference.
/// Every element becomes the absolute difference of `self` and `second`.
///
/// # Examples
/// ```
/// # #![feature(portable_simd)]
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
/// # use simd::prelude::*;
/// use core::u32::MAX;
/// let a = Simd::from_array([0, MAX, 100, 20]);
/// let b = Simd::from_array([MAX, 0, 80, 200]);
/// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
/// ```
fn abs_diff(self, second: Self) -> Self;

/// Returns the sum of the elements of the vector, with wrapping addition.
fn reduce_sum(self) -> Self::Scalar;

Expand Down Expand Up @@ -138,6 +154,13 @@ macro_rules! impl_trait {
unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
}

#[inline]
fn abs_diff(self, second: Self) -> Self {
let max = self.simd_max(second);
let min = self.simd_min(second);
max - min
}

#[inline]
fn reduce_sum(self) -> Self::Scalar {
// Safety: `self` is an integer vector
Expand Down
33 changes: 33 additions & 0 deletions crates/core_simd/tests/abs_diff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#![feature(portable_simd)]

use core_simd::simd::Simd;

const LANES: usize = 16;

#[test]
fn abs_diff_i8() {
use core_simd::simd::num::SimdInt;

for x in i8::MIN..=i8::MAX {
for y in i8::MIN..=i8::MAX {
let left: Simd<u8, LANES> = Simd::splat(x.abs_diff(y));
let right = Simd::splat(x).abs_diff(Simd::splat(y));

assert_eq!(left, right);
}
}
}

#[test]
fn abs_diff_u8() {
use core_simd::simd::num::SimdUint;

for x in u8::MIN..=u8::MAX {
for y in u8::MIN..=u8::MAX {
let left: Simd<u8, LANES> = Simd::splat(x.abs_diff(y));
let right = Simd::splat(x).abs_diff(Simd::splat(y));

assert_eq!(left, right);
}
}
}

0 comments on commit ba197ea

Please sign in to comment.