Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
scalar_kernels.hpp
Go to the documentation of this file.
1#pragma once
2
3// Scalar reference kernels for pulp::simd, shared by the compiled scalar
4// backend (src/scalar.cpp) and the inline fallback that <pulp/simd/simd.hpp>
5// uses when a translation unit is built without pulp-simd's usage
6// requirements (a hand-listed source build such as a wasm or Rack plugin).
7//
8// Plain sequential loops in the element type. These define the numerical
9// reference the other backends are compared against: every reduction
10// accumulates left to right, and nothing is reordered on purpose. The
11// optimiser may still vectorize the elementwise loops (that does not change
12// their results) and, where the target contracts a*b+c into a fused
13// multiply-add by default, fuse them; the reference is therefore exact to
14// rounding of its own formula, not bit-identical across architectures.
15
16#include <algorithm>
17#include <cmath>
18#include <cstddef>
19
21
22template <typename T> inline void add_impl(const T* a, const T* b, T* dst, std::size_t n) noexcept {
23 for (std::size_t i = 0; i < n; ++i)
24 dst[i] = a[i] + b[i];
25}
26
27template <typename T> inline void mul_impl(const T* a, const T* b, T* dst, std::size_t n) noexcept {
28 for (std::size_t i = 0; i < n; ++i)
29 dst[i] = a[i] * b[i];
30}
31
32template <typename T>
33inline void fma_impl(const T* a, const T* b, const T* c, T* dst, std::size_t n) noexcept {
34 for (std::size_t i = 0; i < n; ++i)
35 dst[i] = a[i] * b[i] + c[i];
36}
37
38template <typename T> inline void set_impl(T value, T* dst, std::size_t n) noexcept {
39 for (std::size_t i = 0; i < n; ++i)
40 dst[i] = value;
41}
42
43template <typename T> inline void scale_impl(const T* a, T s, T* dst, std::size_t n) noexcept {
44 for (std::size_t i = 0; i < n; ++i)
45 dst[i] = a[i] * s;
46}
47
48template <typename T> inline void add_scaled_impl(const T* a, T s, T* dst, std::size_t n) noexcept {
49 for (std::size_t i = 0; i < n; ++i)
50 dst[i] += a[i] * s;
51}
52
53template <typename T> inline T sum_impl(const T* x, std::size_t n) noexcept {
54 T acc = T(0);
55 for (std::size_t i = 0; i < n; ++i)
56 acc += x[i];
57 return acc;
58}
59
60template <typename T> inline T maximum_impl(const T* x, std::size_t n) noexcept {
61 if (n == 0)
62 return T(0);
63 T m = x[0];
64 for (std::size_t i = 1; i < n; ++i)
65 m = std::max(m, x[i]);
66 return m;
67}
68
69template <typename T> inline T minimum_impl(const T* x, std::size_t n) noexcept {
70 if (n == 0)
71 return T(0);
72 T m = x[0];
73 for (std::size_t i = 1; i < n; ++i)
74 m = std::min(m, x[i]);
75 return m;
76}
77
78template <typename T> inline void abs_impl(const T* a, T* dst, std::size_t n) noexcept {
79 for (std::size_t i = 0; i < n; ++i)
80 dst[i] = std::abs(a[i]);
81}
82
83template <typename T>
84inline void clamp_impl(const T* a, T lo, T hi, T* dst, std::size_t n) noexcept {
85 for (std::size_t i = 0; i < n; ++i)
86 dst[i] = std::clamp(a[i], lo, hi);
87}
88
89template <typename T> inline T dot_impl(const T* a, const T* b, std::size_t n) noexcept {
90 T acc = T(0);
91 for (std::size_t i = 0; i < n; ++i)
92 acc += a[i] * b[i];
93 return acc;
94}
95
96template <typename T> inline T sum_squares_impl(const T* x, std::size_t n) noexcept {
97 T acc = T(0);
98 for (std::size_t i = 0; i < n; ++i)
99 acc += x[i] * x[i];
100 return acc;
101}
102
103template <typename T> inline T max_abs_impl(const T* x, std::size_t n) noexcept {
104 T m = T(0);
105 for (std::size_t i = 0; i < n; ++i)
106 m = std::max(m, std::abs(x[i]));
107 return m;
108}
109
110template <typename T>
111inline void ramp_mul_impl(const T* x, T start, T step, T* dst, std::size_t n) noexcept {
112 for (std::size_t i = 0; i < n; ++i)
113 dst[i] = x[i] * (start + T(i) * step);
114}
115
116template <typename T>
117inline void correlate_impl(const T* x, const T* h, T* y, std::size_t n_out,
118 std::size_t taps) noexcept {
119 for (std::size_t i = 0; i < n_out; ++i)
120 y[i] = dot_impl(x + i, h, taps);
121}
122
123template <typename T>
124inline void decimate2_impl(const T* x, const T* h, T* y, std::size_t n_out,
125 std::size_t taps) noexcept {
126 for (std::size_t i = 0; i < n_out; ++i)
127 y[i] = dot_impl(x + 2 * i, h, taps);
128}
129
130} // namespace pulp::simd::detail
131
132// Defines every kernel overload for element type T in the current namespace.
133// SPEC is `inline` for the header fallback and empty for the compiled backend.
134#define PULP_SIMD_SCALAR_DEFINE(SPEC, T) \
135 SPEC void add(const T* a, const T* b, T* dst, std::size_t n) noexcept { \
136 ::pulp::simd::detail::add_impl(a, b, dst, n); \
137 } \
138 SPEC void mul(const T* a, const T* b, T* dst, std::size_t n) noexcept { \
139 ::pulp::simd::detail::mul_impl(a, b, dst, n); \
140 } \
141 SPEC void fma(const T* a, const T* b, const T* c, T* dst, std::size_t n) noexcept { \
142 ::pulp::simd::detail::fma_impl(a, b, c, dst, n); \
143 } \
144 SPEC void set(T value, T* dst, std::size_t n) noexcept { \
145 ::pulp::simd::detail::set_impl(value, dst, n); \
146 } \
147 SPEC void scale(const T* a, T s, T* dst, std::size_t n) noexcept { \
148 ::pulp::simd::detail::scale_impl(a, s, dst, n); \
149 } \
150 SPEC void add_scaled(const T* a, T s, T* dst, std::size_t n) noexcept { \
151 ::pulp::simd::detail::add_scaled_impl(a, s, dst, n); \
152 } \
153 SPEC T sum(const T* x, std::size_t n) noexcept { \
154 return ::pulp::simd::detail::sum_impl(x, n); \
155 } \
156 SPEC T maximum(const T* x, std::size_t n) noexcept { \
157 return ::pulp::simd::detail::maximum_impl(x, n); \
158 } \
159 SPEC T minimum(const T* x, std::size_t n) noexcept { \
160 return ::pulp::simd::detail::minimum_impl(x, n); \
161 } \
162 SPEC void abs(const T* a, T* dst, std::size_t n) noexcept { \
163 ::pulp::simd::detail::abs_impl(a, dst, n); \
164 } \
165 SPEC void clamp(const T* a, T lo, T hi, T* dst, std::size_t n) noexcept { \
166 ::pulp::simd::detail::clamp_impl(a, lo, hi, dst, n); \
167 } \
168 SPEC T dot(const T* a, const T* b, std::size_t n) noexcept { \
169 return ::pulp::simd::detail::dot_impl(a, b, n); \
170 } \
171 SPEC T sum_squares(const T* x, std::size_t n) noexcept { \
172 return ::pulp::simd::detail::sum_squares_impl(x, n); \
173 } \
174 SPEC T max_abs(const T* x, std::size_t n) noexcept { \
175 return ::pulp::simd::detail::max_abs_impl(x, n); \
176 } \
177 SPEC void ramp_mul(const T* x, T start, T step, T* dst, std::size_t n) noexcept { \
178 ::pulp::simd::detail::ramp_mul_impl(x, start, step, dst, n); \
179 } \
180 SPEC void correlate(const T* x, const T* h, T* y, std::size_t n_out, \
181 std::size_t taps) noexcept { \
182 ::pulp::simd::detail::correlate_impl(x, h, y, n_out, taps); \
183 } \
184 SPEC void decimate2(const T* x, const T* h, T* y, std::size_t n_out, \
185 std::size_t taps) noexcept { \
186 ::pulp::simd::detail::decimate2_impl(x, h, y, n_out, taps); \
187 }
Definition scalar_kernels.hpp:20
void add_scaled_impl(const T *a, T s, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:48
T dot_impl(const T *a, const T *b, std::size_t n) noexcept
Definition scalar_kernels.hpp:89
void scale_impl(const T *a, T s, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:43
T max_abs_impl(const T *x, std::size_t n) noexcept
Definition scalar_kernels.hpp:103
T minimum_impl(const T *x, std::size_t n) noexcept
Definition scalar_kernels.hpp:69
T sum_squares_impl(const T *x, std::size_t n) noexcept
Definition scalar_kernels.hpp:96
void decimate2_impl(const T *x, const T *h, T *y, std::size_t n_out, std::size_t taps) noexcept
Definition scalar_kernels.hpp:124
T sum_impl(const T *x, std::size_t n) noexcept
Definition scalar_kernels.hpp:53
void add_impl(const T *a, const T *b, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:22
void clamp_impl(const T *a, T lo, T hi, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:84
T maximum_impl(const T *x, std::size_t n) noexcept
Definition scalar_kernels.hpp:60
void mul_impl(const T *a, const T *b, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:27
void abs_impl(const T *a, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:78
void ramp_mul_impl(const T *x, T start, T step, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:111
void set_impl(T value, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:38
void correlate_impl(const T *x, const T *h, T *y, std::size_t n_out, std::size_t taps) noexcept
Definition scalar_kernels.hpp:117
void fma_impl(const T *a, const T *b, const T *c, T *dst, std::size_t n) noexcept
Definition scalar_kernels.hpp:33