Skip to content

Commit dd1f800

Browse files
Make the RHS splats parametric
1 parent 7374ff2 commit dd1f800

File tree

2 files changed

+76
-96
lines changed

2 files changed

+76
-96
lines changed

crates/core_simd/src/ops.rs

+1-96
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use core::ops::{Shr, Shl};
77

88
mod assign;
99
mod deref;
10+
mod splat;
1011
mod unary;
1112

1213
impl<I, T, const LANES: usize> core::ops::Index<I> for Simd<T, LANES>
@@ -119,20 +120,6 @@ macro_rules! impl_op {
119120
}
120121
}
121122

122-
impl_ref_ops! {
123-
impl<const LANES: usize> core::ops::$trait<$scalar> for Simd<$scalar, LANES>
124-
where
125-
LaneCount<LANES>: SupportedLaneCount,
126-
{
127-
type Output = Self;
128-
129-
#[inline]
130-
fn $trait_fn(self, rhs: $scalar) -> Self::Output {
131-
core::ops::$trait::$trait_fn(self, Self::splat(rhs))
132-
}
133-
}
134-
}
135-
136123
impl_ref_ops! {
137124
impl<const LANES: usize> core::ops::$trait<Simd<$scalar, LANES>> for $scalar
138125
where
@@ -202,29 +189,6 @@ macro_rules! impl_unsigned_int_ops {
202189
}
203190
}
204191

205-
impl_ref_ops! {
206-
impl<const LANES: usize> core::ops::Div<$scalar> for Simd<$scalar, LANES>
207-
where
208-
LaneCount<LANES>: SupportedLaneCount,
209-
{
210-
type Output = Self;
211-
212-
#[inline]
213-
fn div(self, rhs: $scalar) -> Self::Output {
214-
if rhs == 0 {
215-
panic!("attempt to divide by zero");
216-
}
217-
if <$scalar>::MIN != 0 &&
218-
self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
219-
rhs == -1 as _ {
220-
panic!("attempt to divide with overflow");
221-
}
222-
let rhs = Self::splat(rhs);
223-
unsafe { intrinsics::simd_div(self, rhs) }
224-
}
225-
}
226-
}
227-
228192
impl_ref_ops! {
229193
impl<const LANES: usize> core::ops::Div<Simd<$scalar, LANES>> for $scalar
230194
where
@@ -268,29 +232,6 @@ macro_rules! impl_unsigned_int_ops {
268232
}
269233
}
270234

271-
impl_ref_ops! {
272-
impl<const LANES: usize> core::ops::Rem<$scalar> for Simd<$scalar, LANES>
273-
where
274-
LaneCount<LANES>: SupportedLaneCount,
275-
{
276-
type Output = Self;
277-
278-
#[inline]
279-
fn rem(self, rhs: $scalar) -> Self::Output {
280-
if rhs == 0 {
281-
panic!("attempt to calculate the remainder with a divisor of zero");
282-
}
283-
if <$scalar>::MIN != 0 &&
284-
self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
285-
rhs == -1 as _ {
286-
panic!("attempt to calculate the remainder with overflow");
287-
}
288-
let rhs = Self::splat(rhs);
289-
unsafe { intrinsics::simd_rem(self, rhs) }
290-
}
291-
}
292-
}
293-
294235
impl_ref_ops! {
295236
impl<const LANES: usize> core::ops::Rem<Simd<$scalar, LANES>> for $scalar
296237
where
@@ -328,24 +269,6 @@ macro_rules! impl_unsigned_int_ops {
328269
}
329270
}
330271

