mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
This commit is contained in:
@@ -139,8 +139,14 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE;
|
||||
# undef CV_FP16
|
||||
#endif
|
||||
|
||||
#if CV_SSE2 || CV_NEON || CV_VSX
|
||||
#define CV__SIMD_FORWARD 128
|
||||
#include "opencv2/core/hal/intrin_forward.hpp"
|
||||
#endif
|
||||
|
||||
#if CV_SSE2
|
||||
|
||||
#include "opencv2/core/hal/intrin_sse_em.hpp"
|
||||
#include "opencv2/core/hal/intrin_sse.hpp"
|
||||
|
||||
#elif CV_NEON
|
||||
@@ -168,6 +174,8 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE;
|
||||
// (and will be mapped to v256_ counterparts) (e.g. vx_load() => v256_load())
|
||||
#if CV_AVX2
|
||||
|
||||
#define CV__SIMD_FORWARD 256
|
||||
#include "opencv2/core/hal/intrin_forward.hpp"
|
||||
#include "opencv2/core/hal/intrin_avx.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,6 +82,14 @@ inline __m128 _v256_extract_low(const __m256& v)
|
||||
inline __m128d _v256_extract_low(const __m256d& v)
|
||||
{ return _mm256_castpd256_pd128(v); }
|
||||
|
||||
inline __m256i _v256_packs_epu32(const __m256i& a, const __m256i& b)
|
||||
{
|
||||
const __m256i m = _mm256_set1_epi32(65535);
|
||||
__m256i am = _mm256_min_epu32(a, m);
|
||||
__m256i bm = _mm256_min_epu32(b, m);
|
||||
return _mm256_packus_epi32(am, bm);
|
||||
}
|
||||
|
||||
///////// Types ////////////
|
||||
|
||||
struct v_uint8x32
|
||||
@@ -626,10 +634,8 @@ OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int8x32, _mm256_adds_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int8x32, _mm256_subs_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint16x16, _mm256_adds_epu16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint16x16, _mm256_subs_epu16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_uint16x16, _mm256_mullo_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int16x16, _mm256_adds_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int16x16, _mm256_subs_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_int16x16, _mm256_mullo_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint32x8, _mm256_add_epi32)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint32x8, _mm256_sub_epi32)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_uint32x8, _mm256_mullo_epi32)
|
||||
@@ -650,13 +656,103 @@ OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_float64x4, _mm256_sub_pd)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_float64x4, _mm256_mul_pd)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_OP(/, v_float64x4, _mm256_div_pd)
|
||||
|
||||
// saturating multiply 8-bit, 16-bit
|
||||
inline v_uint8x32 operator * (const v_uint8x32& a, const v_uint8x32& b)
|
||||
{
|
||||
v_uint16x16 c, d;
|
||||
v_mul_expand(a, b, c, d);
|
||||
return v_pack_u(v_reinterpret_as_s16(c), v_reinterpret_as_s16(d));
|
||||
}
|
||||
inline v_int8x32 operator * (const v_int8x32& a, const v_int8x32& b)
|
||||
{
|
||||
v_int16x16 c, d;
|
||||
v_mul_expand(a, b, c, d);
|
||||
return v_pack(c, d);
|
||||
}
|
||||
inline v_uint16x16 operator * (const v_uint16x16& a, const v_uint16x16& b)
|
||||
{
|
||||
__m256i pl = _mm256_mullo_epi16(a.val, b.val);
|
||||
__m256i ph = _mm256_mulhi_epu16(a.val, b.val);
|
||||
__m256i p0 = _mm256_unpacklo_epi16(pl, ph);
|
||||
__m256i p1 = _mm256_unpackhi_epi16(pl, ph);
|
||||
return v_uint16x16(_v256_packs_epu32(p0, p1));
|
||||
}
|
||||
inline v_int16x16 operator * (const v_int16x16& a, const v_int16x16& b)
|
||||
{
|
||||
__m256i pl = _mm256_mullo_epi16(a.val, b.val);
|
||||
__m256i ph = _mm256_mulhi_epi16(a.val, b.val);
|
||||
__m256i p0 = _mm256_unpacklo_epi16(pl, ph);
|
||||
__m256i p1 = _mm256_unpackhi_epi16(pl, ph);
|
||||
return v_int16x16(_mm256_packs_epi32(p0, p1));
|
||||
}
|
||||
inline v_uint8x32& operator *= (v_uint8x32& a, const v_uint8x32& b)
|
||||
{ a = a * b; return a; }
|
||||
inline v_int8x32& operator *= (v_int8x32& a, const v_int8x32& b)
|
||||
{ a = a * b; return a; }
|
||||
inline v_uint16x16& operator *= (v_uint16x16& a, const v_uint16x16& b)
|
||||
{ a = a * b; return a; }
|
||||
inline v_int16x16& operator *= (v_int16x16& a, const v_int16x16& b)
|
||||
{ a = a * b; return a; }
|
||||
|
||||
/** Non-saturating arithmetics **/
|
||||
#define OPENCV_HAL_IMPL_AVX_BIN_FUNC(func, _Tpvec, intrin) \
|
||||
inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(intrin(a.val, b.val)); }
|
||||
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint8x32, _mm256_add_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int8x32, _mm256_add_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint16x16, _mm256_add_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int16x16, _mm256_add_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint8x32, _mm256_sub_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int8x32, _mm256_sub_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint16x16, _mm256_sub_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int16x16, _mm256_sub_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_mul_wrap, v_uint16x16, _mm256_mullo_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_mul_wrap, v_int16x16, _mm256_mullo_epi16)
|
||||
|
||||
inline v_uint8x32 v_mul_wrap(const v_uint8x32& a, const v_uint8x32& b)
|
||||
{
|
||||
__m256i ad = _mm256_srai_epi16(a.val, 8);
|
||||
__m256i bd = _mm256_srai_epi16(b.val, 8);
|
||||
__m256i p0 = _mm256_mullo_epi16(a.val, b.val); // even
|
||||
__m256i p1 = _mm256_slli_epi16(_mm256_mullo_epi16(ad, bd), 8); // odd
|
||||
|
||||
const __m256i b01 = _mm256_set1_epi32(0xFF00FF00);
|
||||
return v_uint8x32(_mm256_blendv_epi8(p0, p1, b01));
|
||||
}
|
||||
inline v_int8x32 v_mul_wrap(const v_int8x32& a, const v_int8x32& b)
|
||||
{
|
||||
return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b)));
|
||||
}
|
||||
|
||||
// Multiply and expand
|
||||
inline void v_mul_expand(const v_uint8x32& a, const v_uint8x32& b,
|
||||
v_uint16x16& c, v_uint16x16& d)
|
||||
{
|
||||
v_uint16x16 a0, a1, b0, b1;
|
||||
v_expand(a, a0, a1);
|
||||
v_expand(b, b0, b1);
|
||||
c = v_mul_wrap(a0, b0);
|
||||
d = v_mul_wrap(a1, b1);
|
||||
}
|
||||
|
||||
inline void v_mul_expand(const v_int8x32& a, const v_int8x32& b,
|
||||
v_int16x16& c, v_int16x16& d)
|
||||
{
|
||||
v_int16x16 a0, a1, b0, b1;
|
||||
v_expand(a, a0, a1);
|
||||
v_expand(b, b0, b1);
|
||||
c = v_mul_wrap(a0, b0);
|
||||
d = v_mul_wrap(a1, b1);
|
||||
}
|
||||
|
||||
inline void v_mul_expand(const v_int16x16& a, const v_int16x16& b,
|
||||
v_int32x8& c, v_int32x8& d)
|
||||
{
|
||||
v_int16x16 vhi = v_int16x16(_mm256_mulhi_epi16(a.val, b.val));
|
||||
|
||||
v_int16x16 v0, v1;
|
||||
v_zip(a * b, vhi, v0, v1);
|
||||
v_zip(v_mul_wrap(a, b), vhi, v0, v1);
|
||||
|
||||
c = v_reinterpret_as_s32(v0);
|
||||
d = v_reinterpret_as_s32(v1);
|
||||
@@ -668,7 +764,7 @@ inline void v_mul_expand(const v_uint16x16& a, const v_uint16x16& b,
|
||||
v_uint16x16 vhi = v_uint16x16(_mm256_mulhi_epu16(a.val, b.val));
|
||||
|
||||
v_uint16x16 v0, v1;
|
||||
v_zip(a * b, vhi, v0, v1);
|
||||
v_zip(v_mul_wrap(a, b), vhi, v0, v1);
|
||||
|
||||
c = v_reinterpret_as_u32(v0);
|
||||
d = v_reinterpret_as_u32(v1);
|
||||
@@ -685,20 +781,6 @@ inline void v_mul_expand(const v_uint32x8& a, const v_uint32x8& b,
|
||||
inline v_int16x16 v_mul_hi(const v_int16x16& a, const v_int16x16& b) { return v_int16x16(_mm256_mulhi_epi16(a.val, b.val)); }
|
||||
inline v_uint16x16 v_mul_hi(const v_uint16x16& a, const v_uint16x16& b) { return v_uint16x16(_mm256_mulhi_epu16(a.val, b.val)); }
|
||||
|
||||
/** Non-saturating arithmetics **/
|
||||
#define OPENCV_HAL_IMPL_AVX_BIN_FUNC(func, _Tpvec, intrin) \
|
||||
inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(intrin(a.val, b.val)); }
|
||||
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint8x32, _mm256_add_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int8x32, _mm256_add_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint16x16, _mm256_add_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int16x16, _mm256_add_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint8x32, _mm256_sub_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int8x32, _mm256_sub_epi8)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint16x16, _mm256_sub_epi16)
|
||||
OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int16x16, _mm256_sub_epi16)
|
||||
|
||||
/** Bitwise shifts **/
|
||||
#define OPENCV_HAL_IMPL_AVX_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, srai) \
|
||||
inline _Tpuvec operator << (const _Tpuvec& a, int imm) \
|
||||
@@ -1385,6 +1467,10 @@ OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_float32x8, ps, _mm256_castps_si256, _mm256_ca
|
||||
b0.val = intrin(_v256_extract_low(a.val)); \
|
||||
b1.val = intrin(_v256_extract_high(a.val)); \
|
||||
} \
|
||||
inline _Tpwvec v_expand_low(const _Tpvec& a) \
|
||||
{ return _Tpwvec(intrin(_v256_extract_low(a.val))); } \
|
||||
inline _Tpwvec v_expand_high(const _Tpvec& a) \
|
||||
{ return _Tpwvec(intrin(_v256_extract_high(a.val))); } \
|
||||
inline _Tpwvec v256_load_expand(const _Tp* ptr) \
|
||||
{ \
|
||||
__m128i a = _mm_loadu_si128((const __m128i*)ptr); \
|
||||
@@ -1430,7 +1516,12 @@ inline void v_pack_store(schar* ptr, const v_int16x16& a)
|
||||
{ v_store_low(ptr, v_pack(a, a)); }
|
||||
|
||||
inline void v_pack_store(uchar* ptr, const v_uint16x16& a)
|
||||
{ v_store_low(ptr, v_pack(a, a)); }
|
||||
{
|
||||
const __m256i m = _mm256_set1_epi16(255);
|
||||
__m256i am = _mm256_min_epu16(a.val, m);
|
||||
am = _v256_shuffle_odd_64(_mm256_packus_epi16(am, am));
|
||||
v_store_low(ptr, v_uint8x32(am));
|
||||
}
|
||||
|
||||
inline void v_pack_u_store(uchar* ptr, const v_int16x16& a)
|
||||
{ v_store_low(ptr, v_pack_u(a, a)); }
|
||||
@@ -1484,16 +1575,21 @@ inline v_int16x16 v_pack(const v_int32x8& a, const v_int32x8& b)
|
||||
{ return v_int16x16(_v256_shuffle_odd_64(_mm256_packs_epi32(a.val, b.val))); }
|
||||
|
||||
inline v_uint16x16 v_pack(const v_uint32x8& a, const v_uint32x8& b)
|
||||
{ return v_uint16x16(_v256_shuffle_odd_64(_mm256_packus_epi32(a.val, b.val))); }
|
||||
{ return v_uint16x16(_v256_shuffle_odd_64(_v256_packs_epu32(a.val, b.val))); }
|
||||
|
||||
inline v_uint16x16 v_pack_u(const v_int32x8& a, const v_int32x8& b)
|
||||
{ return v_pack(v_reinterpret_as_u32(a), v_reinterpret_as_u32(b)); }
|
||||
{ return v_uint16x16(_v256_shuffle_odd_64(_mm256_packus_epi32(a.val, b.val))); }
|
||||
|
||||
inline void v_pack_store(short* ptr, const v_int32x8& a)
|
||||
{ v_store_low(ptr, v_pack(a, a)); }
|
||||
|
||||
inline void v_pack_store(ushort* ptr, const v_uint32x8& a)
|
||||
{ v_store_low(ptr, v_pack(a, a)); }
|
||||
{
|
||||
const __m256i m = _mm256_set1_epi32(65535);
|
||||
__m256i am = _mm256_min_epu32(a.val, m);
|
||||
am = _v256_shuffle_odd_64(_mm256_packus_epi32(am, am));
|
||||
v_store_low(ptr, v_uint16x16(am));
|
||||
}
|
||||
|
||||
inline void v_pack_u_store(ushort* ptr, const v_int32x8& a)
|
||||
{ v_store_low(ptr, v_pack_u(a, a)); }
|
||||
|
||||
@@ -108,7 +108,7 @@ block and to save contents of the register to memory block.
|
||||
These operations allow to reorder or recombine elements in one or multiple vectors.
|
||||
|
||||
- Interleave, deinterleave (2, 3 and 4 channels): @ref v_load_deinterleave, @ref v_store_interleave
|
||||
- Expand: @ref v_load_expand, @ref v_load_expand_q, @ref v_expand
|
||||
- Expand: @ref v_load_expand, @ref v_load_expand_q, @ref v_expand, @ref v_expand_low, @ref v_expand_high
|
||||
- Pack: @ref v_pack, @ref v_pack_u, @ref v_rshr_pack, @ref v_rshr_pack_u,
|
||||
@ref v_pack_store, @ref v_pack_u_store, @ref v_rshr_pack_store, @ref v_rshr_pack_u_store
|
||||
- Recombine: @ref v_zip, @ref v_recombine, @ref v_combine_low, @ref v_combine_high
|
||||
@@ -185,11 +185,14 @@ Regular integers:
|
||||
|load, store | x | x | x | x | x | x |
|
||||
|interleave | x | x | x | x | x | x |
|
||||
|expand | x | x | x | x | x | x |
|
||||
|expand_low | x | x | x | x | x | x |
|
||||
|expand_high | x | x | x | x | x | x |
|
||||
|expand_q | x | x | | | | |
|
||||
|add, sub | x | x | x | x | x | x |
|
||||
|add_wrap, sub_wrap | x | x | x | x | | |
|
||||
|mul | | | x | x | x | x |
|
||||
|mul_expand | | | x | x | x | |
|
||||
|mul_wrap | x | x | x | x | | |
|
||||
|mul | x | x | x | x | x | x |
|
||||
|mul_expand | x | x | x | x | x | |
|
||||
|compare | x | x | x | x | x | x |
|
||||
|shift | | | x | x | x | x |
|
||||
|dotprod | | | | x | | |
|
||||
@@ -680,7 +683,7 @@ OPENCV_HAL_IMPL_CMP_OP(!=)
|
||||
|
||||
//! @brief Helper macro
|
||||
//! @ingroup core_hal_intrin_impl
|
||||
#define OPENCV_HAL_IMPL_ADD_SUB_OP(func, bin_op, cast_op, _Tp2) \
|
||||
#define OPENCV_HAL_IMPL_ARITHM_OP(func, bin_op, cast_op, _Tp2) \
|
||||
template<typename _Tp, int n> \
|
||||
inline v_reg<_Tp2, n> func(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \
|
||||
{ \
|
||||
@@ -694,12 +697,17 @@ inline v_reg<_Tp2, n> func(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \
|
||||
/** @brief Add values without saturation
|
||||
|
||||
For 8- and 16-bit integer values. */
|
||||
OPENCV_HAL_IMPL_ADD_SUB_OP(v_add_wrap, +, (_Tp), _Tp)
|
||||
OPENCV_HAL_IMPL_ARITHM_OP(v_add_wrap, +, (_Tp), _Tp)
|
||||
|
||||
/** @brief Subtract values without saturation
|
||||
|
||||
For 8- and 16-bit integer values. */
|
||||
OPENCV_HAL_IMPL_ADD_SUB_OP(v_sub_wrap, -, (_Tp), _Tp)
|
||||
OPENCV_HAL_IMPL_ARITHM_OP(v_sub_wrap, -, (_Tp), _Tp)
|
||||
|
||||
/** @brief Multiply values without saturation
|
||||
|
||||
For 8- and 16-bit integer values. */
|
||||
OPENCV_HAL_IMPL_ARITHM_OP(v_mul_wrap, *, (_Tp), _Tp)
|
||||
|
||||
//! @cond IGNORED
|
||||
template<typename T> inline T _absdiff(T a, T b)
|
||||
@@ -1106,6 +1114,44 @@ template<typename _Tp, int n> inline void v_expand(const v_reg<_Tp, n>& a,
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Expand lower values to the wider pack type
|
||||
|
||||
Same as cv::v_expand, but return lower half of the vector.
|
||||
|
||||
Scheme:
|
||||
@code
|
||||
int32x4 int64x2
|
||||
{A B C D} ==> {A B}
|
||||
@endcode */
|
||||
template<typename _Tp, int n>
|
||||
inline v_reg<typename V_TypeTraits<_Tp>::w_type, n/2>
|
||||
v_expand_low(const v_reg<_Tp, n>& a)
|
||||
{
|
||||
v_reg<typename V_TypeTraits<_Tp>::w_type, n/2> b;
|
||||
for( int i = 0; i < (n/2); i++ )
|
||||
b.s[i] = a.s[i];
|
||||
return b;
|
||||
}
|
||||
|
||||
/** @brief Expand higher values to the wider pack type
|
||||
|
||||
Same as cv::v_expand_low, but expand higher half of the vector instead.
|
||||
|
||||
Scheme:
|
||||
@code
|
||||
int32x4 int64x2
|
||||
{A B C D} ==> {C D}
|
||||
@endcode */
|
||||
template<typename _Tp, int n>
|
||||
inline v_reg<typename V_TypeTraits<_Tp>::w_type, n/2>
|
||||
v_expand_high(const v_reg<_Tp, n>& a)
|
||||
{
|
||||
v_reg<typename V_TypeTraits<_Tp>::w_type, n/2> b;
|
||||
for( int i = 0; i < (n/2); i++ )
|
||||
b.s[i] = a.s[i+(n/2)];
|
||||
return b;
|
||||
}
|
||||
|
||||
//! @cond IGNORED
|
||||
template<typename _Tp, int n> inline v_reg<typename V_TypeTraits<_Tp>::int_type, n>
|
||||
v_reinterpret_as_int(const v_reg<_Tp, n>& a)
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef CV__SIMD_FORWARD
|
||||
#error "Need to pre-define forward width"
|
||||
#endif
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
//! @cond IGNORED
|
||||
|
||||
CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
|
||||
|
||||
/** Types **/
|
||||
#if CV__SIMD_FORWARD == 512
|
||||
// [todo] 512
|
||||
#error "AVX512 Not implemented yet"
|
||||
#elif CV__SIMD_FORWARD == 256
|
||||
// 256
|
||||
#define __CV_VX(fun) v256_##fun
|
||||
#define __CV_V_UINT8 v_uint8x32
|
||||
#define __CV_V_INT8 v_int8x32
|
||||
#define __CV_V_UINT16 v_uint16x16
|
||||
#define __CV_V_INT16 v_int16x16
|
||||
#define __CV_V_UINT32 v_uint32x8
|
||||
#define __CV_V_INT32 v_int32x8
|
||||
#define __CV_V_UINT64 v_uint64x4
|
||||
#define __CV_V_INT64 v_int64x4
|
||||
#define __CV_V_FLOAT32 v_float32x8
|
||||
#define __CV_V_FLOAT64 v_float64x4
|
||||
struct v_uint8x32;
|
||||
struct v_int8x32;
|
||||
struct v_uint16x16;
|
||||
struct v_int16x16;
|
||||
struct v_uint32x8;
|
||||
struct v_int32x8;
|
||||
struct v_uint64x4;
|
||||
struct v_int64x4;
|
||||
struct v_float32x8;
|
||||
struct v_float64x4;
|
||||
#else
|
||||
// 128
|
||||
#define __CV_VX(fun) v_##fun
|
||||
#define __CV_V_UINT8 v_uint8x16
|
||||
#define __CV_V_INT8 v_int8x16
|
||||
#define __CV_V_UINT16 v_uint16x8
|
||||
#define __CV_V_INT16 v_int16x8
|
||||
#define __CV_V_UINT32 v_uint32x4
|
||||
#define __CV_V_INT32 v_int32x4
|
||||
#define __CV_V_UINT64 v_uint64x2
|
||||
#define __CV_V_INT64 v_int64x2
|
||||
#define __CV_V_FLOAT32 v_float32x4
|
||||
#define __CV_V_FLOAT64 v_float64x2
|
||||
struct v_uint8x16;
|
||||
struct v_int8x16;
|
||||
struct v_uint16x8;
|
||||
struct v_int16x8;
|
||||
struct v_uint32x4;
|
||||
struct v_int32x4;
|
||||
struct v_uint64x2;
|
||||
struct v_int64x2;
|
||||
struct v_float32x4;
|
||||
struct v_float64x2;
|
||||
#endif
|
||||
|
||||
/** Value reordering **/
|
||||
|
||||
// Expansion
|
||||
void v_expand(const __CV_V_UINT8&, __CV_V_UINT16&, __CV_V_UINT16&);
|
||||
void v_expand(const __CV_V_INT8&, __CV_V_INT16&, __CV_V_INT16&);
|
||||
void v_expand(const __CV_V_UINT16&, __CV_V_UINT32&, __CV_V_UINT32&);
|
||||
void v_expand(const __CV_V_INT16&, __CV_V_INT32&, __CV_V_INT32&);
|
||||
void v_expand(const __CV_V_UINT32&, __CV_V_UINT64&, __CV_V_UINT64&);
|
||||
void v_expand(const __CV_V_INT32&, __CV_V_INT64&, __CV_V_INT64&);
|
||||
// Low Expansion
|
||||
__CV_V_UINT16 v_expand_low(const __CV_V_UINT8&);
|
||||
__CV_V_INT16 v_expand_low(const __CV_V_INT8&);
|
||||
__CV_V_UINT32 v_expand_low(const __CV_V_UINT16&);
|
||||
__CV_V_INT32 v_expand_low(const __CV_V_INT16&);
|
||||
__CV_V_UINT64 v_expand_low(const __CV_V_UINT32&);
|
||||
__CV_V_INT64 v_expand_low(const __CV_V_INT32&);
|
||||
// High Expansion
|
||||
__CV_V_UINT16 v_expand_high(const __CV_V_UINT8&);
|
||||
__CV_V_INT16 v_expand_high(const __CV_V_INT8&);
|
||||
__CV_V_UINT32 v_expand_high(const __CV_V_UINT16&);
|
||||
__CV_V_INT32 v_expand_high(const __CV_V_INT16&);
|
||||
__CV_V_UINT64 v_expand_high(const __CV_V_UINT32&);
|
||||
__CV_V_INT64 v_expand_high(const __CV_V_INT32&);
|
||||
// Load & Low Expansion
|
||||
__CV_V_UINT16 __CV_VX(load_expand)(const uchar*);
|
||||
__CV_V_INT16 __CV_VX(load_expand)(const schar*);
|
||||
__CV_V_UINT32 __CV_VX(load_expand)(const ushort*);
|
||||
__CV_V_INT32 __CV_VX(load_expand)(const short*);
|
||||
__CV_V_UINT64 __CV_VX(load_expand)(const uint*);
|
||||
__CV_V_INT64 __CV_VX(load_expand)(const int*);
|
||||
// Load lower 8-bit and expand into 32-bit
|
||||
__CV_V_UINT32 __CV_VX(load_expand_q)(const uchar*);
|
||||
__CV_V_INT32 __CV_VX(load_expand_q)(const schar*);
|
||||
|
||||
// Saturating Pack
|
||||
__CV_V_UINT8 v_pack(const __CV_V_UINT16&, const __CV_V_UINT16&);
|
||||
__CV_V_INT8 v_pack(const __CV_V_INT16&, const __CV_V_INT16&);
|
||||
__CV_V_UINT16 v_pack(const __CV_V_UINT32&, const __CV_V_UINT32&);
|
||||
__CV_V_INT16 v_pack(const __CV_V_INT32&, const __CV_V_INT32&);
|
||||
// Non-saturating Pack
|
||||
__CV_V_UINT32 v_pack(const __CV_V_UINT64&, const __CV_V_UINT64&);
|
||||
__CV_V_INT32 v_pack(const __CV_V_INT64&, const __CV_V_INT64&);
|
||||
// Pack signed integers with unsigned saturation
|
||||
__CV_V_UINT8 v_pack_u(const __CV_V_INT16&, const __CV_V_INT16&);
|
||||
__CV_V_UINT16 v_pack_u(const __CV_V_INT32&, const __CV_V_INT32&);
|
||||
|
||||
/** Arithmetic, bitwise and comparison operations **/
|
||||
|
||||
// Non-saturating multiply
|
||||
#if CV_VSX
|
||||
template<typename Tvec>
|
||||
Tvec v_mul_wrap(const Tvec& a, const Tvec& b);
|
||||
#else
|
||||
__CV_V_UINT8 v_mul_wrap(const __CV_V_UINT8&, const __CV_V_UINT8&);
|
||||
__CV_V_INT8 v_mul_wrap(const __CV_V_INT8&, const __CV_V_INT8&);
|
||||
__CV_V_UINT16 v_mul_wrap(const __CV_V_UINT16&, const __CV_V_UINT16&);
|
||||
__CV_V_INT16 v_mul_wrap(const __CV_V_INT16&, const __CV_V_INT16&);
|
||||
#endif
|
||||
|
||||
// Multiply and expand
|
||||
#if CV_VSX
|
||||
template<typename Tvec, typename Twvec>
|
||||
void v_mul_expand(const Tvec& a, const Tvec& b, Twvec& c, Twvec& d);
|
||||
#else
|
||||
void v_mul_expand(const __CV_V_UINT8&, const __CV_V_UINT8&, __CV_V_UINT16&, __CV_V_UINT16&);
|
||||
void v_mul_expand(const __CV_V_INT8&, const __CV_V_INT8&, __CV_V_INT16&, __CV_V_INT16&);
|
||||
void v_mul_expand(const __CV_V_UINT16&, const __CV_V_UINT16&, __CV_V_UINT32&, __CV_V_UINT32&);
|
||||
void v_mul_expand(const __CV_V_INT16&, const __CV_V_INT16&, __CV_V_INT32&, __CV_V_INT32&);
|
||||
void v_mul_expand(const __CV_V_UINT32&, const __CV_V_UINT32&, __CV_V_UINT64&, __CV_V_UINT64&);
|
||||
void v_mul_expand(const __CV_V_INT32&, const __CV_V_INT32&, __CV_V_INT64&, __CV_V_INT64&);
|
||||
#endif
|
||||
|
||||
/** Cleanup **/
|
||||
#undef CV__SIMD_FORWARD
|
||||
#undef __CV_VX
|
||||
#undef __CV_V_UINT8
|
||||
#undef __CV_V_INT8
|
||||
#undef __CV_V_UINT16
|
||||
#undef __CV_V_INT16
|
||||
#undef __CV_V_UINT32
|
||||
#undef __CV_V_INT32
|
||||
#undef __CV_V_UINT64
|
||||
#undef __CV_V_INT64
|
||||
#undef __CV_V_FLOAT32
|
||||
#undef __CV_V_FLOAT64
|
||||
|
||||
CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END
|
||||
|
||||
//! @endcond
|
||||
|
||||
} // cv::
|
||||
@@ -435,10 +435,8 @@ OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int8x16, vqaddq_s8)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int8x16, vqsubq_s8)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint16x8, vqaddq_u16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint16x8, vqsubq_u16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_uint16x8, vmulq_u16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int16x8, vqaddq_s16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int16x8, vqsubq_s16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_int16x8, vmulq_s16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int32x4, vaddq_s32)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int32x4, vsubq_s32)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_int32x4, vmulq_s32)
|
||||
@@ -476,6 +474,37 @@ inline v_float32x4& operator /= (v_float32x4& a, const v_float32x4& b)
|
||||
}
|
||||
#endif
|
||||
|
||||
// saturating multiply 8-bit, 16-bit
|
||||
#define OPENCV_HAL_IMPL_NEON_MUL_SAT(_Tpvec, _Tpwvec) \
|
||||
inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \
|
||||
{ \
|
||||
_Tpwvec c, d; \
|
||||
v_mul_expand(a, b, c, d); \
|
||||
return v_pack(c, d); \
|
||||
} \
|
||||
inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \
|
||||
{ a = a * b; return a; }
|
||||
|
||||
OPENCV_HAL_IMPL_NEON_MUL_SAT(v_int8x16, v_int16x8)
|
||||
OPENCV_HAL_IMPL_NEON_MUL_SAT(v_uint8x16, v_uint16x8)
|
||||
OPENCV_HAL_IMPL_NEON_MUL_SAT(v_int16x8, v_int32x4)
|
||||
OPENCV_HAL_IMPL_NEON_MUL_SAT(v_uint16x8, v_uint32x4)
|
||||
|
||||
// Multiply and expand
|
||||
inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b,
|
||||
v_int16x8& c, v_int16x8& d)
|
||||
{
|
||||
c.val = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val));
|
||||
d.val = vmull_s8(vget_high_s8(a.val), vget_high_s8(b.val));
|
||||
}
|
||||
|
||||
inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b,
|
||||
v_uint16x8& c, v_uint16x8& d)
|
||||
{
|
||||
c.val = vmull_u8(vget_low_u8(a.val), vget_low_u8(b.val));
|
||||
d.val = vmull_u8(vget_high_u8(a.val), vget_high_u8(b.val));
|
||||
}
|
||||
|
||||
inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b,
|
||||
v_int32x4& c, v_int32x4& d)
|
||||
{
|
||||
@@ -714,6 +743,10 @@ OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_sub_wrap, vsubq_u8)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_sub_wrap, vsubq_s8)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_sub_wrap, vsubq_u16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_sub_wrap, vsubq_s16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_mul_wrap, vmulq_u8)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_mul_wrap, vmulq_s8)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_mul_wrap, vmulq_u16)
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_mul_wrap, vmulq_s16)
|
||||
|
||||
// TODO: absdiff for signed integers
|
||||
OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_absdiff, vabdq_u8)
|
||||
@@ -1056,6 +1089,14 @@ inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \
|
||||
b0.val = vmovl_##suffix(vget_low_##suffix(a.val)); \
|
||||
b1.val = vmovl_##suffix(vget_high_##suffix(a.val)); \
|
||||
} \
|
||||
inline _Tpwvec v_expand_low(const _Tpvec& a) \
|
||||
{ \
|
||||
return _Tpwvec(vmovl_##suffix(vget_low_##suffix(a.val))); \
|
||||
} \
|
||||
inline _Tpwvec v_expand_high(const _Tpvec& a) \
|
||||
{ \
|
||||
return _Tpwvec(vmovl_##suffix(vget_high_##suffix(a.val))); \
|
||||
} \
|
||||
inline _Tpwvec v_load_expand(const _Tp* ptr) \
|
||||
{ \
|
||||
return _Tpwvec(vmovl_##suffix(vld1_##suffix(ptr))); \
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace cv
|
||||
|
||||
CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
|
||||
|
||||
///////// Types ////////////
|
||||
|
||||
struct v_uint8x16
|
||||
{
|
||||
typedef uchar lane_type;
|
||||
@@ -436,13 +438,7 @@ inline __m128i v_select_si128(__m128i mask, __m128i a, __m128i b)
|
||||
}
|
||||
|
||||
inline v_uint16x8 v_pack(const v_uint32x4& a, const v_uint32x4& b)
|
||||
{
|
||||
__m128i z = _mm_setzero_si128(), maxval32 = _mm_set1_epi32(65535), delta32 = _mm_set1_epi32(32768);
|
||||
__m128i a1 = _mm_sub_epi32(v_select_si128(_mm_cmpgt_epi32(z, a.val), maxval32, a.val), delta32);
|
||||
__m128i b1 = _mm_sub_epi32(v_select_si128(_mm_cmpgt_epi32(z, b.val), maxval32, b.val), delta32);
|
||||
__m128i r = _mm_packs_epi32(a1, b1);
|
||||
return v_uint16x8(_mm_sub_epi16(r, _mm_set1_epi16(-32768)));
|
||||
}
|
||||
{ return v_uint16x8(_v128_packs_epu32(a.val, b.val)); }
|
||||
|
||||
inline void v_pack_store(ushort* ptr, const v_uint32x4& a)
|
||||
{
|
||||
@@ -678,14 +674,14 @@ OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int8x16, _mm_adds_epi8)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int8x16, _mm_subs_epi8)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint16x8, _mm_adds_epu16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint16x8, _mm_subs_epu16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_uint16x8, _mm_mullo_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int16x8, _mm_adds_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int16x8, _mm_subs_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_int16x8, _mm_mullo_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint32x4, _mm_add_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint32x4, _mm_sub_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_uint32x4, _v128_mullo_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int32x4, _mm_add_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int32x4, _mm_sub_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_int32x4, _v128_mullo_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_float32x4, _mm_add_ps)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_float32x4, _mm_sub_ps)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_float32x4, _mm_mul_ps)
|
||||
@@ -699,35 +695,49 @@ OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint64x2, _mm_sub_epi64)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int64x2, _mm_add_epi64)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int64x2, _mm_sub_epi64)
|
||||
|
||||
inline v_uint32x4 operator * (const v_uint32x4& a, const v_uint32x4& b)
|
||||
// saturating multiply 8-bit, 16-bit
|
||||
#define OPENCV_HAL_IMPL_SSE_MUL_SAT(_Tpvec, _Tpwvec) \
|
||||
inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \
|
||||
{ \
|
||||
_Tpwvec c, d; \
|
||||
v_mul_expand(a, b, c, d); \
|
||||
return v_pack(c, d); \
|
||||
} \
|
||||
inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \
|
||||
{ a = a * b; return a; }
|
||||
|
||||
OPENCV_HAL_IMPL_SSE_MUL_SAT(v_int8x16, v_int16x8)
|
||||
OPENCV_HAL_IMPL_SSE_MUL_SAT(v_uint16x8, v_uint32x4)
|
||||
OPENCV_HAL_IMPL_SSE_MUL_SAT(v_int16x8, v_int32x4)
|
||||
|
||||
inline v_uint8x16 operator * (const v_uint8x16& a, const v_uint8x16& b)
|
||||
{
|
||||
__m128i c0 = _mm_mul_epu32(a.val, b.val);
|
||||
__m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a.val, 32), _mm_srli_epi64(b.val, 32));
|
||||
__m128i d0 = _mm_unpacklo_epi32(c0, c1);
|
||||
__m128i d1 = _mm_unpackhi_epi32(c0, c1);
|
||||
return v_uint32x4(_mm_unpacklo_epi64(d0, d1));
|
||||
v_uint16x8 c, d;
|
||||
v_mul_expand(a, b, c, d);
|
||||
return v_pack_u(v_reinterpret_as_s16(c), v_reinterpret_as_s16(d));
|
||||
}
|
||||
inline v_int32x4 operator * (const v_int32x4& a, const v_int32x4& b)
|
||||
inline v_uint8x16& operator *= (v_uint8x16& a, const v_uint8x16& b)
|
||||
{ a = a * b; return a; }
|
||||
|
||||
// Multiply and expand
|
||||
inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b,
|
||||
v_uint16x8& c, v_uint16x8& d)
|
||||
{
|
||||
#if CV_SSE4_1
|
||||
return v_int32x4(_mm_mullo_epi32(a.val, b.val));
|
||||
#else
|
||||
__m128i c0 = _mm_mul_epu32(a.val, b.val);
|
||||
__m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a.val, 32), _mm_srli_epi64(b.val, 32));
|
||||
__m128i d0 = _mm_unpacklo_epi32(c0, c1);
|
||||
__m128i d1 = _mm_unpackhi_epi32(c0, c1);
|
||||
return v_int32x4(_mm_unpacklo_epi64(d0, d1));
|
||||
#endif
|
||||
v_uint16x8 a0, a1, b0, b1;
|
||||
v_expand(a, a0, a1);
|
||||
v_expand(b, b0, b1);
|
||||
c = v_mul_wrap(a0, b0);
|
||||
d = v_mul_wrap(a1, b1);
|
||||
}
|
||||
inline v_uint32x4& operator *= (v_uint32x4& a, const v_uint32x4& b)
|
||||
|
||||
inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b,
|
||||
v_int16x8& c, v_int16x8& d)
|
||||
{
|
||||
a = a * b;
|
||||
return a;
|
||||
}
|
||||
inline v_int32x4& operator *= (v_int32x4& a, const v_int32x4& b)
|
||||
{
|
||||
a = a * b;
|
||||
return a;
|
||||
v_int16x8 a0, a1, b0, b1;
|
||||
v_expand(a, a0, a1);
|
||||
v_expand(b, b0, b1);
|
||||
c = v_mul_wrap(a0, b0);
|
||||
d = v_mul_wrap(a1, b1);
|
||||
}
|
||||
|
||||
inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b,
|
||||
@@ -1018,6 +1028,22 @@ OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_sub_wrap, _mm_sub_epi8)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int8x16, v_sub_wrap, _mm_sub_epi8)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_sub_wrap, _mm_sub_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_sub_wrap, _mm_sub_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_mul_wrap, _mm_mullo_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_mul_wrap, _mm_mullo_epi16)
|
||||
|
||||
inline v_uint8x16 v_mul_wrap(const v_uint8x16& a, const v_uint8x16& b)
|
||||
{
|
||||
__m128i ad = _mm_srai_epi16(a.val, 8);
|
||||
__m128i bd = _mm_srai_epi16(b.val, 8);
|
||||
__m128i p0 = _mm_mullo_epi16(a.val, b.val); // even
|
||||
__m128i p1 = _mm_slli_epi16(_mm_mullo_epi16(ad, bd), 8); // odd
|
||||
const __m128i b01 = _mm_set1_epi32(0xFF00FF00);
|
||||
return v_uint8x16(_v128_blendv_epi8(p0, p1, b01));
|
||||
}
|
||||
inline v_int8x16 v_mul_wrap(const v_int8x16& a, const v_int8x16& b)
|
||||
{
|
||||
return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b)));
|
||||
}
|
||||
|
||||
#define OPENCV_HAL_IMPL_SSE_ABSDIFF_8_16(_Tpuvec, _Tpsvec, bits, smask32) \
|
||||
inline _Tpuvec v_absdiff(const _Tpuvec& a, const _Tpuvec& b) \
|
||||
@@ -1502,70 +1528,39 @@ OPENCV_HAL_IMPL_SSE_SELECT(v_float32x4, ps)
|
||||
OPENCV_HAL_IMPL_SSE_SELECT(v_float64x2, pd)
|
||||
#endif
|
||||
|
||||
#define OPENCV_HAL_IMPL_SSE_EXPAND(_Tpuvec, _Tpwuvec, _Tpu, _Tpsvec, _Tpwsvec, _Tps, suffix, wsuffix, shift) \
|
||||
inline void v_expand(const _Tpuvec& a, _Tpwuvec& b0, _Tpwuvec& b1) \
|
||||
{ \
|
||||
__m128i z = _mm_setzero_si128(); \
|
||||
b0.val = _mm_unpacklo_##suffix(a.val, z); \
|
||||
b1.val = _mm_unpackhi_##suffix(a.val, z); \
|
||||
} \
|
||||
inline _Tpwuvec v_load_expand(const _Tpu* ptr) \
|
||||
{ \
|
||||
__m128i z = _mm_setzero_si128(); \
|
||||
return _Tpwuvec(_mm_unpacklo_##suffix(_mm_loadl_epi64((const __m128i*)ptr), z)); \
|
||||
} \
|
||||
inline void v_expand(const _Tpsvec& a, _Tpwsvec& b0, _Tpwsvec& b1) \
|
||||
{ \
|
||||
b0.val = _mm_srai_##wsuffix(_mm_unpacklo_##suffix(a.val, a.val), shift); \
|
||||
b1.val = _mm_srai_##wsuffix(_mm_unpackhi_##suffix(a.val, a.val), shift); \
|
||||
} \
|
||||
inline _Tpwsvec v_load_expand(const _Tps* ptr) \
|
||||
{ \
|
||||
__m128i a = _mm_loadl_epi64((const __m128i*)ptr); \
|
||||
return _Tpwsvec(_mm_srai_##wsuffix(_mm_unpacklo_##suffix(a, a), shift)); \
|
||||
}
|
||||
/* Expand */
|
||||
#define OPENCV_HAL_IMPL_SSE_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \
|
||||
inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \
|
||||
{ \
|
||||
b0.val = intrin(a.val); \
|
||||
b1.val = __CV_CAT(intrin, _high)(a.val); \
|
||||
} \
|
||||
inline _Tpwvec v_expand_low(const _Tpvec& a) \
|
||||
{ return _Tpwvec(intrin(a.val)); } \
|
||||
inline _Tpwvec v_expand_high(const _Tpvec& a) \
|
||||
{ return _Tpwvec(__CV_CAT(intrin, _high)(a.val)); } \
|
||||
inline _Tpwvec v_load_expand(const _Tp* ptr) \
|
||||
{ \
|
||||
__m128i a = _mm_loadl_epi64((const __m128i*)ptr); \
|
||||
return _Tpwvec(intrin(a)); \
|
||||
}
|
||||
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_uint8x16, v_uint16x8, uchar, v_int8x16, v_int16x8, schar, epi8, epi16, 8)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_uint16x8, v_uint32x4, ushort, v_int16x8, v_int32x4, short, epi16, epi32, 16)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_uint8x16, v_uint16x8, uchar, _v128_cvtepu8_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_int8x16, v_int16x8, schar, _v128_cvtepi8_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_uint16x8, v_uint32x4, ushort, _v128_cvtepu16_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_int16x8, v_int32x4, short, _v128_cvtepi16_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_uint32x4, v_uint64x2, unsigned, _v128_cvtepu32_epi64)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND(v_int32x4, v_int64x2, int, _v128_cvtepi32_epi64)
|
||||
|
||||
inline void v_expand(const v_uint32x4& a, v_uint64x2& b0, v_uint64x2& b1)
|
||||
{
|
||||
__m128i z = _mm_setzero_si128();
|
||||
b0.val = _mm_unpacklo_epi32(a.val, z);
|
||||
b1.val = _mm_unpackhi_epi32(a.val, z);
|
||||
}
|
||||
inline v_uint64x2 v_load_expand(const unsigned* ptr)
|
||||
{
|
||||
__m128i z = _mm_setzero_si128();
|
||||
return v_uint64x2(_mm_unpacklo_epi32(_mm_loadl_epi64((const __m128i*)ptr), z));
|
||||
}
|
||||
inline void v_expand(const v_int32x4& a, v_int64x2& b0, v_int64x2& b1)
|
||||
{
|
||||
__m128i s = _mm_srai_epi32(a.val, 31);
|
||||
b0.val = _mm_unpacklo_epi32(a.val, s);
|
||||
b1.val = _mm_unpackhi_epi32(a.val, s);
|
||||
}
|
||||
inline v_int64x2 v_load_expand(const int* ptr)
|
||||
{
|
||||
__m128i a = _mm_loadl_epi64((const __m128i*)ptr);
|
||||
__m128i s = _mm_srai_epi32(a, 31);
|
||||
return v_int64x2(_mm_unpacklo_epi32(a, s));
|
||||
}
|
||||
#define OPENCV_HAL_IMPL_SSE_EXPAND_Q(_Tpvec, _Tp, intrin) \
|
||||
inline _Tpvec v_load_expand_q(const _Tp* ptr) \
|
||||
{ \
|
||||
__m128i a = _mm_cvtsi32_si128(*(const int*)ptr); \
|
||||
return _Tpvec(intrin(a)); \
|
||||
}
|
||||
|
||||
inline v_uint32x4 v_load_expand_q(const uchar* ptr)
|
||||
{
|
||||
__m128i z = _mm_setzero_si128();
|
||||
__m128i a = _mm_cvtsi32_si128(*(const int*)ptr);
|
||||
return v_uint32x4(_mm_unpacklo_epi16(_mm_unpacklo_epi8(a, z), z));
|
||||
}
|
||||
|
||||
inline v_int32x4 v_load_expand_q(const schar* ptr)
|
||||
{
|
||||
__m128i a = _mm_cvtsi32_si128(*(const int*)ptr);
|
||||
a = _mm_unpacklo_epi8(a, a);
|
||||
a = _mm_unpacklo_epi8(a, a);
|
||||
return v_int32x4(_mm_srai_epi32(a, 24));
|
||||
}
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND_Q(v_uint32x4, uchar, _v128_cvtepu8_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_EXPAND_Q(v_int32x4, schar, _v128_cvtepi8_epi32)
|
||||
|
||||
#define OPENCV_HAL_IMPL_SSE_UNPACKS(_Tpvec, suffix, cast_from, cast_to) \
|
||||
inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) \
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_HAL_INTRIN_SSE_EM_HPP
|
||||
#define OPENCV_HAL_INTRIN_SSE_EM_HPP
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
//! @cond IGNORED
|
||||
|
||||
CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
|
||||
|
||||
#define OPENCV_HAL_SSE_WRAP_1(fun, tp) \
|
||||
inline tp _v128_##fun(const tp& a) \
|
||||
{ return _mm_##fun(a); }
|
||||
|
||||
#define OPENCV_HAL_SSE_WRAP_2(fun, tp) \
|
||||
inline tp _v128_##fun(const tp& a, const tp& b) \
|
||||
{ return _mm_##fun(a, b); }
|
||||
|
||||
#define OPENCV_HAL_SSE_WRAP_3(fun, tp) \
|
||||
inline tp _v128_##fun(const tp& a, const tp& b, const tp& c) \
|
||||
{ return _mm_##fun(a, b, c); }
|
||||
|
||||
///////////////////////////// XOP /////////////////////////////
|
||||
|
||||
// [todo] define CV_XOP
|
||||
#if 1 // CV_XOP
|
||||
inline __m128i _v128_comgt_epu32(const __m128i& a, const __m128i& b)
|
||||
{
|
||||
const __m128i delta = _mm_set1_epi32((int)0x80000000);
|
||||
return _mm_cmpgt_epi32(_mm_xor_si128(a, delta), _mm_xor_si128(b, delta));
|
||||
}
|
||||
// wrapping XOP
|
||||
#else
|
||||
OPENCV_HAL_SSE_WRAP_2(_v128_comgt_epu32, __m128i)
|
||||
#endif // !CV_XOP
|
||||
|
||||
///////////////////////////// SSE4.1 /////////////////////////////
|
||||
|
||||
#if !CV_SSE4_1
|
||||
|
||||
/** Swizzle **/
|
||||
inline __m128i _v128_blendv_epi8(const __m128i& a, const __m128i& b, const __m128i& mask)
|
||||
{ return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(b, a), mask)); }
|
||||
|
||||
/** Convert **/
|
||||
// 8 >> 16
|
||||
inline __m128i _v128_cvtepu8_epi16(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpacklo_epi8(a, z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi8_epi16(const __m128i& a)
|
||||
{ return _mm_srai_epi16(_mm_unpacklo_epi8(a, a), 8); }
|
||||
// 8 >> 32
|
||||
inline __m128i _v128_cvtepu8_epi32(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpacklo_epi16(_mm_unpacklo_epi8(a, z), z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi8_epi32(const __m128i& a)
|
||||
{
|
||||
__m128i r = _mm_unpacklo_epi8(a, a);
|
||||
r = _mm_unpacklo_epi8(r, r);
|
||||
return _mm_srai_epi32(r, 24);
|
||||
}
|
||||
// 16 >> 32
|
||||
inline __m128i _v128_cvtepu16_epi32(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpacklo_epi16(a, z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi16_epi32(const __m128i& a)
|
||||
{ return _mm_srai_epi32(_mm_unpacklo_epi16(a, a), 16); }
|
||||
// 32 >> 64
|
||||
inline __m128i _v128_cvtepu32_epi64(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpacklo_epi32(a, z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi32_epi64(const __m128i& a)
|
||||
{ return _mm_unpacklo_epi32(a, _mm_srai_epi32(a, 31)); }
|
||||
|
||||
/** Arithmetic **/
|
||||
inline __m128i _v128_mullo_epi32(const __m128i& a, const __m128i& b)
|
||||
{
|
||||
__m128i c0 = _mm_mul_epu32(a, b);
|
||||
__m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a, 32), _mm_srli_epi64(b, 32));
|
||||
__m128i d0 = _mm_unpacklo_epi32(c0, c1);
|
||||
__m128i d1 = _mm_unpackhi_epi32(c0, c1);
|
||||
return _mm_unpacklo_epi64(d0, d1);
|
||||
}
|
||||
|
||||
/** Math **/
|
||||
inline __m128i _v128_min_epu32(const __m128i& a, const __m128i& b)
|
||||
{ return _v128_blendv_epi8(a, b, _v128_comgt_epu32(a, b)); }
|
||||
|
||||
// wrapping SSE4.1
|
||||
#else
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepu8_epi16, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepi8_epi16, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepu8_epi32, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepi8_epi32, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepu16_epi32, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepi16_epi32, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepu32_epi64, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_1(cvtepi32_epi64, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_2(min_epu32, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_2(mullo_epi32, __m128i)
|
||||
OPENCV_HAL_SSE_WRAP_3(blendv_epi8, __m128i)
|
||||
#endif // !CV_SSE4_1
|
||||
|
||||
///////////////////////////// Revolutionary /////////////////////////////
|
||||
|
||||
/** Convert **/
|
||||
// 16 << 8
|
||||
inline __m128i _v128_cvtepu8_epi16_high(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpackhi_epi8(a, z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi8_epi16_high(const __m128i& a)
|
||||
{ return _mm_srai_epi16(_mm_unpackhi_epi8(a, a), 8); }
|
||||
// 32 << 16
|
||||
inline __m128i _v128_cvtepu16_epi32_high(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpackhi_epi16(a, z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi16_epi32_high(const __m128i& a)
|
||||
{ return _mm_srai_epi32(_mm_unpackhi_epi16(a, a), 16); }
|
||||
// 64 << 32
|
||||
inline __m128i _v128_cvtepu32_epi64_high(const __m128i& a)
|
||||
{
|
||||
const __m128i z = _mm_setzero_si128();
|
||||
return _mm_unpackhi_epi32(a, z);
|
||||
}
|
||||
inline __m128i _v128_cvtepi32_epi64_high(const __m128i& a)
|
||||
{ return _mm_unpackhi_epi32(a, _mm_srai_epi32(a, 31)); }
|
||||
|
||||
/** Miscellaneous **/
|
||||
inline __m128i _v128_packs_epu32(const __m128i& a, const __m128i& b)
|
||||
{
|
||||
const __m128i m = _mm_set1_epi32(65535);
|
||||
__m128i am = _v128_min_epu32(a, m);
|
||||
__m128i bm = _v128_min_epu32(b, m);
|
||||
#if CV_SSE4_1
|
||||
return _mm_packus_epi32(am, bm);
|
||||
#else
|
||||
const __m128i d = _mm_set1_epi32(32768), nd = _mm_set1_epi16(-32768);
|
||||
am = _mm_sub_epi32(am, d);
|
||||
bm = _mm_sub_epi32(bm, d);
|
||||
am = _mm_packs_epi32(am, bm);
|
||||
return _mm_sub_epi16(am, nd);
|
||||
#endif
|
||||
}
|
||||
|
||||
CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END
|
||||
|
||||
//! @endcond
|
||||
|
||||
} // cv::
|
||||
|
||||
#endif // OPENCV_HAL_INTRIN_SSE_EM_HPP
|
||||
@@ -315,6 +315,10 @@ inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \
|
||||
b0.val = fh(a.val); \
|
||||
b1.val = fl(a.val); \
|
||||
} \
|
||||
inline _Tpwvec v_expand_low(const _Tpvec& a) \
|
||||
{ return _Tpwvec(fh(a.val)); } \
|
||||
inline _Tpwvec v_expand_high(const _Tpvec& a) \
|
||||
{ return _Tpwvec(fl(a.val)); } \
|
||||
inline _Tpwvec v_load_expand(const _Tp* ptr) \
|
||||
{ return _Tpwvec(fh(vec_ld_l8(ptr))); }
|
||||
|
||||
@@ -418,10 +422,8 @@ OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int8x16, vec_adds)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int8x16, vec_subs)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint16x8, vec_adds)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint16x8, vec_subs)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_uint16x8, vec_mul)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int16x8, vec_adds)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int16x8, vec_subs)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_int16x8, vec_mul)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint32x4, vec_add)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint32x4, vec_sub)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_uint32x4, vec_mul)
|
||||
@@ -441,16 +443,30 @@ OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint64x2, vec_sub)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int64x2, vec_add)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int64x2, vec_sub)
|
||||
|
||||
inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, v_int32x4& c, v_int32x4& d)
|
||||
// saturating multiply
|
||||
#define OPENCV_HAL_IMPL_VSX_MUL_SAT(_Tpvec, _Tpwvec) \
|
||||
inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \
|
||||
{ \
|
||||
_Tpwvec c, d; \
|
||||
v_mul_expand(a, b, c, d); \
|
||||
return v_pack(c, d); \
|
||||
} \
|
||||
inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \
|
||||
{ a = a * b; return a; }
|
||||
|
||||
OPENCV_HAL_IMPL_VSX_MUL_SAT(v_int8x16, v_int16x8)
|
||||
OPENCV_HAL_IMPL_VSX_MUL_SAT(v_uint8x16, v_uint16x8)
|
||||
OPENCV_HAL_IMPL_VSX_MUL_SAT(v_int16x8, v_int32x4)
|
||||
OPENCV_HAL_IMPL_VSX_MUL_SAT(v_uint16x8, v_uint32x4)
|
||||
|
||||
template<typename Tvec, typename Twvec>
|
||||
inline void v_mul_expand(const Tvec& a, const Tvec& b, Twvec& c, Twvec& d)
|
||||
{
|
||||
c.val = vec_mul(vec_unpackh(a.val), vec_unpackh(b.val));
|
||||
d.val = vec_mul(vec_unpackl(a.val), vec_unpackl(b.val));
|
||||
}
|
||||
inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, v_uint32x4& c, v_uint32x4& d)
|
||||
{
|
||||
c.val = vec_mul(vec_unpackhu(a.val), vec_unpackhu(b.val));
|
||||
d.val = vec_mul(vec_unpacklu(a.val), vec_unpacklu(b.val));
|
||||
Twvec p0 = Twvec(vec_mule(a.val, b.val));
|
||||
Twvec p1 = Twvec(vec_mulo(a.val, b.val));
|
||||
v_zip(p0, p1, c, d);
|
||||
}
|
||||
|
||||
inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, v_uint64x2& c, v_uint64x2& d)
|
||||
{
|
||||
c.val = vec_mul(vec_unpackhu(a.val), vec_unpackhu(b.val));
|
||||
@@ -459,17 +475,17 @@ inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, v_uint64x2& c
|
||||
|
||||
inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b)
|
||||
{
|
||||
return v_int16x8(vec_packs(
|
||||
vec_sra(vec_mul(vec_unpackh(a.val), vec_unpackh(b.val)), vec_uint4_sp(16)),
|
||||
vec_sra(vec_mul(vec_unpackl(a.val), vec_unpackl(b.val)), vec_uint4_sp(16))
|
||||
));
|
||||
vec_int4 p0 = vec_mule(a.val, b.val);
|
||||
vec_int4 p1 = vec_mulo(a.val, b.val);
|
||||
static const vec_uchar16 perm = {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31};
|
||||
return v_int16x8(vec_perm(vec_short8_c(p0), vec_short8_c(p1), perm));
|
||||
}
|
||||
inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b)
|
||||
{
|
||||
return v_uint16x8(vec_packs(
|
||||
vec_sr(vec_mul(vec_unpackhu(a.val), vec_unpackhu(b.val)), vec_uint4_sp(16)),
|
||||
vec_sr(vec_mul(vec_unpacklu(a.val), vec_unpacklu(b.val)), vec_uint4_sp(16))
|
||||
));
|
||||
vec_uint4 p0 = vec_mule(a.val, b.val);
|
||||
vec_uint4 p1 = vec_mulo(a.val, b.val);
|
||||
static const vec_uchar16 perm = {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31};
|
||||
return v_uint16x8(vec_perm(vec_ushort8_c(p0), vec_ushort8_c(p1), perm));
|
||||
}
|
||||
|
||||
/** Non-saturating arithmetics **/
|
||||
@@ -480,6 +496,7 @@ inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \
|
||||
|
||||
OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_add_wrap, vec_add)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_sub_wrap, vec_sub)
|
||||
OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_mul_wrap, vec_mul)
|
||||
|
||||
/** Bitwise shifts **/
|
||||
#define OPENCV_HAL_IMPL_VSX_SHIFT_OP(_Tpvec, shr, splfunc) \
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace trace {
|
||||
//! @cond IGNORED
|
||||
#define CV_TRACE_NS cv::utils::trace
|
||||
|
||||
#if !defined(OPENCV_DISABLE_TRACE) && defined(__EMSCRIPTEN__)
|
||||
#define OPENCV_DISABLE_TRACE 1
|
||||
#endif
|
||||
|
||||
namespace details {
|
||||
|
||||
#ifndef __OPENCV_TRACE
|
||||
|
||||
@@ -130,19 +130,21 @@ VSX_FINLINE(rt) fnm(const rg& a, const rg& b) \
|
||||
# undef vec_mul
|
||||
# endif
|
||||
/*
|
||||
* there's no a direct instruction for supporting 16-bit multiplication in ISA 2.07,
|
||||
* there's no a direct instruction for supporting 8-bit, 16-bit multiplication in ISA 2.07,
|
||||
* XLC Implement it by using instruction "multiply even", "multiply odd" and "permute"
|
||||
* todo: Do I need to support 8-bit ?
|
||||
**/
|
||||
# define VSX_IMPL_MULH(Tvec, Tcast) \
|
||||
VSX_FINLINE(Tvec) vec_mul(const Tvec& a, const Tvec& b) \
|
||||
{ \
|
||||
static const vec_uchar16 even_perm = {0, 1, 16, 17, 4, 5, 20, 21, \
|
||||
8, 9, 24, 25, 12, 13, 28, 29}; \
|
||||
return vec_perm(Tcast(vec_mule(a, b)), Tcast(vec_mulo(a, b)), even_perm); \
|
||||
# define VSX_IMPL_MULH(Tvec, cperm) \
|
||||
VSX_FINLINE(Tvec) vec_mul(const Tvec& a, const Tvec& b) \
|
||||
{ \
|
||||
static const vec_uchar16 ev_od = {cperm}; \
|
||||
return vec_perm((Tvec)vec_mule(a, b), (Tvec)vec_mulo(a, b), ev_od); \
|
||||
}
|
||||
VSX_IMPL_MULH(vec_short8, vec_short8_c)
|
||||
VSX_IMPL_MULH(vec_ushort8, vec_ushort8_c)
|
||||
#define VSX_IMPL_MULH_P16 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30
|
||||
VSX_IMPL_MULH(vec_char16, VSX_IMPL_MULH_P16)
|
||||
VSX_IMPL_MULH(vec_uchar16, VSX_IMPL_MULH_P16)
|
||||
#define VSX_IMPL_MULH_P8 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29
|
||||
VSX_IMPL_MULH(vec_short8, VSX_IMPL_MULH_P8)
|
||||
VSX_IMPL_MULH(vec_ushort8, VSX_IMPL_MULH_P8)
|
||||
// vmuluwm can be used for unsigned or signed integers, that's what they said
|
||||
VSX_IMPL_2VRG(vec_int4, vec_int4, vmuluwm, vec_mul)
|
||||
VSX_IMPL_2VRG(vec_uint4, vec_uint4, vmuluwm, vec_mul)
|
||||
|
||||
+16
-14
@@ -90,20 +90,21 @@ copyMask_<uchar>(const uchar* _src, size_t sstep, const uchar* mask, size_t mste
|
||||
const uchar* src = (const uchar*)_src;
|
||||
uchar* dst = (uchar*)_dst;
|
||||
int x = 0;
|
||||
#if CV_SIMD128
|
||||
#if CV_SIMD
|
||||
{
|
||||
v_uint8x16 v_zero = v_setzero_u8();
|
||||
v_uint8 v_zero = vx_setzero_u8();
|
||||
|
||||
for( ; x <= size.width - 16; x += 16 )
|
||||
for( ; x <= size.width - v_uint8::nlanes; x += v_uint8::nlanes )
|
||||
{
|
||||
v_uint8x16 v_src = v_load(src + x),
|
||||
v_dst = v_load(dst + x),
|
||||
v_nmask = v_load(mask + x) == v_zero;
|
||||
v_uint8 v_src = vx_load(src + x),
|
||||
v_dst = vx_load(dst + x),
|
||||
v_nmask = vx_load(mask + x) == v_zero;
|
||||
|
||||
v_dst = v_select(v_nmask, v_dst, v_src);
|
||||
v_store(dst + x, v_dst);
|
||||
}
|
||||
}
|
||||
vx_cleanup();
|
||||
#endif
|
||||
for( ; x < size.width; x++ )
|
||||
if( mask[x] )
|
||||
@@ -121,25 +122,26 @@ copyMask_<ushort>(const uchar* _src, size_t sstep, const uchar* mask, size_t mst
|
||||
const ushort* src = (const ushort*)_src;
|
||||
ushort* dst = (ushort*)_dst;
|
||||
int x = 0;
|
||||
#if CV_SIMD128
|
||||
#if CV_SIMD
|
||||
{
|
||||
v_uint8x16 v_zero = v_setzero_u8();
|
||||
v_uint8 v_zero = vx_setzero_u8();
|
||||
|
||||
for( ; x <= size.width - 16; x += 16 )
|
||||
for( ; x <= size.width - v_uint8::nlanes; x += v_uint8::nlanes )
|
||||
{
|
||||
v_uint16x8 v_src1 = v_load(src + x), v_src2 = v_load(src + x + 8),
|
||||
v_dst1 = v_load(dst + x), v_dst2 = v_load(dst + x + 8);
|
||||
v_uint16 v_src1 = vx_load(src + x), v_src2 = vx_load(src + x + v_uint16::nlanes),
|
||||
v_dst1 = vx_load(dst + x), v_dst2 = vx_load(dst + x + v_uint16::nlanes);
|
||||
|
||||
v_uint8x16 v_nmask1, v_nmask2;
|
||||
v_uint8x16 v_nmask = v_load(mask + x) == v_zero;
|
||||
v_uint8 v_nmask1, v_nmask2;
|
||||
v_uint8 v_nmask = vx_load(mask + x) == v_zero;
|
||||
v_zip(v_nmask, v_nmask, v_nmask1, v_nmask2);
|
||||
|
||||
v_dst1 = v_select(v_reinterpret_as_u16(v_nmask1), v_dst1, v_src1);
|
||||
v_dst2 = v_select(v_reinterpret_as_u16(v_nmask2), v_dst2, v_src2);
|
||||
v_store(dst + x, v_dst1);
|
||||
v_store(dst + x + 8, v_dst2);
|
||||
v_store(dst + x + v_uint16::nlanes, v_dst2);
|
||||
}
|
||||
}
|
||||
vx_cleanup();
|
||||
#endif
|
||||
for( ; x < size.width; x++ )
|
||||
if( mask[x] )
|
||||
|
||||
+47
-42
@@ -277,40 +277,42 @@ template<typename T> struct VBLAS
|
||||
int givensx(T*, T*, int, T, T, T*, T*) const { return 0; }
|
||||
};
|
||||
|
||||
#if CV_SIMD128
|
||||
#if CV_SIMD
|
||||
template<> inline int VBLAS<float>::dot(const float* a, const float* b, int n, float* result) const
|
||||
{
|
||||
if( n < 8 )
|
||||
if( n < 2*v_float32::nlanes )
|
||||
return 0;
|
||||
int k = 0;
|
||||
v_float32x4 s0 = v_setzero_f32();
|
||||
for( ; k <= n - v_float32x4::nlanes; k += v_float32x4::nlanes )
|
||||
v_float32 s0 = vx_setzero_f32();
|
||||
for( ; k <= n - v_float32::nlanes; k += v_float32::nlanes )
|
||||
{
|
||||
v_float32x4 a0 = v_load(a + k);
|
||||
v_float32x4 b0 = v_load(b + k);
|
||||
v_float32 a0 = vx_load(a + k);
|
||||
v_float32 b0 = vx_load(b + k);
|
||||
|
||||
s0 += a0 * b0;
|
||||
}
|
||||
*result = v_reduce_sum(s0);
|
||||
vx_cleanup();
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
template<> inline int VBLAS<float>::givens(float* a, float* b, int n, float c, float s) const
|
||||
{
|
||||
if( n < 4 )
|
||||
if( n < v_float32::nlanes)
|
||||
return 0;
|
||||
int k = 0;
|
||||
v_float32x4 c4 = v_setall_f32(c), s4 = v_setall_f32(s);
|
||||
for( ; k <= n - v_float32x4::nlanes; k += v_float32x4::nlanes )
|
||||
v_float32 c4 = vx_setall_f32(c), s4 = vx_setall_f32(s);
|
||||
for( ; k <= n - v_float32::nlanes; k += v_float32::nlanes )
|
||||
{
|
||||
v_float32x4 a0 = v_load(a + k);
|
||||
v_float32x4 b0 = v_load(b + k);
|
||||
v_float32x4 t0 = (a0 * c4) + (b0 * s4);
|
||||
v_float32x4 t1 = (b0 * c4) - (a0 * s4);
|
||||
v_float32 a0 = vx_load(a + k);
|
||||
v_float32 b0 = vx_load(b + k);
|
||||
v_float32 t0 = (a0 * c4) + (b0 * s4);
|
||||
v_float32 t1 = (b0 * c4) - (a0 * s4);
|
||||
v_store(a + k, t0);
|
||||
v_store(b + k, t1);
|
||||
}
|
||||
vx_cleanup();
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -318,17 +320,17 @@ template<> inline int VBLAS<float>::givens(float* a, float* b, int n, float c, f
|
||||
template<> inline int VBLAS<float>::givensx(float* a, float* b, int n, float c, float s,
|
||||
float* anorm, float* bnorm) const
|
||||
{
|
||||
if( n < 4 )
|
||||
if( n < v_float32::nlanes)
|
||||
return 0;
|
||||
int k = 0;
|
||||
v_float32x4 c4 = v_setall_f32(c), s4 = v_setall_f32(s);
|
||||
v_float32x4 sa = v_setzero_f32(), sb = v_setzero_f32();
|
||||
for( ; k <= n - v_float32x4::nlanes; k += v_float32x4::nlanes )
|
||||
v_float32 c4 = vx_setall_f32(c), s4 = vx_setall_f32(s);
|
||||
v_float32 sa = vx_setzero_f32(), sb = vx_setzero_f32();
|
||||
for( ; k <= n - v_float32::nlanes; k += v_float32::nlanes )
|
||||
{
|
||||
v_float32x4 a0 = v_load(a + k);
|
||||
v_float32x4 b0 = v_load(b + k);
|
||||
v_float32x4 t0 = (a0 * c4) + (b0 * s4);
|
||||
v_float32x4 t1 = (b0 * c4) - (a0 * s4);
|
||||
v_float32 a0 = vx_load(a + k);
|
||||
v_float32 b0 = vx_load(b + k);
|
||||
v_float32 t0 = (a0 * c4) + (b0 * s4);
|
||||
v_float32 t1 = (b0 * c4) - (a0 * s4);
|
||||
v_store(a + k, t0);
|
||||
v_store(b + k, t1);
|
||||
sa += t0 + t0;
|
||||
@@ -336,26 +338,28 @@ template<> inline int VBLAS<float>::givensx(float* a, float* b, int n, float c,
|
||||
}
|
||||
*anorm = v_reduce_sum(sa);
|
||||
*bnorm = v_reduce_sum(sb);
|
||||
vx_cleanup();
|
||||
return k;
|
||||
}
|
||||
|
||||
#if CV_SIMD128_64F
|
||||
#if CV_SIMD_64F
|
||||
template<> inline int VBLAS<double>::dot(const double* a, const double* b, int n, double* result) const
|
||||
{
|
||||
if( n < 4 )
|
||||
if( n < 2*v_float64::nlanes )
|
||||
return 0;
|
||||
int k = 0;
|
||||
v_float64x2 s0 = v_setzero_f64();
|
||||
for( ; k <= n - v_float64x2::nlanes; k += v_float64x2::nlanes )
|
||||
v_float64 s0 = vx_setzero_f64();
|
||||
for( ; k <= n - v_float64::nlanes; k += v_float64::nlanes )
|
||||
{
|
||||
v_float64x2 a0 = v_load(a + k);
|
||||
v_float64x2 b0 = v_load(b + k);
|
||||
v_float64 a0 = vx_load(a + k);
|
||||
v_float64 b0 = vx_load(b + k);
|
||||
|
||||
s0 += a0 * b0;
|
||||
}
|
||||
double sbuf[2];
|
||||
v_store(sbuf, s0);
|
||||
*result = sbuf[0] + sbuf[1];
|
||||
vx_cleanup();
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -363,16 +367,17 @@ template<> inline int VBLAS<double>::dot(const double* a, const double* b, int n
|
||||
template<> inline int VBLAS<double>::givens(double* a, double* b, int n, double c, double s) const
|
||||
{
|
||||
int k = 0;
|
||||
v_float64x2 c2 = v_setall_f64(c), s2 = v_setall_f64(s);
|
||||
for( ; k <= n - v_float64x2::nlanes; k += v_float64x2::nlanes )
|
||||
v_float64 c2 = vx_setall_f64(c), s2 = vx_setall_f64(s);
|
||||
for( ; k <= n - v_float64::nlanes; k += v_float64::nlanes )
|
||||
{
|
||||
v_float64x2 a0 = v_load(a + k);
|
||||
v_float64x2 b0 = v_load(b + k);
|
||||
v_float64x2 t0 = (a0 * c2) + (b0 * s2);
|
||||
v_float64x2 t1 = (b0 * c2) - (a0 * s2);
|
||||
v_float64 a0 = vx_load(a + k);
|
||||
v_float64 b0 = vx_load(b + k);
|
||||
v_float64 t0 = (a0 * c2) + (b0 * s2);
|
||||
v_float64 t1 = (b0 * c2) - (a0 * s2);
|
||||
v_store(a + k, t0);
|
||||
v_store(b + k, t1);
|
||||
}
|
||||
vx_cleanup();
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -381,14 +386,14 @@ template<> inline int VBLAS<double>::givensx(double* a, double* b, int n, double
|
||||
double* anorm, double* bnorm) const
|
||||
{
|
||||
int k = 0;
|
||||
v_float64x2 c2 = v_setall_f64(c), s2 = v_setall_f64(s);
|
||||
v_float64x2 sa = v_setzero_f64(), sb = v_setzero_f64();
|
||||
for( ; k <= n - v_float64x2::nlanes; k += v_float64x2::nlanes )
|
||||
v_float64 c2 = vx_setall_f64(c), s2 = vx_setall_f64(s);
|
||||
v_float64 sa = vx_setzero_f64(), sb = vx_setzero_f64();
|
||||
for( ; k <= n - v_float64::nlanes; k += v_float64::nlanes )
|
||||
{
|
||||
v_float64x2 a0 = v_load(a + k);
|
||||
v_float64x2 b0 = v_load(b + k);
|
||||
v_float64x2 t0 = (a0 * c2) + (b0 * s2);
|
||||
v_float64x2 t1 = (b0 * c2) - (a0 * s2);
|
||||
v_float64 a0 = vx_load(a + k);
|
||||
v_float64 b0 = vx_load(b + k);
|
||||
v_float64 t0 = (a0 * c2) + (b0 * s2);
|
||||
v_float64 t1 = (b0 * c2) - (a0 * s2);
|
||||
v_store(a + k, t0);
|
||||
v_store(b + k, t1);
|
||||
sa += t0 * t0;
|
||||
@@ -401,8 +406,8 @@ template<> inline int VBLAS<double>::givensx(double* a, double* b, int n, double
|
||||
*bnorm = bbuf[0] + bbuf[1];
|
||||
return k;
|
||||
}
|
||||
#endif //CV_SIMD128_64F
|
||||
#endif //CV_SIMD128
|
||||
#endif //CV_SIMD_64F
|
||||
#endif //CV_SIMD
|
||||
|
||||
template<typename _Tp> void
|
||||
JacobiSVDImpl_(_Tp* At, size_t astep, _Tp* _W, _Tp* Vt, size_t vstep,
|
||||
|
||||
@@ -607,17 +607,15 @@ void polarToCart( InputArray src1, InputArray src2,
|
||||
{
|
||||
k = 0;
|
||||
|
||||
#if CV_SIMD128
|
||||
if( hasSIMD128() )
|
||||
#if CV_SIMD
|
||||
int cWidth = v_float32::nlanes;
|
||||
for( ; k <= len - cWidth; k += cWidth )
|
||||
{
|
||||
int cWidth = v_float32x4::nlanes;
|
||||
for( ; k <= len - cWidth; k += cWidth )
|
||||
{
|
||||
v_float32x4 v_m = v_load(mag + k);
|
||||
v_store(x + k, v_load(x + k) * v_m);
|
||||
v_store(y + k, v_load(y + k) * v_m);
|
||||
}
|
||||
v_float32 v_m = vx_load(mag + k);
|
||||
v_store(x + k, vx_load(x + k) * v_m);
|
||||
v_store(y + k, vx_load(y + k) * v_m);
|
||||
}
|
||||
vx_cleanup();
|
||||
#endif
|
||||
|
||||
for( ; k < len; k++ )
|
||||
@@ -736,7 +734,7 @@ struct iPow_SIMD
|
||||
}
|
||||
};
|
||||
|
||||
#if CV_SIMD128
|
||||
#if CV_SIMD
|
||||
|
||||
template <>
|
||||
struct iPow_SIMD<uchar, int>
|
||||
@@ -744,13 +742,13 @@ struct iPow_SIMD<uchar, int>
|
||||
int operator() ( const uchar * src, uchar * dst, int len, int power )
|
||||
{
|
||||
int i = 0;
|
||||
v_uint32x4 v_1 = v_setall_u32(1u);
|
||||
v_uint32 v_1 = vx_setall_u32(1u);
|
||||
|
||||
for ( ; i <= len - 8; i += 8)
|
||||
for ( ; i <= len - v_uint16::nlanes; i += v_uint16::nlanes)
|
||||
{
|
||||
v_uint32x4 v_a1 = v_1, v_a2 = v_1;
|
||||
v_uint16x8 v = v_load_expand(src + i);
|
||||
v_uint32x4 v_b1, v_b2;
|
||||
v_uint32 v_a1 = v_1, v_a2 = v_1;
|
||||
v_uint16 v = vx_load_expand(src + i);
|
||||
v_uint32 v_b1, v_b2;
|
||||
v_expand(v, v_b1, v_b2);
|
||||
int p = power;
|
||||
|
||||
@@ -772,6 +770,7 @@ struct iPow_SIMD<uchar, int>
|
||||
v = v_pack(v_a1, v_a2);
|
||||
v_pack_store(dst + i, v);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -783,13 +782,13 @@ struct iPow_SIMD<schar, int>
|
||||
int operator() ( const schar * src, schar * dst, int len, int power)
|
||||
{
|
||||
int i = 0;
|
||||
v_int32x4 v_1 = v_setall_s32(1);
|
||||
v_int32 v_1 = vx_setall_s32(1);
|
||||
|
||||
for ( ; i <= len - 8; i += 8)
|
||||
for ( ; i <= len - v_int16::nlanes; i += v_int16::nlanes)
|
||||
{
|
||||
v_int32x4 v_a1 = v_1, v_a2 = v_1;
|
||||
v_int16x8 v = v_load_expand(src + i);
|
||||
v_int32x4 v_b1, v_b2;
|
||||
v_int32 v_a1 = v_1, v_a2 = v_1;
|
||||
v_int16 v = vx_load_expand(src + i);
|
||||
v_int32 v_b1, v_b2;
|
||||
v_expand(v, v_b1, v_b2);
|
||||
int p = power;
|
||||
|
||||
@@ -811,6 +810,7 @@ struct iPow_SIMD<schar, int>
|
||||
v = v_pack(v_a1, v_a2);
|
||||
v_pack_store(dst + i, v);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -822,13 +822,13 @@ struct iPow_SIMD<ushort, int>
|
||||
int operator() ( const ushort * src, ushort * dst, int len, int power)
|
||||
{
|
||||
int i = 0;
|
||||
v_uint32x4 v_1 = v_setall_u32(1u);
|
||||
v_uint32 v_1 = vx_setall_u32(1u);
|
||||
|
||||
for ( ; i <= len - 8; i += 8)
|
||||
for ( ; i <= len - v_uint16::nlanes; i += v_uint16::nlanes)
|
||||
{
|
||||
v_uint32x4 v_a1 = v_1, v_a2 = v_1;
|
||||
v_uint16x8 v = v_load(src + i);
|
||||
v_uint32x4 v_b1, v_b2;
|
||||
v_uint32 v_a1 = v_1, v_a2 = v_1;
|
||||
v_uint16 v = vx_load(src + i);
|
||||
v_uint32 v_b1, v_b2;
|
||||
v_expand(v, v_b1, v_b2);
|
||||
int p = power;
|
||||
|
||||
@@ -850,6 +850,7 @@ struct iPow_SIMD<ushort, int>
|
||||
v = v_pack(v_a1, v_a2);
|
||||
v_store(dst + i, v);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -861,13 +862,13 @@ struct iPow_SIMD<short, int>
|
||||
int operator() ( const short * src, short * dst, int len, int power)
|
||||
{
|
||||
int i = 0;
|
||||
v_int32x4 v_1 = v_setall_s32(1);
|
||||
v_int32 v_1 = vx_setall_s32(1);
|
||||
|
||||
for ( ; i <= len - 8; i += 8)
|
||||
for ( ; i <= len - v_int16::nlanes; i += v_int16::nlanes)
|
||||
{
|
||||
v_int32x4 v_a1 = v_1, v_a2 = v_1;
|
||||
v_int16x8 v = v_load(src + i);
|
||||
v_int32x4 v_b1, v_b2;
|
||||
v_int32 v_a1 = v_1, v_a2 = v_1;
|
||||
v_int16 v = vx_load(src + i);
|
||||
v_int32 v_b1, v_b2;
|
||||
v_expand(v, v_b1, v_b2);
|
||||
int p = power;
|
||||
|
||||
@@ -889,6 +890,7 @@ struct iPow_SIMD<short, int>
|
||||
v = v_pack(v_a1, v_a2);
|
||||
v_store(dst + i, v);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -900,12 +902,12 @@ struct iPow_SIMD<int, int>
|
||||
int operator() ( const int * src, int * dst, int len, int power)
|
||||
{
|
||||
int i = 0;
|
||||
v_int32x4 v_1 = v_setall_s32(1);
|
||||
v_int32 v_1 = vx_setall_s32(1);
|
||||
|
||||
for ( ; i <= len - 8; i += 8)
|
||||
for ( ; i <= len - v_int32::nlanes*2; i += v_int32::nlanes*2)
|
||||
{
|
||||
v_int32x4 v_a1 = v_1, v_a2 = v_1;
|
||||
v_int32x4 v_b1 = v_load(src + i), v_b2 = v_load(src + i + 4);
|
||||
v_int32 v_a1 = v_1, v_a2 = v_1;
|
||||
v_int32 v_b1 = vx_load(src + i), v_b2 = vx_load(src + i + v_int32::nlanes);
|
||||
int p = power;
|
||||
|
||||
while( p > 1 )
|
||||
@@ -924,8 +926,9 @@ struct iPow_SIMD<int, int>
|
||||
v_a2 *= v_b2;
|
||||
|
||||
v_store(dst + i, v_a1);
|
||||
v_store(dst + i + 4, v_a2);
|
||||
v_store(dst + i + v_int32::nlanes, v_a2);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -937,12 +940,12 @@ struct iPow_SIMD<float, float>
|
||||
int operator() ( const float * src, float * dst, int len, int power)
|
||||
{
|
||||
int i = 0;
|
||||
v_float32x4 v_1 = v_setall_f32(1.f);
|
||||
v_float32 v_1 = vx_setall_f32(1.f);
|
||||
|
||||
for ( ; i <= len - 8; i += 8)
|
||||
for ( ; i <= len - v_float32::nlanes*2; i += v_float32::nlanes*2)
|
||||
{
|
||||
v_float32x4 v_a1 = v_1, v_a2 = v_1;
|
||||
v_float32x4 v_b1 = v_load(src + i), v_b2 = v_load(src + i + 4);
|
||||
v_float32 v_a1 = v_1, v_a2 = v_1;
|
||||
v_float32 v_b1 = vx_load(src + i), v_b2 = vx_load(src + i + v_float32::nlanes);
|
||||
int p = std::abs(power);
|
||||
if( power < 0 )
|
||||
{
|
||||
@@ -966,26 +969,27 @@ struct iPow_SIMD<float, float>
|
||||
v_a2 *= v_b2;
|
||||
|
||||
v_store(dst + i, v_a1);
|
||||
v_store(dst + i + 4, v_a2);
|
||||
v_store(dst + i + v_float32::nlanes, v_a2);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
#if CV_SIMD128_64F
|
||||
#if CV_SIMD_64F
|
||||
template <>
|
||||
struct iPow_SIMD<double, double>
|
||||
{
|
||||
int operator() ( const double * src, double * dst, int len, int power)
|
||||
{
|
||||
int i = 0;
|
||||
v_float64x2 v_1 = v_setall_f64(1.);
|
||||
v_float64 v_1 = vx_setall_f64(1.);
|
||||
|
||||
for ( ; i <= len - 4; i += 4)
|
||||
for ( ; i <= len - v_float64::nlanes*2; i += v_float64::nlanes*2)
|
||||
{
|
||||
v_float64x2 v_a1 = v_1, v_a2 = v_1;
|
||||
v_float64x2 v_b1 = v_load(src + i), v_b2 = v_load(src + i + 2);
|
||||
v_float64 v_a1 = v_1, v_a2 = v_1;
|
||||
v_float64 v_b1 = vx_load(src + i), v_b2 = vx_load(src + i + v_float64::nlanes);
|
||||
int p = std::abs(power);
|
||||
if( power < 0 )
|
||||
{
|
||||
@@ -1009,8 +1013,9 @@ struct iPow_SIMD<double, double>
|
||||
v_a2 *= v_b2;
|
||||
|
||||
v_store(dst + i, v_a1);
|
||||
v_store(dst + i + 2, v_a2);
|
||||
v_store(dst + i + v_float64::nlanes, v_a2);
|
||||
}
|
||||
vx_cleanup();
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -1272,10 +1277,17 @@ void pow( InputArray _src, double power, OutputArray _dst )
|
||||
Cv64suf inf64, nan64;
|
||||
float* fbuf = 0;
|
||||
double* dbuf = 0;
|
||||
#ifndef __EMSCRIPTEN__
|
||||
inf32.i = 0x7f800000;
|
||||
nan32.i = 0x7fffffff;
|
||||
inf64.i = CV_BIG_INT(0x7FF0000000000000);
|
||||
nan64.i = CV_BIG_INT(0x7FFFFFFFFFFFFFFF);
|
||||
#else
|
||||
inf32.f = std::numeric_limits<float>::infinity();
|
||||
nan32.f = std::numeric_limits<float>::quiet_NaN();
|
||||
inf64.f = std::numeric_limits<double>::infinity();
|
||||
nan64.f = std::numeric_limits<double>::quiet_NaN();
|
||||
#endif
|
||||
|
||||
if( src.ptr() == dst.ptr() )
|
||||
{
|
||||
@@ -1595,9 +1607,9 @@ void patchNaNs( InputOutputArray _a, double _val )
|
||||
Cv32suf val;
|
||||
val.f = (float)_val;
|
||||
|
||||
#if CV_SIMD128
|
||||
v_int32x4 v_mask1 = v_setall_s32(0x7fffffff), v_mask2 = v_setall_s32(0x7f800000);
|
||||
v_int32x4 v_val = v_setall_s32(val.i);
|
||||
#if CV_SIMD
|
||||
v_int32 v_mask1 = vx_setall_s32(0x7fffffff), v_mask2 = vx_setall_s32(0x7f800000);
|
||||
v_int32 v_val = vx_setall_s32(val.i);
|
||||
#endif
|
||||
|
||||
for( size_t i = 0; i < it.nplanes; i++, ++it )
|
||||
@@ -1605,18 +1617,16 @@ void patchNaNs( InputOutputArray _a, double _val )
|
||||
int* tptr = ptrs[0];
|
||||
size_t j = 0;
|
||||
|
||||
#if CV_SIMD128
|
||||
if( hasSIMD128() )
|
||||
#if CV_SIMD
|
||||
size_t cWidth = (size_t)v_int32::nlanes;
|
||||
for ( ; j + cWidth <= len; j += cWidth)
|
||||
{
|
||||
size_t cWidth = (size_t)v_int32x4::nlanes;
|
||||
for ( ; j + cWidth <= len; j += cWidth)
|
||||
{
|
||||
v_int32x4 v_src = v_load(tptr + j);
|
||||
v_int32x4 v_cmp_mask = v_mask2 < (v_src & v_mask1);
|
||||
v_int32x4 v_dst = v_select(v_cmp_mask, v_val, v_src);
|
||||
v_store(tptr + j, v_dst);
|
||||
}
|
||||
v_int32 v_src = vx_load(tptr + j);
|
||||
v_int32 v_cmp_mask = v_mask2 < (v_src & v_mask1);
|
||||
v_int32 v_dst = v_select(v_cmp_mask, v_val, v_src);
|
||||
v_store(tptr + j, v_dst);
|
||||
}
|
||||
vx_cleanup();
|
||||
#endif
|
||||
|
||||
for( ; j < len; j++ )
|
||||
|
||||
@@ -27,16 +27,26 @@ float fastAtan2(float y, float x);
|
||||
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static inline float atan_f32(float y, float x)
|
||||
{
|
||||
float a = atan2(y, x) * 180.0f / CV_PI;
|
||||
if (a < 0.0f)
|
||||
a += 360.0f;
|
||||
if (a >= 360.0f)
|
||||
a -= 360.0f;
|
||||
return a; // range [0; 360)
|
||||
}
|
||||
#else
|
||||
static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI);
|
||||
static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI);
|
||||
static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI);
|
||||
static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI);
|
||||
|
||||
using namespace cv;
|
||||
|
||||
static inline float atan_f32(float y, float x)
|
||||
{
|
||||
float ax = std::abs(x), ay = std::abs(y);
|
||||
@@ -59,6 +69,7 @@ static inline float atan_f32(float y, float x)
|
||||
a = 360.f - a;
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CV_SIMD
|
||||
|
||||
@@ -363,7 +374,7 @@ void sqrt64f(const double* src, double* dst, int len)
|
||||
// Workaround for ICE in MSVS 2015 update 3 (issue #7795)
|
||||
// CV_AVX is not used here, because generated code is faster in non-AVX mode.
|
||||
// (tested with disabled IPP on i5-6300U)
|
||||
#if (defined _MSC_VER && _MSC_VER >= 1900)
|
||||
#if (defined _MSC_VER && _MSC_VER >= 1900) || defined(__EMSCRIPTEN__)
|
||||
void exp32f(const float *src, float *dst, int n)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
+83
-105
@@ -2310,18 +2310,12 @@ static void scaleAdd_32f(const float* src1, const float* src2, float* dst,
|
||||
{
|
||||
float alpha = *_alpha;
|
||||
int i = 0;
|
||||
#if CV_SIMD128
|
||||
if (hasSIMD128())
|
||||
{
|
||||
v_float32x4 v_alpha = v_setall_f32(alpha);
|
||||
const int cWidth = v_float32x4::nlanes;
|
||||
for (; i <= len - cWidth; i += cWidth)
|
||||
{
|
||||
v_float32x4 v_src1 = v_load(src1 + i);
|
||||
v_float32x4 v_src2 = v_load(src2 + i);
|
||||
v_store(dst + i, (v_src1 * v_alpha) + v_src2);
|
||||
}
|
||||
}
|
||||
#if CV_SIMD
|
||||
v_float32 v_alpha = vx_setall_f32(alpha);
|
||||
const int cWidth = v_float32::nlanes;
|
||||
for (; i <= len - cWidth; i += cWidth)
|
||||
v_store(dst + i, v_muladd(vx_load(src1 + i), v_alpha, vx_load(src2 + i)));
|
||||
vx_cleanup();
|
||||
#endif
|
||||
for (; i < len; i++)
|
||||
dst[i] = src1[i] * alpha + src2[i];
|
||||
@@ -2333,22 +2327,12 @@ static void scaleAdd_64f(const double* src1, const double* src2, double* dst,
|
||||
{
|
||||
double alpha = *_alpha;
|
||||
int i = 0;
|
||||
#if CV_SIMD128_64F
|
||||
if (hasSIMD128())
|
||||
{
|
||||
v_float64x2 a2 = v_setall_f64(alpha);
|
||||
const int cWidth = v_float64x2::nlanes;
|
||||
for (; i <= len - cWidth * 2; i += cWidth * 2)
|
||||
{
|
||||
v_float64x2 x0, x1, y0, y1, t0, t1;
|
||||
x0 = v_load(src1 + i); x1 = v_load(src1 + i + cWidth);
|
||||
y0 = v_load(src2 + i); y1 = v_load(src2 + i + cWidth);
|
||||
t0 = x0 * a2 + y0;
|
||||
t1 = x1 * a2 + y1;
|
||||
v_store(dst + i, t0);
|
||||
v_store(dst + i + cWidth, t1);
|
||||
}
|
||||
}
|
||||
#if CV_SIMD_64F
|
||||
v_float64 a2 = vx_setall_f64(alpha);
|
||||
const int cWidth = v_float64::nlanes;
|
||||
for (; i <= len - cWidth; i += cWidth)
|
||||
v_store(dst + i, v_muladd(vx_load(src1 + i), a2, vx_load(src2 + i)));
|
||||
vx_cleanup();
|
||||
#endif
|
||||
for (; i < len; i++)
|
||||
dst[i] = src1[i] * alpha + src2[i];
|
||||
@@ -3025,42 +3009,40 @@ static double dotProd_8u(const uchar* src1, const uchar* src2, int len)
|
||||
#endif
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD128
|
||||
if (hasSIMD128())
|
||||
#if CV_SIMD
|
||||
int len0 = len & -v_uint16::nlanes, blockSize0 = (1 << 15), blockSize;
|
||||
|
||||
while (i < len0)
|
||||
{
|
||||
int len0 = len & -8, blockSize0 = (1 << 15), blockSize;
|
||||
blockSize = std::min(len0 - i, blockSize0);
|
||||
v_int32 v_sum = vx_setzero_s32();
|
||||
const int cWidth = v_uint16::nlanes;
|
||||
|
||||
while (i < len0)
|
||||
int j = 0;
|
||||
for (; j <= blockSize - cWidth * 2; j += cWidth * 2)
|
||||
{
|
||||
blockSize = std::min(len0 - i, blockSize0);
|
||||
v_int32x4 v_sum = v_setzero_s32();
|
||||
const int cWidth = v_uint16x8::nlanes;
|
||||
v_uint16 v_src10, v_src20, v_src11, v_src21;
|
||||
v_expand(vx_load(src1 + j), v_src10, v_src11);
|
||||
v_expand(vx_load(src2 + j), v_src20, v_src21);
|
||||
|
||||
int j = 0;
|
||||
for (; j <= blockSize - cWidth * 2; j += cWidth * 2)
|
||||
{
|
||||
v_uint16x8 v_src10, v_src20, v_src11, v_src21;
|
||||
v_expand(v_load(src1 + j), v_src10, v_src11);
|
||||
v_expand(v_load(src2 + j), v_src20, v_src21);
|
||||
|
||||
v_sum += v_dotprod(v_reinterpret_as_s16(v_src10), v_reinterpret_as_s16(v_src20));
|
||||
v_sum += v_dotprod(v_reinterpret_as_s16(v_src11), v_reinterpret_as_s16(v_src21));
|
||||
}
|
||||
|
||||
for (; j <= blockSize - cWidth; j += cWidth)
|
||||
{
|
||||
v_int16x8 v_src10 = v_reinterpret_as_s16(v_load_expand(src1 + j));
|
||||
v_int16x8 v_src20 = v_reinterpret_as_s16(v_load_expand(src2 + j));
|
||||
|
||||
v_sum += v_dotprod(v_src10, v_src20);
|
||||
}
|
||||
r += (double)v_reduce_sum(v_sum);
|
||||
|
||||
src1 += blockSize;
|
||||
src2 += blockSize;
|
||||
i += blockSize;
|
||||
v_sum += v_dotprod(v_reinterpret_as_s16(v_src10), v_reinterpret_as_s16(v_src20));
|
||||
v_sum += v_dotprod(v_reinterpret_as_s16(v_src11), v_reinterpret_as_s16(v_src21));
|
||||
}
|
||||
|
||||
for (; j <= blockSize - cWidth; j += cWidth)
|
||||
{
|
||||
v_int16 v_src10 = v_reinterpret_as_s16(vx_load_expand(src1 + j));
|
||||
v_int16 v_src20 = v_reinterpret_as_s16(vx_load_expand(src2 + j));
|
||||
|
||||
v_sum += v_dotprod(v_src10, v_src20);
|
||||
}
|
||||
r += (double)v_reduce_sum(v_sum);
|
||||
|
||||
src1 += blockSize;
|
||||
src2 += blockSize;
|
||||
i += blockSize;
|
||||
}
|
||||
vx_cleanup();
|
||||
#elif CV_NEON
|
||||
if( cv::checkHardwareSupport(CV_CPU_NEON) )
|
||||
{
|
||||
@@ -3113,42 +3095,40 @@ static double dotProd_8s(const schar* src1, const schar* src2, int len)
|
||||
double r = 0.0;
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD128
|
||||
if (hasSIMD128())
|
||||
#if CV_SIMD
|
||||
int len0 = len & -v_int16::nlanes, blockSize0 = (1 << 14), blockSize;
|
||||
|
||||
while (i < len0)
|
||||
{
|
||||
int len0 = len & -8, blockSize0 = (1 << 14), blockSize;
|
||||
blockSize = std::min(len0 - i, blockSize0);
|
||||
v_int32 v_sum = vx_setzero_s32();
|
||||
const int cWidth = v_int16::nlanes;
|
||||
|
||||
while (i < len0)
|
||||
int j = 0;
|
||||
for (; j <= blockSize - cWidth * 2; j += cWidth * 2)
|
||||
{
|
||||
blockSize = std::min(len0 - i, blockSize0);
|
||||
v_int32x4 v_sum = v_setzero_s32();
|
||||
const int cWidth = v_int16x8::nlanes;
|
||||
v_int16 v_src10, v_src20, v_src11, v_src21;
|
||||
v_expand(vx_load(src1 + j), v_src10, v_src11);
|
||||
v_expand(vx_load(src2 + j), v_src20, v_src21);
|
||||
|
||||
int j = 0;
|
||||
for (; j <= blockSize - cWidth * 2; j += cWidth * 2)
|
||||
{
|
||||
v_int16x8 v_src10, v_src20, v_src11, v_src21;
|
||||
v_expand(v_load(src1 + j), v_src10, v_src11);
|
||||
v_expand(v_load(src2 + j), v_src20, v_src21);
|
||||
|
||||
v_sum += v_dotprod(v_src10, v_src20);
|
||||
v_sum += v_dotprod(v_src11, v_src21);
|
||||
}
|
||||
|
||||
for (; j <= blockSize - cWidth; j += cWidth)
|
||||
{
|
||||
v_int16x8 v_src10 = v_load_expand(src1 + j);
|
||||
v_int16x8 v_src20 = v_load_expand(src2 + j);
|
||||
|
||||
v_sum += v_dotprod(v_src10, v_src20);
|
||||
}
|
||||
r += (double)v_reduce_sum(v_sum);
|
||||
|
||||
src1 += blockSize;
|
||||
src2 += blockSize;
|
||||
i += blockSize;
|
||||
v_sum += v_dotprod(v_src10, v_src20);
|
||||
v_sum += v_dotprod(v_src11, v_src21);
|
||||
}
|
||||
|
||||
for (; j <= blockSize - cWidth; j += cWidth)
|
||||
{
|
||||
v_int16 v_src10 = vx_load_expand(src1 + j);
|
||||
v_int16 v_src20 = vx_load_expand(src2 + j);
|
||||
|
||||
v_sum += v_dotprod(v_src10, v_src20);
|
||||
}
|
||||
r += (double)v_reduce_sum(v_sum);
|
||||
|
||||
src1 += blockSize;
|
||||
src2 += blockSize;
|
||||
i += blockSize;
|
||||
}
|
||||
vx_cleanup();
|
||||
#elif CV_NEON
|
||||
if( cv::checkHardwareSupport(CV_CPU_NEON) )
|
||||
{
|
||||
@@ -3232,28 +3212,26 @@ static double dotProd_32f(const float* src1, const float* src2, int len)
|
||||
#endif
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD128
|
||||
if (hasSIMD128())
|
||||
#if CV_SIMD
|
||||
int len0 = len & -v_float32::nlanes, blockSize0 = (1 << 13), blockSize;
|
||||
|
||||
while (i < len0)
|
||||
{
|
||||
int len0 = len & -4, blockSize0 = (1 << 13), blockSize;
|
||||
blockSize = std::min(len0 - i, blockSize0);
|
||||
v_float32 v_sum = vx_setzero_f32();
|
||||
|
||||
while (i < len0)
|
||||
{
|
||||
blockSize = std::min(len0 - i, blockSize0);
|
||||
v_float32x4 v_sum = v_setzero_f32();
|
||||
int j = 0;
|
||||
int cWidth = v_float32::nlanes;
|
||||
for (; j <= blockSize - cWidth; j += cWidth)
|
||||
v_sum = v_muladd(vx_load(src1 + j), vx_load(src2 + j), v_sum);
|
||||
|
||||
int j = 0;
|
||||
int cWidth = v_float32x4::nlanes;
|
||||
for (; j <= blockSize - cWidth; j += cWidth)
|
||||
v_sum = v_muladd(v_load(src1 + j), v_load(src2 + j), v_sum);
|
||||
r += v_reduce_sum(v_sum);
|
||||
|
||||
r += v_reduce_sum(v_sum);
|
||||
|
||||
src1 += blockSize;
|
||||
src2 += blockSize;
|
||||
i += blockSize;
|
||||
}
|
||||
src1 += blockSize;
|
||||
src2 += blockSize;
|
||||
i += blockSize;
|
||||
}
|
||||
vx_cleanup();
|
||||
#endif
|
||||
return r + dotProd_(src1, src2, len - i);
|
||||
}
|
||||
|
||||
@@ -407,10 +407,13 @@ template<typename R> struct TheTest
|
||||
|
||||
Data<Rx2> resB = vx_load_expand(dataA.d);
|
||||
|
||||
Rx2 c, d;
|
||||
Rx2 c, d, e, f;
|
||||
v_expand(a, c, d);
|
||||
|
||||
Data<Rx2> resC = c, resD = d;
|
||||
e = v_expand_low(a);
|
||||
f = v_expand_high(a);
|
||||
|
||||
Data<Rx2> resC = c, resD = d, resE = e, resF = f;
|
||||
const int n = Rx2::nlanes;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
@@ -418,6 +421,8 @@ template<typename R> struct TheTest
|
||||
EXPECT_EQ(dataA[i], resB[i]);
|
||||
EXPECT_EQ(dataA[i], resC[i]);
|
||||
EXPECT_EQ(dataA[i + n], resD[i]);
|
||||
EXPECT_EQ(dataA[i], resE[i]);
|
||||
EXPECT_EQ(dataA[i + n], resF[i]);
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -455,19 +460,21 @@ template<typename R> struct TheTest
|
||||
return *this;
|
||||
}
|
||||
|
||||
TheTest & test_addsub_wrap()
|
||||
TheTest & test_arithm_wrap()
|
||||
{
|
||||
Data<R> dataA, dataB;
|
||||
dataB.reverse();
|
||||
R a = dataA, b = dataB;
|
||||
|
||||
Data<R> resC = v_add_wrap(a, b),
|
||||
resD = v_sub_wrap(a, b);
|
||||
resD = v_sub_wrap(a, b),
|
||||
resE = v_mul_wrap(a, b);
|
||||
for (int i = 0; i < R::nlanes; ++i)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("i=%d", i));
|
||||
EXPECT_EQ((LaneType)(dataA[i] + dataB[i]), resC[i]);
|
||||
EXPECT_EQ((LaneType)(dataA[i] - dataB[i]), resD[i]);
|
||||
EXPECT_EQ((LaneType)(dataA[i] * dataB[i]), resE[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -475,6 +482,7 @@ template<typename R> struct TheTest
|
||||
TheTest & test_mul()
|
||||
{
|
||||
Data<R> dataA, dataB;
|
||||
dataA[1] = static_cast<LaneType>(std::numeric_limits<LaneType>::max());
|
||||
dataB.reverse();
|
||||
R a = dataA, b = dataB;
|
||||
|
||||
@@ -482,7 +490,7 @@ template<typename R> struct TheTest
|
||||
for (int i = 0; i < R::nlanes; ++i)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("i=%d", i));
|
||||
EXPECT_EQ(dataA[i] * dataB[i], resC[i]);
|
||||
EXPECT_EQ(saturate_cast<LaneType>(dataA[i] * dataB[i]), resC[i]);
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -1209,7 +1217,9 @@ void test_hal_intrin_uint8()
|
||||
.test_expand()
|
||||
.test_expand_q()
|
||||
.test_addsub()
|
||||
.test_addsub_wrap()
|
||||
.test_arithm_wrap()
|
||||
.test_mul()
|
||||
.test_mul_expand()
|
||||
.test_cmp()
|
||||
.test_logic()
|
||||
.test_min_max()
|
||||
@@ -1242,7 +1252,9 @@ void test_hal_intrin_int8()
|
||||
.test_expand()
|
||||
.test_expand_q()
|
||||
.test_addsub()
|
||||
.test_addsub_wrap()
|
||||
.test_arithm_wrap()
|
||||
.test_mul()
|
||||
.test_mul_expand()
|
||||
.test_cmp()
|
||||
.test_logic()
|
||||
.test_min_max()
|
||||
@@ -1267,7 +1279,7 @@ void test_hal_intrin_uint16()
|
||||
.test_interleave()
|
||||
.test_expand()
|
||||
.test_addsub()
|
||||
.test_addsub_wrap()
|
||||
.test_arithm_wrap()
|
||||
.test_mul()
|
||||
.test_mul_expand()
|
||||
.test_cmp()
|
||||
@@ -1295,7 +1307,7 @@ void test_hal_intrin_int16()
|
||||
.test_interleave()
|
||||
.test_expand()
|
||||
.test_addsub()
|
||||
.test_addsub_wrap()
|
||||
.test_arithm_wrap()
|
||||
.test_mul()
|
||||
.test_mul_expand()
|
||||
.test_cmp()
|
||||
|
||||
Reference in New Issue
Block a user