1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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};
use core::ops::{Shl, Shr};

mod assign;
mod deref;
mod unary;

impl<I, T, const LANES: usize> core::ops::Index<I> for Simd<T, LANES>
where
    T: SimdElement,
    LaneCount<LANES>: SupportedLaneCount,
    I: core::slice::SliceIndex<[T]>,
{
    type Output = I::Output;
    fn index(&self, index: I) -> &Self::Output {
        &self.as_array()[index]
    }
}

impl<I, T, const LANES: usize> core::ops::IndexMut<I> for Simd<T, LANES>
where
    T: SimdElement,
    LaneCount<LANES>: SupportedLaneCount,
    I: core::slice::SliceIndex<[T]>,
{
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        &mut self.as_mut_array()[index]
    }
}

macro_rules! unsafe_base {
    ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
        // 安全性: $lhs 和 $rhs 是 vectors
        unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) }
    };
}

/// SAFETY: 这个宏不应该用于除 Shl 或 Shr 之外的任何东西,并且通过了适当的 shift 内部函数。
/// 它处理执行 bitand 除了调用移位运算符之外,因此结果是明确定义的: 如果您 shl、lshr 或 ashr 如果 `rhs >= <Int>::BITS`,LLVM 可以返回一个毒值在最坏的情况下,这可能会添加另一个指令和循环,充其量,它可能会带来更多的优化机会,或者干脆完全忽略,尤其是对于默认为它的 SIMD ISA。
///
///
///
///
///
// FIXME: 考虑在 cg_llvm 中实现这个?
// cg_clif 默认为这个,标量 MIR 移位也默认为 wrapping
macro_rules! wrap_bitshift {
    ($lhs:ident, $rhs:ident, {$simd_call:ident}, $int:ident) => {
        #[allow(clippy::suspicious_arithmetic_impl)]
        // 安全性: $lhs 和 bitand 结果是 vectors
        unsafe {
            $crate::simd::intrinsics::$simd_call(
                $lhs,
                $rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)),
            )
        }
    };
}

/// SAFETY: 这个宏只能用于实现 Div 或 Rem 并给出匹配的内部函数。
/// 它使用掩码和选择来防止 LLVM 的整数 div 或 rem 的 UB 条件,从而保证返回 Rust 值。
///
///
/// |                  | LLVM | Rust
/// | :--------------: | :--- | :----------
/// | N {/,%} 0        | UB   | panic!()
/// | <$int>::MIN / -1 | UB   | <$int>::MIN
/// | <$int>::MIN % -1 | UB   | 0
///
macro_rules! int_divrem_guard {
    (   $lhs:ident,
        $rhs:ident,
        {   const PANIC_ZERO: &'static str = $zero:literal;
            $simd_call:ident
        },
        $int:ident ) => {
        if $rhs.simd_eq(Simd::splat(0 as _)).any() {
            panic!($zero);
        } else {
            // 防止 MIN/-1 情况下的其他 UB 溢出。
            let rhs = if <$int>::MIN != 0 {
                // 在最坏的情况下,这应该优化到一些无分支的逻辑操作理想情况下,整个条件应该蒸发 Fire LLVM 并在没有得到提示时手动实现它们
                //
                //
                ($lhs.simd_eq(Simd::splat(<$int>::MIN))
                // 类型推断可能会在此处中断,因此将 SInt 裁剪为合适的大小
                & $rhs.simd_eq(Simd::splat(-1i64 as _)))
                .select(Simd::splat(1 as _), $rhs)
            } else {
                // 很好的终止条件,可以很容易地 const-fold 掉另一个分支。
                $rhs
            };
            // 安全性: $lhs 和 rhs 是 vectors
            unsafe { $crate::simd::intrinsics::$simd_call($lhs, rhs) }
        }
    };
}

