OpenShot Audio Library | OpenShotAudio: juce_fallback_SIMDNativeOps.h Source File

OpenShot Audio Library | OpenShotAudio 0.3.0

Loading...
Searching...
No Matches
juce_fallback_SIMDNativeOps.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11 Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12 27th April 2017).
13
14 End User License Agreement: www.juce.com/juce-5-licence
15 Privacy Policy: www.juce.com/juce-5-privacy-policy
16
17 Or: You may also use this code under the terms of the GPL v3 (see
18 www.gnu.org/licenses).
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29namespace dsp
30{
31
33 namespace SIMDInternal
34{
35 template <typename Primitive> struct MaskTypeFor { using type = Primitive; };
36 template <> struct MaskTypeFor <float> { using type = uint32_t; };
37 template <> struct MaskTypeFor <double> { using type = uint64_t; };
38 template <> struct MaskTypeFor <char> { using type = uint8_t; };
39 template <> struct MaskTypeFor <int8_t> { using type = uint8_t; };
40 template <> struct MaskTypeFor <int16_t> { using type = uint16_t; };
41 template <> struct MaskTypeFor <int32_t> { using type = uint32_t; };
42 template <> struct MaskTypeFor <int64_t> { using type = uint64_t; };
43 template <> struct MaskTypeFor <std::complex<float>> { using type = uint32_t; };
44 template <> struct MaskTypeFor <std::complex<double>> { using type = uint64_t; };
45
46 template <typename Primitive> struct PrimitiveType { using type = typename std::remove_cv<Primitive>::type; };
47 template <typename Primitive> struct PrimitiveType<std::complex<Primitive>> { using type = typename std::remove_cv<Primitive>::type; };
48
49 template <int n> struct Log2Helper { enum { value = Log2Helper<n/2>::value + 1 }; };
50 template <> struct Log2Helper<1> { enum { value = 0 }; };
51}
52
59template <typename ScalarType, typename vSIMDType>
60 struct SIMDFallbackOps
61{
62 static constexpr size_t n = sizeof (vSIMDType) / sizeof (ScalarType);
63 static constexpr size_t mask = (sizeof (vSIMDType) / sizeof (ScalarType)) - 1;
64 static constexpr size_t bits = SIMDInternal::Log2Helper<(int) n>::value;
65
66 // helper types
67 using MaskType = typename SIMDInternal::MaskTypeFor<ScalarType>::type;
68 union UnionType { vSIMDType v; ScalarType s[n]; };
69 union UnionMaskType { vSIMDType v; MaskType m[n]; };
70
71
72 // fallback methods
73 static forcedinline vSIMDType add (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarAdd> (a, b); }
74 static forcedinline vSIMDType sub (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarSub> (a, b); }
75 static forcedinline vSIMDType mul (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMul> (a, b); }
76 static forcedinline vSIMDType bit_and (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarAnd> (a, b); }
77 static forcedinline vSIMDType bit_or (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarOr > (a, b); }
78 static forcedinline vSIMDType bit_xor (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarXor> (a, b); }
79 static forcedinline vSIMDType bit_notand (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarNot> (a, b); }
80
81 static forcedinline vSIMDType min (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMin> (a, b); }
82 static forcedinline vSIMDType max (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMax> (a, b); }
83 static forcedinline vSIMDType equal (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarEq > (a, b); }
84 static forcedinline vSIMDType notEqual (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarNeq> (a, b); }
85 static forcedinline vSIMDType greaterThan (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarGt > (a, b); }
86 static forcedinline vSIMDType greaterThanOrEqual (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarGeq> (a, b); }
87
88 static forcedinline ScalarType get (vSIMDType v, size_t i) noexcept
89 {
90 UnionType u {v};
91 return u.s[i];
92 }
93
94 static forcedinline vSIMDType set (vSIMDType v, size_t i, ScalarType s) noexcept
95 {
96 UnionType u {v};
97
98 u.s[i] = s;
99 return u.v;
100 }
101
102 static forcedinline vSIMDType bit_not (vSIMDType av) noexcept
103 {
104 UnionMaskType a {av};
105
106 for (size_t i = 0; i < n; ++i)
107 a.m[i] = ~a.m[i];
108
109 return a.v;
110 }
111
112 static forcedinline ScalarType sum (vSIMDType av) noexcept
113 {
114 UnionType a {av};
115 auto retval = static_cast<ScalarType> (0);
116
117 for (size_t i = 0; i < n; ++i)
118 retval += a.s[i];
119
120 return retval;
121 }
122
123 static forcedinline vSIMDType truncate (vSIMDType av) noexcept
124 {
125 UnionType a {av};
126
127 for (size_t i = 0; i < n; ++i)
128 {
129 jassert (a.s[i] >= ScalarType (0));
130 a.s[i] = static_cast <ScalarType> (static_cast<int> (a.s[i]));
131 }
132
133 return a.v;
134 }
135
136 static forcedinline vSIMDType multiplyAdd (vSIMDType av, vSIMDType bv, vSIMDType cv) noexcept
137 {
138 UnionType a {av}, b {bv}, c {cv};
139
140 for (size_t i = 0; i < n; ++i)
141 a.s[i] += b.s[i] * c.s[i];
142
143 return a.v;
144 }
145
146 //==============================================================================
147 static forcedinline bool allEqual (vSIMDType av, vSIMDType bv) noexcept
148 {
149 UnionType a {av}, b {bv};
150
151 for (size_t i = 0; i < n; ++i)
152 if (a.s[i] != b.s[i])
153 return false;
154
155 return true;
156 }
157
158 //==============================================================================
159 static forcedinline vSIMDType cmplxmul (vSIMDType av, vSIMDType bv) noexcept
160 {
161 UnionType a {av}, b {bv}, r;
162
163 const int m = n >> 1;
164 for (int i = 0; i < m; ++i)
165 {
166 std::complex<ScalarType> result
167 = std::complex<ScalarType> (a.s[i<<1], a.s[(i<<1)|1])
168 * std::complex<ScalarType> (b.s[i<<1], b.s[(i<<1)|1]);
169
170 r.s[i<<1] = result.real();
171 r.s[(i<<1)|1] = result.imag();
172 }
173
174 return r.v;
175 }
176
177 struct ScalarAdd { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a + b; } };
178 struct ScalarSub { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a - b; } };
179 struct ScalarMul { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a * b; } };
180 struct ScalarMin { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return jmin (a, b); } };
181 struct ScalarMax { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return jmax (a, b); } };
182 struct ScalarAnd { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a & b; } };
183 struct ScalarOr { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a | b; } };
184 struct ScalarXor { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a ^ b; } };
185 struct ScalarNot { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return (~a) & b; } };
186 struct ScalarEq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a == b); } };
187 struct ScalarNeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a != b); } };
188 struct ScalarGt { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a > b); } };
189 struct ScalarGeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a >= b); } };
190
191 // generic apply routines for operations above
192 template <typename Op>
193 static forcedinline vSIMDType apply (vSIMDType av, vSIMDType bv) noexcept
194 {
195 UnionType a {av}, b {bv};
196
197 for (size_t i = 0; i < n; ++i)
198 a.s[i] = Op::op (a.s[i], b.s[i]);
199
200 return a.v;
201 }
202
203 template <typename Op>
204 static forcedinline vSIMDType cmp (vSIMDType av, vSIMDType bv) noexcept
205 {
206 UnionType a {av}, b {bv};
207 UnionMaskType r;
208
209 for (size_t i = 0; i < n; ++i)
210 r.m[i] = Op::op (a.s[i], b.s[i]) ? static_cast<MaskType> (-1) : static_cast<MaskType> (0);
211
212 return r.v;
213 }
214
215 template <typename Op>
216 static forcedinline vSIMDType bitapply (vSIMDType av, vSIMDType bv) noexcept
217 {
218 UnionMaskType a {av}, b {bv};
219
220 for (size_t i = 0; i < n; ++i)
221 a.m[i] = Op::op (a.m[i], b.m[i]);
222
223 return a.v;
224 }
225
226 static forcedinline vSIMDType expand (ScalarType s) noexcept
227 {
228 UnionType r;
229
230 for (size_t i = 0; i < n; ++i)
231 r.s[i] = s;
232
233 return r.v;
234 }
235
236 static forcedinline vSIMDType load (const ScalarType* a) noexcept
237 {
238 UnionType r;
239
240 for (size_t i = 0; i < n; ++i)
241 r.s[i] = a[i];
242
243 return r.v;
244 }
245
246 static forcedinline void store (vSIMDType av, ScalarType* dest) noexcept
247 {
248 UnionType a {av};
249
250 for (size_t i = 0; i < n; ++i)
251 dest[i] = a.s[i];
252 }
253
254 template <unsigned int shuffle_idx>
255 static forcedinline vSIMDType shuffle (vSIMDType av) noexcept
256 {
257 UnionType a {av}, r;
258
259 // the compiler will unroll this loop and the index can
260 // be computed at compile-time, so this will be super fast
261 for (size_t i = 0; i < n; ++i)
262 r.s[i] = a.s[(shuffle_idx >> (bits * i)) & mask];
263
264 return r.v;
265 }
266};
267
268} // namespace dsp
269} // namespace juce
juce::dsp::SIMDFallbackOps
Definition: juce_fallback_SIMDNativeOps.h:61