The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. namespace dsp
  22. {
  23. /** A template specialisation to find corresponding mask type for primitives. */
  24. namespace SIMDInternal
  25. {
  26. template <typename Primitive> struct MaskTypeFor { typedef Primitive type; };
  27. template <> struct MaskTypeFor <float> { typedef uint32_t type; };
  28. template <> struct MaskTypeFor <double> { typedef uint64_t type; };
  29. template <> struct MaskTypeFor <char> { typedef uint8_t type; };
  30. template <> struct MaskTypeFor <int8_t> { typedef uint8_t type; };
  31. template <> struct MaskTypeFor <int16_t> { typedef uint16_t type; };
  32. template <> struct MaskTypeFor <int32_t> { typedef uint32_t type; };
  33. template <> struct MaskTypeFor <int64_t> { typedef uint64_t type; };
  34. template <> struct MaskTypeFor <std::complex<float>> { typedef uint32_t type; };
  35. template <> struct MaskTypeFor <std::complex<double>> { typedef uint64_t type; };
  36. template <typename Primitive> struct PrimitiveType { typedef Primitive type; };
  37. template <typename Primitive> struct PrimitiveType<std::complex<Primitive>> { typedef Primitive type; };
  38. template <int n> struct Log2Helper { enum { value = Log2Helper<n/2>::value + 1 }; };
  39. template <> struct Log2Helper<1> { enum { value = 0 }; };
  40. }
  41. /**
  42. Useful fallback routines to use if the native SIMD op is not supported. You
  43. should never need to use this directly. Use juce_SIMDRegister instead.
  44. @tags{DSP}
  45. */
  46. template <typename ScalarType, typename vSIMDType>
  47. struct SIMDFallbackOps
  48. {
  49. static constexpr size_t n = sizeof (vSIMDType) / sizeof (ScalarType);
  50. static constexpr size_t mask = (sizeof (vSIMDType) / sizeof (ScalarType)) - 1;
  51. static constexpr size_t bits = SIMDInternal::Log2Helper<n>::value;
  52. // helper types
  53. using MaskType = typename SIMDInternal::MaskTypeFor<ScalarType>::type;
  54. union UnionType { vSIMDType v; ScalarType s[n]; };
  55. union UnionMaskType { vSIMDType v; MaskType m[n]; };
  56. // fallback methods
  57. static forcedinline vSIMDType add (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarAdd> (a, b); }
  58. static forcedinline vSIMDType sub (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarSub> (a, b); }
  59. static forcedinline vSIMDType mul (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMul> (a, b); }
  60. static forcedinline vSIMDType bit_and (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarAnd> (a, b); }
  61. static forcedinline vSIMDType bit_or (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarOr > (a, b); }
  62. static forcedinline vSIMDType bit_xor (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarXor> (a, b); }
  63. static forcedinline vSIMDType bit_notand (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarNot> (a, b); }
  64. static forcedinline vSIMDType min (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMin> (a, b); }
  65. static forcedinline vSIMDType max (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMax> (a, b); }
  66. static forcedinline vSIMDType equal (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarEq > (a, b); }
  67. static forcedinline vSIMDType notEqual (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarNeq> (a, b); }
  68. static forcedinline vSIMDType greaterThan (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarGt > (a, b); }
  69. static forcedinline vSIMDType greaterThanOrEqual (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarGeq> (a, b); }
  70. static forcedinline ScalarType get (vSIMDType v, size_t i) noexcept
  71. {
  72. UnionType u {v};
  73. return u.s[i];
  74. }
  75. static forcedinline vSIMDType set (vSIMDType v, size_t i, ScalarType s) noexcept
  76. {
  77. UnionType u {v};
  78. u.s[i] = s;
  79. return u.v;
  80. }
  81. static forcedinline vSIMDType bit_not (vSIMDType av) noexcept
  82. {
  83. UnionMaskType a {av};
  84. for (size_t i = 0; i < n; ++i)
  85. a.m[i] = ~a.m[i];
  86. return a.v;
  87. }
  88. static forcedinline ScalarType sum (vSIMDType av) noexcept
  89. {
  90. UnionType a {av};
  91. auto retval = static_cast<ScalarType> (0);
  92. for (size_t i = 0; i < n; ++i)
  93. retval += a.s[i];
  94. return retval;
  95. }
  96. static forcedinline vSIMDType multiplyAdd (vSIMDType av, vSIMDType bv, vSIMDType cv) noexcept
  97. {
  98. UnionType a {av}, b {bv}, c {cv};
  99. for (size_t i = 0; i < n; ++i)
  100. a.s[i] += b.s[i] * c.s[i];
  101. return a.v;
  102. }
  103. //==============================================================================
  104. static forcedinline bool allEqual (vSIMDType av, vSIMDType bv) noexcept
  105. {
  106. UnionType a {av}, b {bv};
  107. for (size_t i = 0; i < n; ++i)
  108. if (a.s[i] != b.s[i])
  109. return false;
  110. return true;
  111. }
  112. //==============================================================================
  113. static forcedinline vSIMDType cmplxmul (vSIMDType av, vSIMDType bv) noexcept
  114. {
  115. UnionType a {av}, b {bv}, r;
  116. const int m = n >> 1;
  117. for (int i = 0; i < m; ++i)
  118. {
  119. std::complex<ScalarType> result
  120. = std::complex<ScalarType> (a.s[i<<1], a.s[(i<<1)|1])
  121. * std::complex<ScalarType> (b.s[i<<1], b.s[(i<<1)|1]);
  122. r.s[i<<1] = result.real();
  123. r.s[(i<<1)|1] = result.imag();
  124. }
  125. return r.v;
  126. }
  127. struct ScalarAdd { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a + b; } };
  128. struct ScalarSub { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a - b; } };
  129. struct ScalarMul { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a * b; } };
  130. struct ScalarMin { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return jmin (a, b); } };
  131. struct ScalarMax { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return jmax (a, b); } };
  132. struct ScalarAnd { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a & b; } };
  133. struct ScalarOr { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a | b; } };
  134. struct ScalarXor { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a ^ b; } };
  135. struct ScalarNot { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return (~a) & b; } };
  136. struct ScalarEq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a == b); } };
  137. struct ScalarNeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a != b); } };
  138. struct ScalarGt { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a > b); } };
  139. struct ScalarGeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a >= b); } };
  140. // generic apply routines for operations above
  141. template <typename Op>
  142. static forcedinline vSIMDType apply (vSIMDType av, vSIMDType bv) noexcept
  143. {
  144. UnionType a {av}, b {bv};
  145. for (size_t i = 0; i < n; ++i)
  146. a.s[i] = Op::op (a.s[i], b.s[i]);
  147. return a.v;
  148. }
  149. template <typename Op>
  150. static forcedinline vSIMDType cmp (vSIMDType av, vSIMDType bv) noexcept
  151. {
  152. UnionType a {av}, b {bv};
  153. UnionMaskType r;
  154. for (size_t i = 0; i < n; ++i)
  155. r.m[i] = Op::op (a.s[i], b.s[i]) ? static_cast<MaskType> (-1) : static_cast<MaskType> (0);
  156. return r.v;
  157. }
  158. template <typename Op>
  159. static forcedinline vSIMDType bitapply (vSIMDType av, vSIMDType bv) noexcept
  160. {
  161. UnionMaskType a {av}, b {bv};
  162. for (size_t i = 0; i < n; ++i)
  163. a.m[i] = Op::op (a.m[i], b.m[i]);
  164. return a.v;
  165. }
  166. static forcedinline vSIMDType expand (ScalarType s) noexcept
  167. {
  168. UnionType r;
  169. for (size_t i = 0; i < n; ++i)
  170. r.s[i] = s;
  171. return r.v;
  172. }
  173. static forcedinline vSIMDType load (const ScalarType* a) noexcept
  174. {
  175. UnionType r;
  176. for (size_t i = 0; i < n; ++i)
  177. r.s[i] = a[i];
  178. return r.v;
  179. }
  180. static forcedinline void store (vSIMDType av, ScalarType* dest) noexcept
  181. {
  182. UnionType a {av};
  183. for (size_t i = 0; i < n; ++i)
  184. dest[i] = a.s[i];
  185. }
  186. template <unsigned int shuffle_idx>
  187. static forcedinline vSIMDType shuffle (vSIMDType av) noexcept
  188. {
  189. UnionType a {av}, r;
  190. // the compiler will unroll this loop and the index can
  191. // be computed at compile-time, so this will be super fast
  192. for (size_t i = 0; i < n; ++i)
  193. r.s[i] = a.s[(shuffle_idx >> (bits * i)) & mask];
  194. return r.v;
  195. }
  196. };
  197. } // namespace dsp
  198. } // namespace juce