331-
impl_ref_ops! {
332-
impl<const LANES: usize> core::ops::Shl<$scalar> for Simd<$scalar, LANES>
333-
where
334-
LaneCount<LANES>: SupportedLaneCount,
335-
{
336-
type Output = Self;
337-
338-
#[inline]
339-
fn shl(self, rhs: $scalar) -> Self::Output {
340-
if invalid_shift_rhs(rhs) {
341-
panic!("attempt to shift left with overflow");
342-
}
343-
let rhs = Self::splat(rhs);
344-
unsafe { intrinsics::simd_shl(self, rhs) }
345-
}
346-
}
347-
}
348-
349272
impl_ref_ops! {
350273
impl<const LANES: usize> core::ops::Shr<Self> for Simd<$scalar, LANES>
351274
where
@@ -367,24 +290,6 @@ macro_rules! impl_unsigned_int_ops {
367290
}
368291
}
369292
}
370-
371-
impl_ref_ops! {
372-
impl<const LANES: usize> core::ops::Shr<$scalar> for Simd<$scalar, LANES>
373-
where
374-
LaneCount<LANES>: SupportedLaneCount,
375-
{
376-
type Output = Self;
377-
378-
#[inline]
379-
fn shr(self, rhs: $scalar) -> Self::Output {
380-
if invalid_shift_rhs(rhs) {
381-
panic!("attempt to shift with overflow");
382-
}
383-
let rhs = Self::splat(rhs);
384-
unsafe { intrinsics::simd_shr(self, rhs) }
385-
}
386-
}
387-
}
388293
)*
389294
};
390295
}

crates/core_simd/src/ops/splat.rs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//! This module implements "auto-splats" for operators.
2+
//! These should be handled with care due to the risks to type inference.
3+
//! We require for every autosplat that:
4+
//! - Simd<T, _> implements the operation for itself, returning Simd<T, _>
5+
//! - T implements the same operation for T, returning T
6+
//!
7+
//! The second bound is not strictly necessary, but enforces symmetry
8+
//! between a vector operation and repeating the scalar equivalent.
9+
use super::*;
10+
11+
macro_rules! autosplat_rhs {
12+
($(impl<T, const LANES: usize> $op:ident<$operand:ty> for Simd<$scalar:ty, LANES> {
13+
fn $call:ident
14+
})*) => {
15+
$(impl<T, const LANES: usize> $op<$operand> for Simd<$scalar, LANES>
16+
where
17+
Self: $op<Self, Output=Self>,
18+
$operand: SimdElement + $op<T, Output=T>,
19+
LaneCount<LANES>: SupportedLaneCount,
20+
{
21+
type Output = Self;
22+
23+
#[inline]
24+
#[must_use = "operator returns a new vector without mutating the inputs"]
25+
fn $call(self, rhs: $operand) -> Self::Output {
26+
self.$call(Self::splat(rhs))
27+
}
28+
})*
29+
}
30+
}
31+
32+
33+
autosplat_rhs! {
34+
// Arithmetic
35+
impl<T, const LANES: usize> Add<T> for Simd<T, LANES> {
36+
fn add
37+
}
38+
39+
impl<T, const LANES: usize> Mul<T> for Simd<T, LANES> {
40+
fn mul
41+
}
42+
43+
impl<T, const LANES: usize> Sub<T> for Simd<T, LANES> {
44+
fn sub
45+
}
46+
47+
impl<T, const LANES: usize> Div<T> for Simd<T, LANES> {
48+
fn div
49+
}
50+
51+
impl<T, const LANES: usize> Rem<T> for Simd<T, LANES> {
52+
fn rem
53+
}
54+
55+
// Bitwise
56+
impl<T, const LANES: usize> BitAnd<T> for Simd<T, LANES> {
57+
fn bitand
58+
}
59+
60+
impl<T, const LANES: usize> BitOr<T> for Simd<T, LANES> {
61+
fn bitor
62+
}
63+
64+
impl<T, const LANES: usize> BitXor<T> for Simd<T, LANES> {
65+
fn bitxor
66+
}
67+
68+
impl<T, const LANES: usize> Shl<T> for Simd<T, LANES> {
69+
fn shl
70+
}
71+
72+
impl<T, const LANES: usize> Shr<T> for Simd<T, LANES> {
73+
fn shr
74+
}
75+
}

0 commit comments

Comments
 (0)