nk
1.0.0
C++ Numerical Computing Runtime
Toggle main menu visibility
Loading...
Searching...
No Matches
fft_kernels.hpp
1
// ops/include/nk/ops/fft/fft_kernels.hpp
2
//
3
// Private kernel-dispatch header for FFT backends. Compiled by
4
// exactly one of backends/MDspFft_{portable,simd}.cpp based on
5
// NK_WITH_SIMD. The only caller of fftRadix2Impl is fftAlongDim
6
// in fft.cpp — other FFT users (transforms/, spectral_analysis/,
7
// convFFT) still call the inline scalar fftRadix2 in helpers.hpp
8
// directly; migrate them individually if their perf matters.
9
10
#pragma once
11
12
#include <nk/value/value.hpp>
// Complex (nk::Complex) // Complex
13
14
#include <cstddef>
15
16
namespace
nk::ops::detail {
17
18
// In-place radix-2 FFT over an interleaved-complex buffer.
19
// N must be a power of 2. W is a precomputed twiddle table of
20
// length N/2 (see fillFftTwiddles in helpers.hpp).
21
//
22
// The portable backend forwards to the inline scalar reference.
23
// The SIMD backend converts to SoA (split real/imag) internally,
24
// runs vectorised butterflies via Highway, and converts back.
25
void
fftRadix2Impl(Complex *buf, std::size_t N,
const
Complex *W);
26
27
// Stockham auto-sort radix-2 dispatcher (SIMD backend only). Same
28
// contract as fftRadix2Impl but uses an internal thread-local
29
// scratch buffer instead of working in place — eliminates the
30
// bit-reversal pre-pass at the cost of 2× memory for the working
31
// state. Exposed for benchmarking from fft_bench; the public
32
// fftRadix2Impl chooses whether to route here based on N.
33
void
fftStockhamDispatch(Complex *buf, std::size_t N,
const
Complex *W);
34
35
// SoA radix-2 dispatcher: same in-place semantics as fftRadix2Impl,
36
// but the kernel converts buf → split real/imag arrays internally to
37
// avoid the AVX2 LoadInterleaved2/StoreInterleaved2 permute cost,
38
// then converts back. Per-thread re/im scratch grows monotonically.
39
void
fftRadix2SoaDispatch(Complex *buf, std::size_t N,
const
Complex *W);
40
41
// SoA radix-4 dispatcher: same algorithm as the AoS r4 path, but
42
// using split real/imag layout to skip the AVX2 LoadInterleaved2 ×4
43
// + StoreInterleaved2 ×4 permute cost per inner iteration. N must
44
// be a power of 4. Per-thread re/im scratch grows monotonically.
45
void
fftRadix4Pow4SoaDispatch(Complex *buf, std::size_t N,
const
Complex *W);
46
47
// SoA-native FFT stages: caller provides split-real/imag scratch
48
// already populated with the input. Runs bit-reverse + butterfly
49
// stages in place on re/im, picks r2 or r4 internally based on N.
50
// Used by the wrapper's rfft path which packs straight into SoA and
51
// twists straight from SoA, avoiding the per-call AoS↔SoA conversion
52
// the public AoS-in/out dispatchers wrap around the same kernels.
53
//
54
// On WASM (Emscripten target) — the dispatcher falls back to AoS in
55
// the wrapper since SoA doesn't help SIMD128. This entry point still
56
// works (it just routes to the AoS path with internal conversion);
57
// the wrapper checks the platform and decides.
58
void
fftSoaStagesDispatch(
double
*re,
double
*im, std::size_t N,
const
Complex *W);
59
60
}
// namespace nk::ops::detail
src
ops
include
nk
ops
fft
fft_kernels.hpp
Generated by
1.17.0