Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 8aef340

Browse files
Refactor bitops with #[must_use]
1 parent b6d0eec commit 8aef340

File tree

1 file changed

+98
-33
lines changed

1 file changed

+98
-33
lines changed

crates/core_simd/src/ops.rs

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,29 @@ where
3232
}
3333
}
3434

35+
macro_rules! unsafe_base_op {
36+
($(impl<const LANES: usize> $op:ident for Simd<$scalar:ty, LANES> {
37+
fn $call:ident(self, rhs: Self) -> Self::Output {
38+
unsafe{ $simd_call:ident }
39+
}
40+
})*) => {
41+
$(impl<const LANES: usize> $op for Simd<$scalar, LANES>
42+
where
43+
$scalar: SimdElement,
44+
LaneCount<LANES>: SupportedLaneCount,
45+
{
46+
type Output = Self;
47+
48+
#[inline]
49+
#[must_use = "operator returns a new vector without mutating the inputs"]
50+
fn $call(self, rhs: Self) -> Self::Output {
51+
unsafe { $crate::intrinsics::$simd_call(self, rhs) }
52+
}
53+
}
54+
)*
55+
}
56+
}
57+
3558
/// SAFETY: This macro should not be used for anything except Shl or Shr, and passed the appropriate shift intrinsic.
3659
/// It handles performing a bitand in addition to calling the shift operator, so that the result
3760
/// is well-defined: LLVM can return a poison value if you shl, lshr, or ashr if rhs >= <Int>::BITS
@@ -41,13 +64,13 @@ where
4164
///
4265
// FIXME: Consider implementing this in cg_llvm instead?
4366
// cg_clif defaults to this, and scalar MIR shifts also default to wrapping
44-
macro_rules! wrap_bitshift_inner {
45-
(impl<const LANES: usize> $op:ident for Simd<$int:ty, LANES> {
67+
macro_rules! wrap_bitshift {
68+
($(impl<const LANES: usize> $op:ident for Simd<$int:ty, LANES> {
4669
fn $call:ident(self, rhs: Self) -> Self::Output {
4770
unsafe { $simd_call:ident }
4871
}
49-
}) => {
50-
impl<const LANES: usize> $op for Simd<$int, LANES>
72+
})*) => {
73+
$(impl<const LANES: usize> $op for Simd<$int, LANES>
5174
where
5275
$int: SimdElement,
5376
LaneCount<LANES>: SupportedLaneCount,
@@ -61,24 +84,45 @@ macro_rules! wrap_bitshift_inner {
6184
$crate::intrinsics::$simd_call(self, rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)))
6285
}
6386
}
64-
}
87+
})*
6588
};
6689
}
6790

