1use std::any::TypeId;
2
3use crate::fft_helper::{
4 fft_helper_immut, fft_helper_immut_unroll2x, fft_helper_inplace, fft_helper_inplace_unroll2x,
5 fft_helper_outofplace, fft_helper_outofplace_unroll2x,
6};
7
8pub fn assert_f32<T: 'static>() {
10 let id_f32 = TypeId::of::<f32>();
11 let id_t = TypeId::of::<T>();
12 assert!(id_t == id_f32, "Wrong float type, must be f32");
13}
14
15pub fn assert_f64<T: 'static>() {
17 let id_f64 = TypeId::of::<f64>();
18 let id_t = TypeId::of::<T>();
19 assert!(id_t == id_f64, "Wrong float type, must be f64");
20}
21
22macro_rules! interleave_complex_f32 {
24 ($input:ident, $offset:literal, { $($idx:literal),* }) => {
25 [
26 $(
27 extract_lo_lo_f32($input[$idx], $input[$idx+$offset]),
28 extract_hi_hi_f32($input[$idx], $input[$idx+$offset]),
29 )*
30 ]
31 }
32}
33
34macro_rules! separate_interleaved_complex_f32 {
50 ($input:ident, { $($idx:literal),* }) => {
51 [
52 $(
53 extract_lo_lo_f32($input[$idx], $input[$idx+1]),
54 )*
55 $(
56 extract_hi_hi_f32($input[$idx], $input[$idx+1]),
57 )*
58 ]
59 }
60}
61
62macro_rules! boilerplate_fft_sse_oop {
63 ($struct_name:ident, $len_fn:expr) => {
64 impl<S: SseNum, T: FftNum> Fft<T> for $struct_name<S, T> {
65 fn process_immutable_with_scratch(
66 &self,
67 input: &[Complex<T>],
68 output: &mut [Complex<T>],
69 _scratch: &mut [Complex<T>],
70 ) {
71 unsafe {
72 let simd_input = crate::array_utils::workaround_transmute(input);
73 let simd_output = crate::array_utils::workaround_transmute_mut(output);
74 super::sse_common::sse_fft_helper_immut(
75 simd_input,
76 simd_output,
77 &mut [],
78 self.len(),
79 0,
80 |input, output, _| self.perform_fft_immut(input, output, &mut []),
81 );
82 }
83 }
84 fn process_outofplace_with_scratch(
85 &self,
86 input: &mut [Complex<T>],
87 output: &mut [Complex<T>],
88 _scratch: &mut [Complex<T>],
89 ) {
90 unsafe {
91 let simd_input = crate::array_utils::workaround_transmute_mut(input);
92 let simd_output = crate::array_utils::workaround_transmute_mut(output);
93 super::sse_common::sse_fft_helper_outofplace(
94 simd_input,
95 simd_output,
96 &mut [],
97 self.len(),
98 0,
99 |input, output, _| self.perform_fft_out_of_place(input, output, &mut []),
100 );
101 }
102 }
103 fn process_with_scratch(&self, buffer: &mut [Complex<T>], scratch: &mut [Complex<T>]) {
104 unsafe {
105 let simd_buffer = crate::array_utils::workaround_transmute_mut(buffer);
106 let simd_scratch = crate::array_utils::workaround_transmute_mut(scratch);
107 super::sse_common::sse_fft_helper_inplace(
108 simd_buffer,
109 simd_scratch,
110 self.len(),
111 self.get_inplace_scratch_len(),
112 |chunk, scratch| {
113 self.perform_fft_out_of_place(chunk, scratch, &mut []);
114 chunk.copy_from_slice(scratch);
115 },
116 )
117 }
118 }
119 #[inline(always)]
120 fn get_inplace_scratch_len(&self) -> usize {
121 self.len()
122 }
123 #[inline(always)]
124 fn get_outofplace_scratch_len(&self) -> usize {
125 0
126 }
127 #[inline(always)]
128 fn get_immutable_scratch_len(&self) -> usize {
129 0
130 }
131 }
132 impl<S: SseNum, T> Length for $struct_name<S, T> {
133 #[inline(always)]
134 fn len(&self) -> usize {
135 $len_fn(self)
136 }
137 }
138 impl<S: SseNum, T> Direction for $struct_name<S, T> {
139 #[inline(always)]
140 fn fft_direction(&self) -> FftDirection {
141 self.direction
142 }
143 }
144 };
145}
146
147#[target_feature(enable = "sse4.1")]
150pub unsafe fn sse_fft_helper_immut<T>(
151 input: &[T],
152 output: &mut [T],
153 scratch: &mut [T],
154 chunk_size: usize,
155 required_scratch: usize,
156 chunk_fn: impl FnMut(&[T], &mut [T], &mut [T]),
157) {
158 fft_helper_immut(
159 input,
160 output,
161 scratch,
162 chunk_size,
163 required_scratch,
164 chunk_fn,
165 )
166}
167
168#[target_feature(enable = "sse4.1")]
171pub unsafe fn sse_fft_helper_outofplace<T>(
172 input: &mut [T],
173 output: &mut [T],
174 scratch: &mut [T],
175 chunk_size: usize,
176 required_scratch: usize,
177 chunk_fn: impl FnMut(&mut [T], &mut [T], &mut [T]),
178) {
179 fft_helper_outofplace(
180 input,
181 output,
182 scratch,
183 chunk_size,
184 required_scratch,
185 chunk_fn,
186 )
187}
188
189#[target_feature(enable = "sse4.1")]
192pub unsafe fn sse_fft_helper_inplace<T>(
193 buffer: &mut [T],
194 scratch: &mut [T],
195 chunk_size: usize,
196 required_scratch: usize,
197 chunk_fn: impl FnMut(&mut [T], &mut [T]),
198) {
199 fft_helper_inplace(buffer, scratch, chunk_size, required_scratch, chunk_fn)
200}
201
202#[target_feature(enable = "sse4.1")]
205pub unsafe fn sse_fft_helper_immut_unroll2x<T>(
206 input: &[T],
207 output: &mut [T],
208 chunk_size: usize,
209 chunk2x_fn: impl FnMut(&[T], &mut [T]),
210 chunk_fn: impl FnMut(&[T], &mut [T]),
211) {
212 fft_helper_immut_unroll2x(input, output, chunk_size, chunk2x_fn, chunk_fn)
213}
214
215#[target_feature(enable = "sse4.1")]
218pub unsafe fn sse_fft_helper_outofplace_unroll2x<T>(
219 input: &mut [T],
220 output: &mut [T],
221 chunk_size: usize,
222 chunk2x_fn: impl FnMut(&mut [T], &mut [T]),
223 chunk_fn: impl FnMut(&mut [T], &mut [T]),
224) {
225 fft_helper_outofplace_unroll2x(input, output, chunk_size, chunk2x_fn, chunk_fn)
226}
227
228#[target_feature(enable = "sse4.1")]
231pub unsafe fn sse_fft_helper_inplace_unroll2x<T>(
232 buffer: &mut [T],
233 chunk_size: usize,
234 chunk2x_fn: impl FnMut(&mut [T]),
235 chunk_fn: impl FnMut(&mut [T]),
236) {
237 fft_helper_inplace_unroll2x(buffer, chunk_size, chunk2x_fn, chunk_fn)
238}