Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b6d0eec
Wrap bitshifts in ops.rs
workingjubilee Dec 9, 2021
8aef340
Refactor bitops with `#[must_use]`
workingjubilee Dec 9, 2021
049e8ca
Refactor float arith with `#[must_use]`
workingjubilee Dec 9, 2021
5dcd397
Finish refactoring ints in ops.rs
workingjubilee Dec 9, 2021
bc326a2
Refactor ops.rs with a recursive macro
workingjubilee Dec 22, 2021
a424205
Use Mask::any in div check
workingjubilee Dec 24, 2021
4bbef26
Merge portable-simd#210 - ./wrap-shifts
workingjubilee Dec 30, 2021
ecc00ef
impl std::simd::StdFloat
workingjubilee Dec 21, 2021
af26e3b
Tear down and rewrite support for float testing
workingjubilee Dec 21, 2021
09fa72a
Merge portable-simd#219 - ./std-float
workingjubilee Dec 31, 2021
65cb2c9
Fix mask alias
calebzulawski Jan 9, 2022
138b9cf
Use intrinsic for min/max
calebzulawski Jan 13, 2022
41db153
Merge pull request #224 from rust-lang/feature/min-max-intrinsic
calebzulawski Jan 14, 2022
a4f5f01
Use intrinsics for Mask::{to,from}_array
workingjubilee Nov 13, 2021
56566d8
Annotate signed type in int_divrem_guard
workingjubilee Jan 20, 2022
4fc62c2
fix documentation typo
AlecGoncharow Jan 23, 2022
36cca22
Update crates/core_simd/src/vector/float.rs
calebzulawski Jan 25, 2022
cad7434
Merge pull request #231 from AlecGoncharow/patch-1
calebzulawski Jan 25, 2022
a991d48
Add Simd::cast
workingjubilee Jan 27, 2022
0031b02
Add core_simd/tests/cast.rs
workingjubilee Jan 27, 2022
7072c22
Merge portable-simd#232 - ./feat/typecast
workingjubilee Jan 27, 2022
03f6fbb
Omit Simd::cast during bootstrap
workingjubilee Jan 27, 2022
cde7bdc
Sync rust-lang/portable-simd@03f6fbb21e6050da2a05b3ce8f480c020b384916
workingjubilee Jan 27, 2022
e96159e
pub use std::simd::StdFloat;
workingjubilee Jan 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Finish refactoring ints in ops.rs
This should perform a SIMD check for whether or not we can div/rem,
so that we can panic several times faster!
  • Loading branch information
workingjubilee committed Dec 9, 2021
commit 5dcd397f47a17aec3b049af2d7541530b859e47b
271 changes: 147 additions & 124 deletions crates/core_simd/src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
use core::ops::{Add, Mul};
use core::ops::{BitAnd, BitOr, BitXor};
use core::ops::{Div, Rem, Sub};
Expand Down Expand Up @@ -284,145 +283,169 @@ float_arith! {
}
}