68-
macro_rules! wrap_bitshifts {
69-
($(impl<const LANES: usize> ShiftOps for Simd<$int:ty, LANES> {
91+
macro_rules! bitops {
92+
($(impl<const LANES: usize> BitOps for Simd<$int:ty, LANES> {
93+
fn bitand(self, rhs: Self) -> Self::Output;
94+
fn bitor(self, rhs: Self) -> Self::Output;
95+
fn bitxor(self, rhs: Self) -> Self::Output;
7096
fn shl(self, rhs: Self) -> Self::Output;
7197
fn shr(self, rhs: Self) -> Self::Output;
7298
})*) => {
7399
$(
74-
wrap_bitshift_inner! {
100+
unsafe_base_op!{
101+
impl<const LANES: usize> BitAnd for Simd<$int, LANES> {
102+
fn bitand(self, rhs: Self) -> Self::Output {
103+
unsafe { simd_and }
104+
}
105+
}
106+
107+
impl<const LANES: usize> BitOr for Simd<$int, LANES> {
108+
fn bitor(self, rhs: Self) -> Self::Output {
109+
unsafe { simd_or }
110+
}
111+
}
112+
113+
impl<const LANES: usize> BitXor for Simd<$int, LANES> {
114+
fn bitxor(self, rhs: Self) -> Self::Output {
115+
unsafe { simd_xor }
116+
}
117+
}
118+
}
119+
wrap_bitshift! {
75120
impl<const LANES: usize> Shl for Simd<$int, LANES> {
76121
fn shl(self, rhs: Self) -> Self::Output {
77122
unsafe { simd_shl }
78123
}
79124
}
80-
}
81-
wrap_bitshift_inner! {
125+
82126
impl<const LANES: usize> Shr for Simd<$int, LANES> {
83127
fn shr(self, rhs: Self) -> Self::Output {
84128
// This automatically monomorphizes to lshr or ashr, depending,
@@ -91,53 +135,86 @@ macro_rules! wrap_bitshifts {
91135
};
92136
}
93137

94-
wrap_bitshifts! {
95-
impl<const LANES: usize> ShiftOps for Simd<i8, LANES> {
138+
// Integers can always accept bitand, bitor, and bitxor.
139+
// The only question is how to handle shifts >= <Int>::BITS?
140+
// Our current solution uses wrapping logic.
141+
bitops! {
142+
impl<const LANES: usize> BitOps for Simd<i8, LANES> {
143+
fn bitand(self, rhs: Self) -> Self::Output;
144+
fn bitor(self, rhs: Self) -> Self::Output;
145+
fn bitxor(self, rhs: Self) -> Self::Output;
96146
fn shl(self, rhs: Self) -> Self::Output;
97147
fn shr(self, rhs: Self) -> Self::Output;
98148
}
99149

100-
impl<const LANES: usize> ShiftOps for Simd<i16, LANES> {
150+
impl<const LANES: usize> BitOps for Simd<i16, LANES> {
151+
fn bitand(self, rhs: Self) -> Self::Output;
152+
fn bitor(self, rhs: Self) -> Self::Output;
153+
fn bitxor(self, rhs: Self) -> Self::Output;
101154
fn shl(self, rhs: Self) -> Self::Output;
102155
fn shr(self, rhs: Self) -> Self::Output;
103156
}
104157

105-
impl<const LANES: usize> ShiftOps for Simd<i32, LANES> {
158+
impl<const LANES: usize> BitOps for Simd<i32, LANES> {
159+
fn bitand(self, rhs: Self) -> Self::Output;
160+
fn bitor(self, rhs: Self) -> Self::Output;
161+
fn bitxor(self, rhs: Self) -> Self::Output;
106162
fn shl(self, rhs: Self) -> Self::Output;
107163
fn shr(self, rhs: Self) -> Self::Output;
108164
}
109165

110-
impl<const LANES: usize> ShiftOps for Simd<i64, LANES> {
166+
impl<const LANES: usize> BitOps for Simd<i64, LANES> {
167+
fn bitand(self, rhs: Self) -> Self::Output;
168+
fn bitor(self, rhs: Self) -> Self::Output;
169+
fn bitxor(self, rhs: Self) -> Self::Output;
111170
fn shl(self, rhs: Self) -> Self::Output;
112171
fn shr(self, rhs: Self) -> Self::Output;
113172
}
114173

115-
impl<const LANES: usize> ShiftOps for Simd<isize, LANES> {
174+
impl<const LANES: usize> BitOps for Simd<isize, LANES> {
175+
fn bitand(self, rhs: Self) -> Self::Output;
176+
fn bitor(self, rhs: Self) -> Self::Output;
177+
fn bitxor(self, rhs: Self) -> Self::Output;
116178
fn shl(self, rhs: Self) -> Self::Output;
117179
fn shr(self, rhs: Self) -> Self::Output;
118180
}
119181

120-
impl<const LANES: usize> ShiftOps for Simd<u8, LANES> {
182+
impl<const LANES: usize> BitOps for Simd<u8, LANES> {
183+
fn bitand(self, rhs: Self) -> Self::Output;
184+
fn bitor(self, rhs: Self) -> Self::Output;
185+
fn bitxor(self, rhs: Self) -> Self::Output;
121186
fn shl(self, rhs: Self) -> Self::Output;
122187
fn shr(self, rhs: Self) -> Self::Output;
123188
}
124189

125-
impl<const LANES: usize> ShiftOps for Simd<u16, LANES> {
190+
impl<const LANES: usize> BitOps for Simd<u16, LANES> {
191+
fn bitand(self, rhs: Self) -> Self::Output;
192+
fn bitor(self, rhs: Self) -> Self::Output;
193+
fn bitxor(self, rhs: Self) -> Self::Output;
126194
fn shl(self, rhs: Self) -> Self::Output;
127195
fn shr(self, rhs: Self) -> Self::Output;
128196
}
129197

130-
impl<const LANES: usize> ShiftOps for Simd<u32, LANES> {
198+
impl<const LANES: usize> BitOps for Simd<u32, LANES> {
199+
fn bitand(self, rhs: Self) -> Self::Output;
200+
fn bitor(self, rhs: Self) -> Self::Output;
201+
fn bitxor(self, rhs: Self) -> Self::Output;
131202
fn shl(self, rhs: Self) -> Self::Output;
132203
fn shr(self, rhs: Self) -> Self::Output;
133204
}
134205

135-
impl<const LANES: usize> ShiftOps for Simd<u64, LANES> {
206+
impl<const LANES: usize> BitOps for Simd<u64, LANES> {
207+
fn bitand(self, rhs: Self) -> Self::Output;
208+
fn bitor(self, rhs: Self) -> Self::Output;
209+
fn bitxor(self, rhs: Self) -> Self::Output;
136210
fn shl(self, rhs: Self) -> Self::Output;
137211
fn shr(self, rhs: Self) -> Self::Output;
138212
}
139213

140-
impl<const LANES: usize> ShiftOps for Simd<usize, LANES> {
214+
impl<const LANES: usize> BitOps for Simd<usize, LANES> {
215+
fn bitand(self, rhs: Self) -> Self::Output;
216+
fn bitor(self, rhs: Self) -> Self::Output;
217+
fn bitxor(self, rhs: Self) -> Self::Output;
141218
fn shl(self, rhs: Self) -> Self::Output;
142219
fn shr(self, rhs: Self) -> Self::Output;
143220
}
@@ -186,15 +263,6 @@ macro_rules! impl_op {
186263
{ impl Rem for $scalar:ty } => {
187264
impl_op! { @binary $scalar, Rem::rem, simd_rem }
188265
};
189-
{ impl BitAnd for $scalar:ty } => {
190-
impl_op! { @binary $scalar, BitAnd::bitand, simd_and }
191-
};
192-
{ impl BitOr for $scalar:ty } => {
193-
impl_op! { @binary $scalar, BitOr::bitor, simd_or }
194-
};
195-
{ impl BitXor for $scalar:ty } => {
196-
impl_op! { @binary $scalar, BitXor::bitxor, simd_xor }
197-
};
198266

199267
// generic binary op with assignment when output is `Self`
200268
{ @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $intrinsic:ident } => {
@@ -236,9 +304,6 @@ macro_rules! impl_unsigned_int_ops {
236304
impl_op! { impl Add for $scalar }
237305
impl_op! { impl Sub for $scalar }
238306
impl_op! { impl Mul for $scalar }
239-
impl_op! { impl BitAnd for $scalar }
240-
impl_op! { impl BitOr for $scalar }
241-
impl_op! { impl BitXor for $scalar }
242307

243308
// Integers panic on divide by 0
244309
impl_ref_ops! {

0 commit comments

Comments
 (0)