|
|
@@ -61,21 +61,24 @@ template <typename Type> |
|
|
|
struct SIMDRegister
|
|
|
|
{
|
|
|
|
//==============================================================================
|
|
|
|
/** The type that represents the individual constituents of the SIMD Register */
|
|
|
|
typedef Type ElementType;
|
|
|
|
|
|
|
|
/** STL compatible value_type definition (same as ElementType). */
|
|
|
|
typedef ElementType value_type;
|
|
|
|
|
|
|
|
/** The corresponding primitive integer type, for example, this will be int32_t
|
|
|
|
if type is a float. */
|
|
|
|
typedef typename SIMDInternal::MaskTypeFor<Type>::type MaskType;
|
|
|
|
typedef typename SIMDInternal::MaskTypeFor<ElementType>::type MaskType;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
// Here are some types which are needed internally
|
|
|
|
|
|
|
|
/** The native primitive type (used internally). */
|
|
|
|
typedef typename SIMDInternal::PrimitiveType<Type>::type ElementType;
|
|
|
|
|
|
|
|
/** STL compatible value_type definition. */
|
|
|
|
typedef typename SIMDInternal::PrimitiveType<Type>::type value_type;
|
|
|
|
typedef typename SIMDInternal::PrimitiveType<ElementType>::type PrimitiveType;
|
|
|
|
|
|
|
|
/** The native operations for this platform and type combination (used internally) */
|
|
|
|
typedef SIMDNativeOps<ElementType> NativeOps;
|
|
|
|
typedef SIMDNativeOps<PrimitiveType> NativeOps;
|
|
|
|
|
|
|
|
/** The native type (used internally). */
|
|
|
|
typedef typename NativeOps::vSIMDType vSIMDType;
|
|
|
@@ -88,14 +91,14 @@ struct SIMDRegister |
|
|
|
|
|
|
|
/** Wrapper for operations which need to be handled differently for complex
|
|
|
|
and scalar types (used internally). */
|
|
|
|
typedef CmplxSIMDOps<Type> CmplxOps;
|
|
|
|
typedef CmplxSIMDOps<ElementType> CmplxOps;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** The size in bytes of this register. */
|
|
|
|
static constexpr size_t SIMDRegisterSize = sizeof (vSIMDType);
|
|
|
|
|
|
|
|
/** The number of elements that this vector can hold. */
|
|
|
|
static constexpr size_t SIMDNumElements = SIMDRegisterSize / sizeof (Type);
|
|
|
|
static constexpr size_t SIMDNumElements = SIMDRegisterSize / sizeof (ElementType);
|
|
|
|
|
|
|
|
vSIMDType value;
|
|
|
|
|
|
|
@@ -106,7 +109,7 @@ struct SIMDRegister |
|
|
|
//==============================================================================
|
|
|
|
/** Creates a new SIMDRegister from the corresponding scalar primitive.
|
|
|
|
The scalar is extended to all elements of the vector. */
|
|
|
|
inline static SIMDRegister JUCE_VECTOR_CALLTYPE expand (Type s) noexcept { return {CmplxOps::expand (s)}; }
|
|
|
|
inline static SIMDRegister JUCE_VECTOR_CALLTYPE expand (ElementType s) noexcept { return {CmplxOps::expand (s)}; }
|
|
|
|
|
|
|
|
/** Creates a new SIMDRegister from the internal SIMD type (for example
|
|
|
|
__mm128 for single-precision floating point on SSE architectures). */
|
|
|
@@ -115,18 +118,18 @@ struct SIMDRegister |
|
|
|
//==============================================================================
|
|
|
|
/** Returns the idx-th element of the receiver. Note that this does not check if idx
|
|
|
|
is larger than the native register size. */
|
|
|
|
inline Type JUCE_VECTOR_CALLTYPE operator[] (size_t idx) const noexcept
|
|
|
|
inline ElementType JUCE_VECTOR_CALLTYPE operator[] (size_t idx) const noexcept
|
|
|
|
{
|
|
|
|
jassert (idx < SIMDNumElements);
|
|
|
|
return reinterpret_cast<const Type*> (&value) [idx];
|
|
|
|
return reinterpret_cast<const ElementType*> (&value) [idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the idx-th element of the receiver. Note that this does not check if idx
|
|
|
|
is larger than the native register size. */
|
|
|
|
inline Type& JUCE_VECTOR_CALLTYPE operator[] (size_t idx) noexcept
|
|
|
|
inline ElementType& JUCE_VECTOR_CALLTYPE operator[] (size_t idx) noexcept
|
|
|
|
{
|
|
|
|
jassert (idx < SIMDNumElements);
|
|
|
|
return reinterpret_cast<Type*> (&value) [idx];
|
|
|
|
return reinterpret_cast<ElementType*> (&value) [idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
@@ -141,16 +144,16 @@ struct SIMDRegister |
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** Broadcasts the scalar to all elements of the receiver. */
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator= (Type s) noexcept { value = CmplxOps::expand (s); return *this; }
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator= (ElementType s) noexcept { value = CmplxOps::expand (s); return *this; }
|
|
|
|
|
|
|
|
/** Adds a scalar to the receiver. */
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator+= (Type s) noexcept { value = NativeOps::add (value, CmplxOps::expand (s)); return *this; }
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator+= (ElementType s) noexcept { value = NativeOps::add (value, CmplxOps::expand (s)); return *this; }
|
|
|
|
|
|
|
|
/** Subtracts a scalar to the receiver. */
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator-= (Type s) noexcept { value = NativeOps::sub (value, CmplxOps::expand (s)); return *this; }
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator-= (ElementType s) noexcept { value = NativeOps::sub (value, CmplxOps::expand (s)); return *this; }
|
|
|
|
|
|
|
|
/** Multiplies a scalar to the receiver. */
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator*= (Type s) noexcept { value = CmplxOps::mul (value, CmplxOps::expand (s)); return *this; }
|
|
|
|
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator*= (ElementType s) noexcept { value = CmplxOps::mul (value, CmplxOps::expand (s)); return *this; }
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** Bit-and the reciver with SIMDRegister v and store the result in the receiver. */
|
|
|
@@ -184,13 +187,13 @@ struct SIMDRegister |
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** Returns a vector where each element is the sum of the corresponding element in the receiver and the scalar s.*/
|
|
|
|
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator+ (Type s) const noexcept { return { NativeOps::add (value, CmplxOps::expand (s)) }; }
|
|
|
|
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator+ (ElementType s) const noexcept { return { NativeOps::add (value, CmplxOps::expand (s)) }; }
|
|
|
|
|
|
|
|
/** Returns a vector where each element is the difference of the corresponding element in the receiver and the scalar s.*/
|
|
|
|
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator- (Type s) const noexcept { return { NativeOps::sub (value, CmplxOps::expand (s)) }; }
|
|
|
|
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator- (ElementType s) const noexcept { return { NativeOps::sub (value, CmplxOps::expand (s)) }; }
|
|
|
|
|
|
|
|
/** Returns a vector where each element is the difference of the corresponding element in the receiver and the scalar s.*/
|
|
|
|
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator* (Type s) const noexcept { return { CmplxOps::mul (value, CmplxOps::expand (s)) }; }
|
|
|
|
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator* (ElementType s) const noexcept { return { CmplxOps::mul (value, CmplxOps::expand (s)) }; }
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** Returns the bit-and of the receiver and v. */
|
|
|
@@ -262,11 +265,11 @@ struct SIMDRegister |
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** Returns a scalar which is the sum of all elements of the receiver. */
|
|
|
|
inline Type sum() const noexcept { return CmplxOps::sum (value); }
|
|
|
|
inline ElementType sum() const noexcept { return CmplxOps::sum (value); }
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** Checks if the given pointer is suffeciently aligned for using SIMD operations. */
|
|
|
|
static inline bool isSIMDAligned (Type* ptr) noexcept
|
|
|
|
static inline bool isSIMDAligned (ElementType* ptr) noexcept
|
|
|
|
{
|
|
|
|
uintptr_t bitmask = SIMDRegisterSize - 1;
|
|
|
|
return (reinterpret_cast<uintptr_t> (ptr) & bitmask) == 0;
|
|
|
@@ -277,7 +280,7 @@ struct SIMDRegister |
|
|
|
If the current position in memory is already aligned then this method
|
|
|
|
will simply return the pointer.
|
|
|
|
*/
|
|
|
|
static inline Type* getNextSIMDAlignedPtr (Type* ptr) noexcept
|
|
|
|
static inline ElementType* getNextSIMDAlignedPtr (ElementType* ptr) noexcept
|
|
|
|
{
|
|
|
|
return snapPointerToAlignment (ptr, SIMDRegisterSize);
|
|
|
|
}
|
|
|
|