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.

221 lines
10.0KB

  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. */
  45. template <typename ScalarType, typename vSIMDType>
  46. struct SIMDFallbackOps
  47. {
  48. static constexpr size_t n = sizeof (vSIMDType) / sizeof (ScalarType);
  49. static constexpr size_t mask = (sizeof (vSIMDType) / sizeof (ScalarType)) - 1;
  50. static constexpr size_t bits = SIMDInternal::Log2Helper<n>::value;
  51. // corresponding mask type
  52. typedef typename SIMDInternal::MaskTypeFor<ScalarType>::type MaskType;
  53. // fallback methods
  54. static forcedinline vSIMDType add (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarAdd> (a, b); }
  55. static forcedinline vSIMDType sub (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarSub> (a, b); }
  56. static forcedinline vSIMDType mul (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMul> (a, b); }
  57. static forcedinline vSIMDType bit_and (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarAnd> (a, b); }
  58. static forcedinline vSIMDType bit_or (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarOr > (a, b); }
  59. static forcedinline vSIMDType bit_xor (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarXor> (a, b); }
  60. static forcedinline vSIMDType bit_notand (vSIMDType a, vSIMDType b) noexcept { return bitapply<ScalarNot> (a, b); }
  61. static forcedinline vSIMDType min (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMin> (a, b); }
  62. static forcedinline vSIMDType max (vSIMDType a, vSIMDType b) noexcept { return apply<ScalarMax> (a, b); }
  63. static forcedinline vSIMDType equal (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarEq > (a, b); }
  64. static forcedinline vSIMDType notEqual (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarNeq> (a, b); }
  65. static forcedinline vSIMDType greaterThan (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarGt > (a, b); }
  66. static forcedinline vSIMDType greaterThanOrEqual (vSIMDType a, vSIMDType b) noexcept { return cmp<ScalarGeq> (a, b); }
  67. static forcedinline vSIMDType bit_not (vSIMDType a) noexcept
  68. {
  69. vSIMDType retval;
  70. auto* dst = reinterpret_cast<MaskType*> (&retval);
  71. auto* aSrc = reinterpret_cast<const MaskType*> (&a);
  72. for (size_t i = 0; i < n; ++i)
  73. dst [i] = ~aSrc [i];
  74. return retval;
  75. }
  76. static forcedinline ScalarType sum (vSIMDType a) noexcept
  77. {
  78. auto retval = static_cast<ScalarType> (0);
  79. auto* aSrc = reinterpret_cast<const ScalarType*> (&a);
  80. for (size_t i = 0; i < n; ++i)
  81. retval += aSrc [i];
  82. return retval;
  83. }
  84. static forcedinline vSIMDType multiplyAdd (vSIMDType a, vSIMDType b, vSIMDType c) noexcept
  85. {
  86. vSIMDType retval;
  87. auto* dst = reinterpret_cast<ScalarType*> (&retval);
  88. auto* aSrc = reinterpret_cast<const ScalarType*> (&a);
  89. auto* bSrc = reinterpret_cast<const ScalarType*> (&b);
  90. auto* cSrc = reinterpret_cast<const ScalarType*> (&c);
  91. for (size_t i = 0; i < n; ++i)
  92. dst [i] = aSrc [i] + (bSrc [i] * cSrc [i]);
  93. return retval;
  94. }
  95. //==============================================================================
  96. static forcedinline vSIMDType cmplxmul (vSIMDType a, vSIMDType b) noexcept
  97. {
  98. vSIMDType retval;
  99. auto* dst = reinterpret_cast<std::complex<ScalarType>*> (&retval);
  100. auto* aSrc = reinterpret_cast<const std::complex<ScalarType>*> (&a);
  101. auto* bSrc = reinterpret_cast<const std::complex<ScalarType>*> (&b);
  102. const int m = n >> 1;
  103. for (int i = 0; i < m; ++i)
  104. dst [i] = aSrc [i] * bSrc [i];
  105. return retval;
  106. }
  107. struct ScalarAdd { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a + b; } };
  108. struct ScalarSub { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a - b; } };
  109. struct ScalarMul { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return a * b; } };
  110. struct ScalarMin { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return jmin (a, b); } };
  111. struct ScalarMax { static forcedinline ScalarType op (ScalarType a, ScalarType b) noexcept { return jmax (a, b); } };
  112. struct ScalarAnd { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a & b; } };
  113. struct ScalarOr { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a | b; } };
  114. struct ScalarXor { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a ^ b; } };
  115. struct ScalarNot { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return (~a) & b; } };
  116. struct ScalarEq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a == b); } };
  117. struct ScalarNeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a != b); } };
  118. struct ScalarGt { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a > b); } };
  119. struct ScalarGeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a >= b); } };
  120. // generic apply routines for operations above
  121. template <typename Op>
  122. static forcedinline vSIMDType apply (vSIMDType a, vSIMDType b) noexcept
  123. {
  124. vSIMDType retval;
  125. auto* dst = reinterpret_cast<ScalarType*> (&retval);
  126. auto* aSrc = reinterpret_cast<const ScalarType*> (&a);
  127. auto* bSrc = reinterpret_cast<const ScalarType*> (&b);
  128. for (size_t i = 0; i < n; ++i)
  129. dst [i] = Op::op (aSrc [i], bSrc [i]);
  130. return retval;
  131. }
  132. template <typename Op>
  133. static forcedinline vSIMDType cmp (vSIMDType a, vSIMDType b) noexcept
  134. {
  135. vSIMDType retval;
  136. auto* dst = reinterpret_cast<MaskType*> (&retval);
  137. auto* aSrc = reinterpret_cast<const ScalarType*> (&a);
  138. auto* bSrc = reinterpret_cast<const ScalarType*> (&b);
  139. for (size_t i = 0; i < n; ++i)
  140. dst [i] = Op::op (aSrc [i], bSrc [i]) ? static_cast<MaskType> (-1) : static_cast<MaskType> (0);
  141. return retval;
  142. }
  143. template <typename Op>
  144. static forcedinline vSIMDType bitapply (vSIMDType a, vSIMDType b) noexcept
  145. {
  146. vSIMDType retval;
  147. auto* dst = reinterpret_cast<MaskType*> (&retval);
  148. auto* aSrc = reinterpret_cast<const MaskType*> (&a);
  149. auto* bSrc = reinterpret_cast<const MaskType*> (&b);
  150. for (size_t i = 0; i < n; ++i)
  151. dst [i] = Op::op (aSrc [i], bSrc [i]);
  152. return retval;
  153. }
  154. static forcedinline vSIMDType expand (ScalarType s) noexcept
  155. {
  156. vSIMDType retval;
  157. auto* dst = reinterpret_cast<ScalarType*> (&retval);
  158. for (size_t i = 0; i < n; ++i)
  159. dst [i] = s;
  160. return retval;
  161. }
  162. template <unsigned int shuffle_idx>
  163. static forcedinline vSIMDType shuffle (vSIMDType a) noexcept
  164. {
  165. vSIMDType retval;
  166. auto* dst = reinterpret_cast<ScalarType*> (&retval);
  167. auto* aSrc = reinterpret_cast<const ScalarType*> (&a);
  168. // the compiler will unroll this loop and the index can
  169. // be computed at compile-time, so this will be super fast
  170. for (size_t i = 0; i < n; ++i)
  171. dst [i] = aSrc [(shuffle_idx >> (bits * i)) & mask];
  172. return retval;
  173. }
  174. };
  175. } // namespace dsp
  176. } // namespace juce