Skip to main content

rustfft/avx/
mod.rs

1use crate::fft_helper::{fft_helper_immut, fft_helper_inplace, fft_helper_outofplace};
2use crate::{Fft, FftDirection, FftNum};
3use std::arch::x86_64::{__m256, __m256d};
4use std::sync::Arc;
5
6pub trait AvxNum: FftNum {
7    type VectorType: AvxVector256<ScalarType = Self>;
8}
9
10impl AvxNum for f32 {
11    type VectorType = __m256;
12}
13impl AvxNum for f64 {
14    type VectorType = __m256d;
15}
16
17// Data that most (non-butterfly) SIMD FFT algorithms share
18// Algorithms aren't required to use this struct, but it allows for a lot of reduction in code duplication
19struct CommonSimdData<T, V> {
20    inner_fft: Arc<dyn Fft<T>>,
21    twiddles: Box<[V]>,
22
23    len: usize,
24
25    inplace_scratch_len: usize,
26    outofplace_scratch_len: usize,
27    immut_scratch_len: usize,
28
29    direction: FftDirection,
30}
31
32macro_rules! boilerplate_avx_fft {
33    ($struct_name:ident, $len_fn:expr, $inplace_scratch_len_fn:expr, $out_of_place_scratch_len_fn:expr, $immut_scratch_len_fn:expr) => {
34        impl<A: AvxNum, T: FftNum> Fft<T> for $struct_name<A, T> {
35            fn process_immutable_with_scratch(
36                &self,
37                input: &[Complex<T>],
38                output: &mut [Complex<T>],
39                scratch: &mut [Complex<T>],
40            ) {
41                unsafe {
42                    super::avx_fft_helper_immut(
43                        input,
44                        output,
45                        scratch,
46                        self.len(),
47                        self.get_immutable_scratch_len(),
48                        |in_chunk, out_chunk, scratch| {
49                            self.perform_fft_immut(in_chunk, out_chunk, scratch)
50                        },
51                    )
52                }
53            }
54
55            fn process_outofplace_with_scratch(
56                &self,
57                input: &mut [Complex<T>],
58                output: &mut [Complex<T>],
59                scratch: &mut [Complex<T>],
60            ) {
61                unsafe {
62                    super::avx_fft_helper_outofplace(
63                        input,
64                        output,
65                        scratch,
66                        self.len(),
67                        self.get_outofplace_scratch_len(),
68                        |in_chunk, out_chunk, scratch| {
69                            self.perform_fft_out_of_place(in_chunk, out_chunk, scratch)
70                        },
71                    )
72                }
73            }
74            fn process_with_scratch(&self, buffer: &mut [Complex<T>], scratch: &mut [Complex<T>]) {
75                unsafe {
76                    super::avx_fft_helper_inplace(
77                        buffer,
78                        scratch,
79                        self.len(),
80                        self.get_inplace_scratch_len(),
81                        |chunk, scratch| self.perform_fft_inplace(chunk, scratch),
82                    )
83                }
84            }
85            #[inline(always)]
86            fn get_inplace_scratch_len(&self) -> usize {
87                $inplace_scratch_len_fn(self)
88            }
89            #[inline(always)]
90            fn get_outofplace_scratch_len(&self) -> usize {
91                $out_of_place_scratch_len_fn(self)
92            }
93            #[inline(always)]
94            fn get_immutable_scratch_len(&self) -> usize {
95                $immut_scratch_len_fn(self)
96            }
97        }
98        impl<A: AvxNum, T> Length for $struct_name<A, T> {
99            #[inline(always)]
100            fn len(&self) -> usize {
101                $len_fn(self)
102            }
103        }
104        impl<A: AvxNum, T> Direction for $struct_name<A, T> {
105            #[inline(always)]
106            fn fft_direction(&self) -> FftDirection {
107                self.direction
108            }
109        }
110    };
111}
112
113macro_rules! boilerplate_avx_fft_commondata {
114    ($struct_name:ident) => {
115        impl<A: AvxNum, T: FftNum> Fft<T> for $struct_name<A, T> {
116            fn process_immutable_with_scratch(
117                &self,
118                input: &[Complex<T>],
119                output: &mut [Complex<T>],
120                scratch: &mut [Complex<T>],
121            ) {
122                unsafe {
123                    super::avx_fft_helper_immut(
124                        input,
125                        output,
126                        scratch,
127                        self.len(),
128                        self.get_immutable_scratch_len(),
129                        |in_chunk, out_chunk, scratch| {
130                            self.perform_fft_immut(in_chunk, out_chunk, scratch)
131                        },
132                    )
133                }
134            }
135            fn process_outofplace_with_scratch(
136                &self,
137                input: &mut [Complex<T>],
138                output: &mut [Complex<T>],
139                scratch: &mut [Complex<T>],
140            ) {
141                unsafe {
142                    super::avx_fft_helper_outofplace(
143                        input,
144                        output,
145                        scratch,
146                        self.len(),
147                        self.get_outofplace_scratch_len(),
148                        |in_chunk, out_chunk, scratch| {
149                            self.perform_fft_out_of_place(in_chunk, out_chunk, scratch)
150                        },
151                    )
152                }
153            }
154            fn process_with_scratch(&self, buffer: &mut [Complex<T>], scratch: &mut [Complex<T>]) {
155                unsafe {
156                    super::avx_fft_helper_inplace(
157                        buffer,
158                        scratch,
159                        self.len(),
160                        self.get_inplace_scratch_len(),
161                        |chunk, scratch| self.perform_fft_inplace(chunk, scratch),
162                    )
163                }
164            }
165            #[inline(always)]
166            fn get_inplace_scratch_len(&self) -> usize {
167                self.common_data.inplace_scratch_len
168            }
169            #[inline(always)]
170            fn get_outofplace_scratch_len(&self) -> usize {
171                self.common_data.outofplace_scratch_len
172            }
173            #[inline(always)]
174            fn get_immutable_scratch_len(&self) -> usize {
175                self.common_data.immut_scratch_len
176            }
177        }
178        impl<A: AvxNum, T> Length for $struct_name<A, T> {
179            #[inline(always)]
180            fn len(&self) -> usize {
181                self.common_data.len
182            }
183        }
184        impl<A: AvxNum, T> Direction for $struct_name<A, T> {
185            #[inline(always)]
186            fn fft_direction(&self) -> FftDirection {
187                self.common_data.direction
188            }
189        }
190    };
191}
192
193// A wrapper for the FFT helper functions that make sure the entire thing happens with the benefit of the AVX and FMA target features,
194// so that things like loading twiddle factor registers etc can be lifted out of the loop
195#[target_feature(enable = "avx", enable = "fma")]
196pub unsafe fn avx_fft_helper_immut<T>(
197    input: &[T],
198    output: &mut [T],
199    scratch: &mut [T],
200    chunk_size: usize,
201    required_scratch: usize,
202    chunk_fn: impl FnMut(&[T], &mut [T], &mut [T]),
203) {
204    fft_helper_immut(
205        input,
206        output,
207        scratch,
208        chunk_size,
209        required_scratch,
210        chunk_fn,
211    )
212}
213
214// A wrapper for the FFT helper functions that make sure the entire thing happens with the benefit of the AVX and FMA target features,
215// so that things like loading twiddle factor registers etc can be lifted out of the loop
216#[target_feature(enable = "avx", enable = "fma")]
217pub unsafe fn avx_fft_helper_outofplace<T>(
218    input: &mut [T],
219    output: &mut [T],
220    scratch: &mut [T],
221    chunk_size: usize,
222    required_scratch: usize,
223    chunk_fn: impl FnMut(&mut [T], &mut [T], &mut [T]),
224) {
225    fft_helper_outofplace(
226        input,
227        output,
228        scratch,
229        chunk_size,
230        required_scratch,
231        chunk_fn,
232    )
233}
234
235// A wrapper for the FFT helper functions that make sure the entire thing happens with the benefit of the AVX and FMA target features,
236// so that things like loading twiddle factor registers etc can be lifted out of the loop
237#[target_feature(enable = "avx", enable = "fma")]
238pub unsafe fn avx_fft_helper_inplace<T>(
239    buffer: &mut [T],
240    scratch: &mut [T],
241    chunk_size: usize,
242    required_scratch: usize,
243    chunk_fn: impl FnMut(&mut [T], &mut [T]),
244) {
245    fft_helper_inplace(buffer, scratch, chunk_size, required_scratch, chunk_fn)
246}
247
248#[macro_use]
249mod avx_vector;
250
251mod avx32_butterflies;
252mod avx32_utils;
253
254mod avx64_butterflies;
255mod avx64_utils;
256
257mod avx_bluesteins;
258mod avx_mixed_radix;
259mod avx_raders;
260
261pub mod avx_planner;
262
263pub use self::avx32_butterflies::{
264    Butterfly11Avx, Butterfly128Avx, Butterfly12Avx, Butterfly16Avx, Butterfly24Avx,
265    Butterfly256Avx, Butterfly27Avx, Butterfly32Avx, Butterfly36Avx, Butterfly48Avx,
266    Butterfly512Avx, Butterfly54Avx, Butterfly5Avx, Butterfly64Avx, Butterfly72Avx, Butterfly7Avx,
267    Butterfly8Avx, Butterfly9Avx,
268};
269
270pub use self::avx64_butterflies::{
271    Butterfly11Avx64, Butterfly128Avx64, Butterfly12Avx64, Butterfly16Avx64, Butterfly18Avx64,
272    Butterfly24Avx64, Butterfly256Avx64, Butterfly27Avx64, Butterfly32Avx64, Butterfly36Avx64,
273    Butterfly512Avx64, Butterfly5Avx64, Butterfly64Avx64, Butterfly7Avx64, Butterfly8Avx64,
274    Butterfly9Avx64,
275};
276
277pub use self::avx_bluesteins::BluesteinsAvx;
278pub use self::avx_mixed_radix::{
279    MixedRadix11xnAvx, MixedRadix12xnAvx, MixedRadix16xnAvx, MixedRadix2xnAvx, MixedRadix3xnAvx,
280    MixedRadix4xnAvx, MixedRadix5xnAvx, MixedRadix6xnAvx, MixedRadix7xnAvx, MixedRadix8xnAvx,
281    MixedRadix9xnAvx,
282};
283pub use self::avx_raders::RadersAvx2;
284use self::avx_vector::AvxVector256;