OpenShot Library | OpenShotAudio  0.2.1
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 
27 namespace juce
28 {
29 namespace dsp
30 {
31 
32 /** A template specialisation to find corresponding mask type for primitives. */
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 
53 /**
54  Useful fallback routines to use if the native SIMD op is not supported. You
55  should never need to use this directly. Use juce_SIMDRegister instead.
56 
57  @tags{DSP}
58 */
59 template <typename ScalarType, typename vSIMDType>
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
STL namespace.
Useful fallback routines to use if the native SIMD op is not supported.