macro_rules! for_base_types {
    (   T = ($($scalar:ident),*);
        type Lhs = Simd<T, N>;
        type Rhs = Simd<T, N>;
        type Output = $out:ty;

        impl $op:ident::$call:ident {
            $macro_impl:ident $inner:tt
        }) => {
            $(
                impl<const N: usize> $op<Self> for Simd<$scalar, N>
                where
                    $scalar: SimdElement,
                    LaneCount<N>: SupportedLaneCount,
                {
                    type Output = $out;

                    #[inline]
                    #[must_use = "operator returns a new vector without mutating the inputs"]
                    fn $call(self, rhs: Self) -> Self::Output {
                        $macro_impl!(self, rhs, $inner, $scalar)
                    }
                })*
    }
}

// "TokenTree muncher": 为其实现的操作采用一组标量类型 `T = {};` 类型参数、`Op::fn` 名称和扩展为 expr 的宏,替换为内部函数。
//
// 它将它传递给 for_base_types,后者使用函数中的扩展 expr 扩展类型的 impl,并与自身递归。
//
// tl;dr 为一组类型实现了一组 ops::{Traits}
//
//
macro_rules! for_base_ops {
    (
        T = $types:tt;
        type Lhs = Simd<T, N>;
        type Rhs = Simd<T, N>;
        type Output = $out:ident;
        impl $op:ident::$call:ident
            $inner:tt
        $($rest:tt)*
    ) => {
        for_base_types! {
            T = $types;
            type Lhs = Simd<T, N>;
            type Rhs = Simd<T, N>;
            type Output = $out;
            impl $op::$call
                $inner
        }
        for_base_ops! {
            T = $types;
            type Lhs = Simd<T, N>;
            type Rhs = Simd<T, N>;
            type Output = $out;
            $($rest)*
        }
    };
    ($($done:tt)*) => {
        // Done.
    }
}

// 整数总是可以接受 add、mul、sub、bitand、bitor 和 bitxor。
// 对于所有这些操作,simd_* 内部函数应用了包装逻辑。
for_base_ops! {
    T = (i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
    type Lhs = Simd<T, N>;
    type Rhs = Simd<T, N>;
    type Output = Self;

    impl Add::add {
        unsafe_base { simd_add }
    }

    impl Mul::mul {
        unsafe_base { simd_mul }
    }

    impl Sub::sub {
        unsafe_base { simd_sub }
    }

    impl BitAnd::bitand {
        unsafe_base { simd_and }
    }

    impl BitOr::bitor {
        unsafe_base { simd_or }
    }

    impl BitXor::bitxor {
        unsafe_base { simd_xor }
    }

    impl Div::div {
        int_divrem_guard {
            const PANIC_ZERO: &'static str = "attempt to divide by zero";
            simd_div
        }
    }

    impl Rem::rem {
        int_divrem_guard {
            const PANIC_ZERO: &'static str = "attempt to calculate the remainder with a divisor of zero";
            simd_rem
        }
    }

    // 唯一的问题是如何处理 shifts >= <Int>::BITS?
    // 我们当前的解决方案中使用了包装逻辑。
    impl Shl::shl {
        wrap_bitshift { simd_shl }
    }

    impl Shr::shr {
        wrap_bitshift {
            // 根据情况,它会自动单态化为 lshr 或 ashr,因此对 UInts 和 SInts 都使用它也没问题。
            //
            simd_shr
        }
    }
}

// 我们在这里不需要任何特殊的预防措施:
// 浮点数总是接受算术运算,但可能会变成 NaN。
for_base_ops! {
    T = (f32, f64);
    type Lhs = Simd<T, N>;
    type Rhs = Simd<T, N>;
    type Output = Self;

    impl Add::add {
        unsafe_base { simd_add }
    }

    impl Mul::mul {
        unsafe_base { simd_mul }
    }

    impl Sub::sub {
        unsafe_base { simd_sub }
    }

    impl Div::div {
        unsafe_base { simd_div }
    }

    impl Rem::rem {
        unsafe_base { simd_rem }
    }
}