mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge pull request #9753 from tomoaki0705:universalMatmul
* add accuracy test and performance check for matmul * add performance tests for transform and dotProduct * add test Core_TransformLargeTest for 8u version of transform * remove raw SSE2/NEON implementation from matmul.cpp * use universal intrinsic instead of raw intrinsic * remove unused templated function * add v_matmuladd which multiply 3x3 matrix and add 3x1 vector * add v_rotate_left/right in universal intrinsic * suppress intrinsic on some function and platform * add pure SW implementation of new universal intrinsics * add test for new universal intrinsics * core: prevent memory access after the end of buffer * fix perf tests
This commit is contained in:
committed by
Alexander Alekhin
parent
2674c6b5e0
commit
3cbe60cca2
@@ -885,12 +885,59 @@ template<typename _Tp, int n> inline v_reg<_Tp, n> operator shift_op(const v_reg
|
||||
/** @brief Bitwise shift left
|
||||
|
||||
For 16-, 32- and 64-bit integer values. */
|
||||
OPENCV_HAL_IMPL_SHIFT_OP(<<)
|
||||
OPENCV_HAL_IMPL_SHIFT_OP(<< )
|
||||
|
||||
/** @brief Bitwise shift right
|
||||
|
||||
For 16-, 32- and 64-bit integer values. */
|
||||
OPENCV_HAL_IMPL_SHIFT_OP(>>)
|
||||
OPENCV_HAL_IMPL_SHIFT_OP(>> )
|
||||
|
||||
/** @brief Element shift left among vector
|
||||
|
||||
For all type */
|
||||
#define OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(suffix,opA,opB) \
|
||||
template<int imm, typename _Tp, int n> inline v_reg<_Tp, n> v_rotate_##suffix(const v_reg<_Tp, n>& a) \
|
||||
{ \
|
||||
v_reg<_Tp, n> b; \
|
||||
for (int i = 0; i < n; i++) \
|
||||
{ \
|
||||
int sIndex = i opA imm; \
|
||||
if (0 <= sIndex && sIndex < n) \
|
||||
{ \
|
||||
b.s[i] = a.s[sIndex]; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
b.s[i] = 0; \
|
||||
} \
|
||||
} \
|
||||
return b; \
|
||||
} \
|
||||
template<int imm, typename _Tp, int n> inline v_reg<_Tp, n> v_rotate_##suffix(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \
|
||||
{ \
|
||||
v_reg<_Tp, n> c; \
|
||||
for (int i = 0; i < n; i++) \
|
||||
{ \
|
||||
int aIndex = i opA imm; \
|
||||
int bIndex = i opA imm opB n; \
|
||||
if (0 <= bIndex && bIndex < n) \
|
||||
{ \
|
||||
c.s[i] = b.s[bIndex]; \
|
||||
} \
|
||||
else if (0 <= aIndex && aIndex < n) \
|
||||
{ \
|
||||
c.s[i] = a.s[aIndex]; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
c.s[i] = 0; \
|
||||
} \
|
||||
} \
|
||||
return c; \
|
||||
}
|
||||
|
||||
OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(left, -, +)
|
||||
OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(right, +, -)
|
||||
|
||||
/** @brief Sum packed values
|
||||
|
||||
@@ -1860,6 +1907,30 @@ inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0,
|
||||
v.s[0]*m0.s[3] + v.s[1]*m1.s[3] + v.s[2]*m2.s[3] + v.s[3]*m3.s[3]);
|
||||
}
|
||||
|
||||
/** @brief Matrix multiplication and add
|
||||
|
||||
Scheme:
|
||||
@code
|
||||
{A0 A1 A2 } |V0| |D0|
|
||||
{B0 B1 B2 } |V1| |D1|
|
||||
{C0 C1 C2 } x |V2| + |D2|
|
||||
====================
|
||||
{R0 R1 R2 R3}, where:
|
||||
R0 = A0V0 + A1V1 + A2V2 + D0,
|
||||
R1 = B0V0 + B1V1 + B2V2 + D1
|
||||
...
|
||||
@endcode
|
||||
*/
|
||||
inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0,
|
||||
const v_float32x4& m1, const v_float32x4& m2,
|
||||
const v_float32x4& m3)
|
||||
{
|
||||
return v_float32x4(v.s[0]*m0.s[0] + v.s[1]*m1.s[0] + v.s[2]*m2.s[0] + m3.s[0],
|
||||
v.s[0]*m0.s[1] + v.s[1]*m1.s[1] + v.s[2]*m2.s[1] + m3.s[1],
|
||||
v.s[0]*m0.s[2] + v.s[1]*m1.s[2] + v.s[2]*m2.s[2] + m3.s[2],
|
||||
v.s[0]*m0.s[3] + v.s[1]*m1.s[3] + v.s[2]*m2.s[3] + m3.s[3]);
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
//! @name Check SIMD support
|
||||
|
||||
@@ -407,6 +407,18 @@ inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0,
|
||||
return v_float32x4(res);
|
||||
}
|
||||
|
||||
inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0,
|
||||
const v_float32x4& m1, const v_float32x4& m2,
|
||||
const v_float32x4& a)
|
||||
{
|
||||
float32x2_t vl = vget_low_f32(v.val), vh = vget_high_f32(v.val);
|
||||
float32x4_t res = vmulq_lane_f32(m0.val, vl, 0);
|
||||
res = vmlaq_lane_f32(res, m1.val, vl, 1);
|
||||
res = vmlaq_lane_f32(res, m2.val, vh, 0);
|
||||
res = vaddq_f32(res, a.val);
|
||||
return v_float32x4(res);
|
||||
}
|
||||
|
||||
#define OPENCV_HAL_IMPL_NEON_BIN_OP(bin_op, _Tpvec, intrin) \
|
||||
inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \
|
||||
{ \
|
||||
@@ -747,7 +759,15 @@ template<int n> inline _Tpvec v_shl(const _Tpvec& a) \
|
||||
template<int n> inline _Tpvec v_shr(const _Tpvec& a) \
|
||||
{ return _Tpvec(vshrq_n_##suffix(a.val, n)); } \
|
||||
template<int n> inline _Tpvec v_rshr(const _Tpvec& a) \
|
||||
{ return _Tpvec(vrshrq_n_##suffix(a.val, n)); }
|
||||
{ return _Tpvec(vrshrq_n_##suffix(a.val, n)); } \
|
||||
template<int n> inline _Tpvec v_rotate_right(const _Tpvec& a) \
|
||||
{ return _Tpvec(vextq_##suffix(a.val, vdupq_n_##suffix(0), n)); } \
|
||||
template<int n> inline _Tpvec v_rotate_left(const _Tpvec& a) \
|
||||
{ return _Tpvec(vextq_##suffix(vdupq_n_##suffix(0), a.val, _Tpvec::nlanes - n)); } \
|
||||
template<int n> inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vextq_##suffix(a.val, b.val, n)); } \
|
||||
template<int n> inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \
|
||||
{ return _Tpvec(vextq_##suffix(b.val, a.val, _Tpvec::nlanes - n)); }
|
||||
|
||||
OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint8x16, u8, schar, s8)
|
||||
OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int8x16, s8, schar, s8)
|
||||
|
||||
@@ -602,6 +602,16 @@ inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0,
|
||||
return v_float32x4(_mm_add_ps(_mm_add_ps(v0, v1), _mm_add_ps(v2, v3)));
|
||||
}
|
||||
|
||||
inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0,
|
||||
const v_float32x4& m1, const v_float32x4& m2,
|
||||
const v_float32x4& a)
|
||||
{
|
||||
__m128 v0 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(0, 0, 0, 0)), m0.val);
|
||||
__m128 v1 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(1, 1, 1, 1)), m1.val);
|
||||
__m128 v2 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(2, 2, 2, 2)), m2.val);
|
||||
|
||||
return v_float32x4(_mm_add_ps(_mm_add_ps(v0, v1), _mm_add_ps(v2, a.val)));
|
||||
}
|
||||
|
||||
#define OPENCV_HAL_IMPL_SSE_BIN_OP(bin_op, _Tpvec, intrin) \
|
||||
inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \
|
||||
@@ -1011,6 +1021,29 @@ OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint16x8, v_int16x8, epi16, _mm_srai_epi16)
|
||||
OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint32x4, v_int32x4, epi32, _mm_srai_epi32)
|
||||
OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint64x2, v_int64x2, epi64, v_srai_epi64)
|
||||
|
||||
template<int imm, typename _Tpvec>
|
||||
inline _Tpvec v_rotate_right(const _Tpvec &a)
|
||||
{
|
||||
return _Tpvec(_mm_srli_si128(a.val, imm*(sizeof(typename _Tpvec::lane_type))));
|
||||
}
|
||||
template<int imm, typename _Tpvec>
|
||||
inline _Tpvec v_rotate_left(const _Tpvec &a)
|
||||
{
|
||||
return _Tpvec(_mm_slli_si128(a.val, imm*(sizeof(typename _Tpvec::lane_type))));
|
||||
}
|
||||
template<int imm, typename _Tpvec>
|
||||
inline _Tpvec v_rotate_right(const _Tpvec &a, const _Tpvec &b)
|
||||
{
|
||||
const int cWidth = sizeof(typename _Tpvec::lane_type);
|
||||
return _Tpvec(_mm_or_si128(_mm_srli_si128(a.val, imm*cWidth), _mm_slli_si128(b.val, (16 - imm*cWidth))));
|
||||
}
|
||||
template<int imm, typename _Tpvec>
|
||||
inline _Tpvec v_rotate_left(const _Tpvec &a, const _Tpvec &b)
|
||||
{
|
||||
const int cWidth = sizeof(typename _Tpvec::lane_type);
|
||||
return _Tpvec(_mm_or_si128(_mm_slli_si128(a.val, imm*cWidth), _mm_srli_si128(b.val, (16 - imm*cWidth))));
|
||||
}
|
||||
|
||||
#define OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(_Tpvec, _Tp) \
|
||||
inline _Tpvec v_load(const _Tp* ptr) \
|
||||
{ return _Tpvec(_mm_loadu_si128((const __m128i*)ptr)); } \
|
||||
|
||||
Reference in New Issue
Block a user