/// Automatically implements operators over references in addition to the provided operator.
macro_rules! impl_ref_ops {
// binary op
{
impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
where
LaneCount<$lanes2:ident>: SupportedLaneCount,
{
type Output = $output:ty;

$(#[$attrs:meta])*
fn $fn:ident($self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) -> Self::Output $body:tt
// Division by zero is poison, according to LLVM.
// So is dividing the MIN value of a signed integer by -1,
// since that would return MAX + 1.
// FIXME: Rust allows <SInt>::MIN / -1,
// so we should probably figure out how to make that safe.
macro_rules! int_divrem_guard {
($(impl<const LANES: usize> $op:ident for Simd<$sint:ty, LANES> {
const PANIC_ZERO: &'static str = $zero:literal;
const PANIC_OVERFLOW: &'static str = $overflow:literal;
fn $call:ident {
unsafe { $simd_call:ident }
}
} => {
impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
})*) => {
$(impl<const LANES: usize> $op for Simd<$sint, LANES>
where
LaneCount<$lanes2>: SupportedLaneCount,
$sint: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = $output;

$(#[$attrs])*
fn $fn($self_tok, $rhs_arg: $rhs_arg_ty) -> Self::Output $body
}
type Output = Self;
#[inline]
#[must_use = "operator returns a new vector without mutating the inputs"]
fn $call(self, rhs: Self) -> Self::Output {
if rhs.lanes_eq(Simd::splat(0)).any() {
panic!("attempt to calculate the remainder with a divisor of zero");
} else if <$sint>::MIN != 0 && self.lanes_eq(Simd::splat(<$sint>::MIN)) & rhs.lanes_eq(Simd::splat(-1 as _))
!= Mask::splat(false)
{
panic!("attempt to calculate the remainder with overflow");
} else {
unsafe { $crate::intrinsics::$simd_call(self, rhs) }
}
}
})*
};
}

/// Automatically implements operators over vectors and scalars for a particular vector.
macro_rules! impl_op {
{ impl Add for $scalar:ty } => {
impl_op! { @binary $scalar, Add::add, simd_add }
};
{ impl Sub for $scalar:ty } => {
impl_op! { @binary $scalar, Sub::sub, simd_sub }
};
{ impl Mul for $scalar:ty } => {
impl_op! { @binary $scalar, Mul::mul, simd_mul }
};
{ impl Div for $scalar:ty } => {
impl_op! { @binary $scalar, Div::div, simd_div }
};
{ impl Rem for $scalar:ty } => {
impl_op! { @binary $scalar, Rem::rem, simd_rem }
};
macro_rules! int_arith {
($(impl<const LANES: usize> IntArith for Simd<$sint:ty, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
})*) => {
$(
unsafe_base_op!{
impl<const LANES: usize> Add for Simd<$sint, LANES> {
fn add(self, rhs: Self) -> Self::Output {
unsafe { simd_add }
}
}

// generic binary op with assignment when output is `Self`
{ @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $intrinsic:ident } => {
impl_ref_ops! {
impl<const LANES: usize> core::ops::$trait<Self> for Simd<$scalar, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
impl<const LANES: usize> Mul for Simd<$sint, LANES> {
fn mul(self, rhs: Self) -> Self::Output {
unsafe { simd_mul }
}
}

#[inline]
fn $trait_fn(self, rhs: Self) -> Self::Output {
unsafe {
intrinsics::$intrinsic(self, rhs)
}
impl<const LANES: usize> Sub for Simd<$sint, LANES> {
fn sub(self, rhs: Self) -> Self::Output {
unsafe { simd_sub }
}
}
}
};
}

/// Implements unsigned integer operators for the provided types.
macro_rules! impl_unsigned_int_ops {
{ $($scalar:ty),* } => {
$(
impl_op! { impl Add for $scalar }
impl_op! { impl Sub for $scalar }
impl_op! { impl Mul for $scalar }

// Integers panic on divide by 0
impl_ref_ops! {
impl<const LANES: usize> core::ops::Div<Self> for Simd<$scalar, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;

#[inline]
fn div(self, rhs: Self) -> Self::Output {
if rhs.as_array()
.iter()
.any(|x| *x == 0)
{
panic!("attempt to divide by zero");
}

// Guards for div(MIN, -1),
// this check only applies to signed ints
if <$scalar>::MIN != 0 && self.as_array().iter()
.zip(rhs.as_array().iter())
.any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
panic!("attempt to divide with overflow");
}
unsafe { intrinsics::simd_div(self, rhs) }
}
int_divrem_guard!{
impl<const LANES: usize> Div for Simd<$sint, LANES> {
const PANIC_ZERO: &'static str = "attempt to divide by zero";
const PANIC_OVERFLOW: &'static str = "attempt to divide with overflow";
fn div {
unsafe { simd_div }
}
}

// remainder panics on zero divisor
impl_ref_ops! {
impl<const LANES: usize> core::ops::Rem<Self> for Simd<$scalar, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;

#[inline]
fn rem(self, rhs: Self) -> Self::Output {
if rhs.as_array()
.iter()
.any(|x| *x == 0)
{
panic!("attempt to calculate the remainder with a divisor of zero");
}

// Guards for rem(MIN, -1)
// this branch applies the check only to signed ints
if <$scalar>::MIN != 0 && self.as_array().iter()
.zip(rhs.as_array().iter())
.any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
panic!("attempt to calculate the remainder with overflow");
}
unsafe { intrinsics::simd_rem(self, rhs) }
}
impl<const LANES: usize> Rem for Simd<$sint, LANES> {
const PANIC_ZERO: &'static str = "attempt to calculate the remainder with a divisor of zero";
const PANIC_OVERFLOW: &'static str = "attempt to calculate the remainder with overflow";
fn rem {
unsafe { simd_rem }
}
}
)*
};
})*
}
}

/// Implements unsigned integer operators for the provided types.
macro_rules! impl_signed_int_ops {
{ $($scalar:ty),* } => {
impl_unsigned_int_ops! { $($scalar),* }
};
}
int_arith! {
impl<const LANES: usize> IntArith for Simd<i8, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl_unsigned_int_ops! { u8, u16, u32, u64, usize }
impl_signed_int_ops! { i8, i16, i32, i64, isize }
impl<const LANES: usize> IntArith for Simd<i16, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<i32, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<i64, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<isize, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<u8, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<u16, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<u32, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<u64, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}

impl<const LANES: usize> IntArith for Simd<usize, LANES> {
fn add(self, rhs: Self) -> Self::Output;
fn mul(self, rhs: Self) -> Self::Output;
fn sub(self, rhs: Self) -> Self::Output;
fn div(self, rhs: Self) -> Self::Output;
fn rem(self, rhs: Self) -> Self::Output;
}
}