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.

265 lines
10KB

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