| @@ -19,11 +19,11 @@ struct f32<4> { | |||||
| f32<4>(float x) { | f32<4>(float x) { | ||||
| v = _mm_set_ps1(x); | v = _mm_set_ps1(x); | ||||
| } | } | ||||
| /** Reads an array of 4 values */ | |||||
| /** Reads an array of 4 values. */ | |||||
| f32<4>(const float *x) { | f32<4>(const float *x) { | ||||
| v = _mm_loadu_ps(x); | v = _mm_loadu_ps(x); | ||||
| } | } | ||||
| /** Writes an array of 4 values */ | |||||
| /** Writes an array of 4 values. */ | |||||
| void store(float *x) { | void store(float *x) { | ||||
| _mm_storeu_ps(x, v); | _mm_storeu_ps(x, v); | ||||
| } | } | ||||
| @@ -36,71 +36,73 @@ typedef f32<4> f32_4; | |||||
| // Operator overloads | // Operator overloads | ||||
| #define DECLARE_F32_4_OPERATOR_INFIX(operator, func) \ | #define DECLARE_F32_4_OPERATOR_INFIX(operator, func) \ | ||||
| inline f32_4 operator(f32_4 a, f32_4 b) { \ | |||||
| inline f32_4 operator(const f32_4 &a, const f32_4 &b) { \ | |||||
| return f32_4(func(a.v, b.v)); \ | return f32_4(func(a.v, b.v)); \ | ||||
| } \ | } \ | ||||
| template <typename T> \ | template <typename T> \ | ||||
| f32_4 operator(T a, f32_4 b) { \ | |||||
| f32_4 operator(const T &a, const f32_4 &b) { \ | |||||
| return operator(f32_4(a), b); \ | return operator(f32_4(a), b); \ | ||||
| } \ | } \ | ||||
| template <typename T> \ | template <typename T> \ | ||||
| f32_4 operator(f32_4 a, T b) { \ | |||||
| f32_4 operator(const f32_4 &a, const T &b) { \ | |||||
| return operator(a, f32_4(b)); \ | return operator(a, f32_4(b)); \ | ||||
| } | } | ||||
| DECLARE_F32_4_OPERATOR_INFIX(operator+, _mm_add_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator-, _mm_sub_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator*, _mm_mul_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator/, _mm_div_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator==, _mm_cmpeq_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator>=, _mm_cmpge_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator>, _mm_cmpgt_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator<=, _mm_cmple_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator<, _mm_cmplt_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator!=, _mm_cmpneq_ps) | |||||
| #define DECLARE_F32_4_OPERATOR_INCREMENT(operator, func) \ | #define DECLARE_F32_4_OPERATOR_INCREMENT(operator, func) \ | ||||
| inline f32_4 &operator(f32_4 &a, f32_4 b) { \ | |||||
| inline f32_4 &operator(f32_4 &a, const f32_4 &b) { \ | |||||
| a.v = func(a.v, b.v); \ | a.v = func(a.v, b.v); \ | ||||
| return a; \ | return a; \ | ||||
| } \ | } \ | ||||
| template <typename T> \ | template <typename T> \ | ||||
| f32_4 &operator(f32_4 &a, T b) { \ | |||||
| f32_4 &operator(f32_4 &a, const T &b) { \ | |||||
| return operator(a, f32_4(b)); \ | return operator(a, f32_4(b)); \ | ||||
| } | } | ||||
| DECLARE_F32_4_OPERATOR_INFIX(operator+, _mm_add_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator-, _mm_sub_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator*, _mm_mul_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator/, _mm_div_ps) | |||||
| DECLARE_F32_4_OPERATOR_INCREMENT(operator+=, _mm_add_ps); | DECLARE_F32_4_OPERATOR_INCREMENT(operator+=, _mm_add_ps); | ||||
| DECLARE_F32_4_OPERATOR_INCREMENT(operator-=, _mm_sub_ps); | DECLARE_F32_4_OPERATOR_INCREMENT(operator-=, _mm_sub_ps); | ||||
| DECLARE_F32_4_OPERATOR_INCREMENT(operator*=, _mm_mul_ps); | DECLARE_F32_4_OPERATOR_INCREMENT(operator*=, _mm_mul_ps); | ||||
| DECLARE_F32_4_OPERATOR_INCREMENT(operator/=, _mm_div_ps); | DECLARE_F32_4_OPERATOR_INCREMENT(operator/=, _mm_div_ps); | ||||
| // TODO Perhaps return a future i32 type for these, or add casting between multiple simd types | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator==, _mm_cmpeq_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator>=, _mm_cmpge_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator>, _mm_cmpgt_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator<=, _mm_cmple_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator<, _mm_cmplt_ps) | |||||
| DECLARE_F32_4_OPERATOR_INFIX(operator!=, _mm_cmpneq_ps) | |||||
| inline f32_4 rsqrt(f32_4 a) { | |||||
| return f32_4(_mm_rsqrt_ps(a.v)); | |||||
| } | |||||
| inline f32_4 rcp(f32_4 a) { | |||||
| return f32_4(_mm_rcp_ps(a.v)); | |||||
| inline f32_4 fmax(f32_4 x, f32_4 b) { | |||||
| return f32_4(_mm_max_ps(x.v, b.v)); | |||||
| } | } | ||||
| inline f32_4 fmin(f32_4 x, f32_4 b) { | |||||
| return f32_4(_mm_min_ps(x.v, b.v)); | |||||
| } | |||||
| } // namespace simd | |||||
| } // namespace rack | |||||
| namespace std { | |||||
| inline rack::simd::f32_4 max(rack::simd::f32_4 a, rack::simd::f32_4 b) { | |||||
| return rack::simd::f32_4(_mm_max_ps(a.v, b.v)); | |||||
| inline f32_4 sqrt(f32_4 x) { | |||||
| return f32_4(_mm_sqrt_ps(x.v)); | |||||
| } | } | ||||
| inline rack::simd::f32_4 min(rack::simd::f32_4 a, rack::simd::f32_4 b) { | |||||
| return rack::simd::f32_4(_mm_min_ps(a.v, b.v)); | |||||
| /** Returns the approximate reciprocal square root. | |||||
| Much faster than `1/sqrt(x)`. | |||||
| */ | |||||
| inline f32_4 rsqrt(f32_4 x) { | |||||
| return f32_4(_mm_rsqrt_ps(x.v)); | |||||
| } | } | ||||
| inline rack::simd::f32_4 sqrt(rack::simd::f32_4 a) { | |||||
| return rack::simd::f32_4(_mm_sqrt_ps(a.v)); | |||||
| /** Returns the approximate reciprocal. | |||||
| Much faster than `1/x`. | |||||
| */ | |||||
| inline f32_4 rcp(f32_4 x) { | |||||
| return f32_4(_mm_rcp_ps(x.v)); | |||||
| } | } | ||||
| } // namespace std | |||||
| } // namespace simd | |||||
| } // namespace rack | |||||