// 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. // This file is not standalone. // It is included with these active namespaces: //namespace opencv_test { namespace hal { namespace intrinXXX { //CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN void test_hal_intrin_uint8(); void test_hal_intrin_int8(); void test_hal_intrin_uint16(); void test_hal_intrin_int16(); void test_hal_intrin_uint32(); void test_hal_intrin_int32(); void test_hal_intrin_uint64(); void test_hal_intrin_int64(); void test_hal_intrin_float32(); void test_hal_intrin_float64(); void test_hal_intrin_float16(); #ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY //================================================================================================== #if defined (__clang__) && defined(__has_warning) #if __has_warning("-Wmaybe-uninitialized") #define CV_DISABLE_GCC_MAYBE_UNINITIALIZED_WARNINGS #endif #elif defined (__GNUC__) // in case of gcc, it does not have macro __has_warning #define CV_DISABLE_GCC_MAYBE_UNINITIALIZED_WARNINGS #endif #if defined (CV_DISABLE_GCC_MAYBE_UNINITIALIZED_WARNINGS) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif template struct Data { typedef typename VTraits::lane_type LaneType; typedef typename V_TypeTraits::int_type int_type; Data() { for (int i = 0; i < VTraits::vlanes(); ++i) d[i] = (LaneType)(i + 1); } Data(LaneType val) { fill(val); } Data(const R & r) { *this = r; } operator R () const { CV_Assert(VTraits::vlanes() <= VTraits::max_nlanes); return vx_load(d); } Data & operator=(const R & r) { v_store(d, r); return *this; } template Data & operator*=(T m) { for (int i = 0; i < VTraits::vlanes(); ++i) d[i] *= (LaneType)m; return *this; } template Data & operator+=(T m) { for (int i = 0; i < VTraits::vlanes(); ++i) d[i] += (LaneType)m; return *this; } void fill(LaneType val, int s, int c = VTraits::vlanes()) { for (int i = s; i < c; ++i) d[i] = val; } void fill(LaneType val) { fill(val, 0); } void reverse() { for (int i = 0; i < VTraits::vlanes() / 2; ++i) std::swap(d[i], d[VTraits::vlanes() - i - 1]); } const LaneType & operator[](int i) const { #if 0 // TODO: strange bug - AVX2 tests are failed with this CV_CheckGE(i, 0, ""); CV_CheckLT(i, (int)VTraits::vlanes(), ""); #else CV_Assert(i >= 0 && i < VTraits::max_nlanes); #endif return d[i]; } LaneType & operator[](int i) { CV_CheckGE(i, 0, ""); CV_CheckLT(i, (int)VTraits::max_nlanes, ""); return d[i]; } int_type as_int(int i) const { CV_CheckGE(i, 0, ""); CV_CheckLT(i, (int)VTraits::max_nlanes, ""); union { LaneType l; int_type i; } v; v.l = d[i]; return v.i; } const LaneType * mid() const { return d + VTraits::vlanes() / 2; } LaneType * mid() { return d + VTraits::vlanes() / 2; } LaneType sum(int s, int c) { LaneType res = 0; for (int i = s; i < s + c; ++i) res += d[i]; return res; } LaneType sum() { return sum(0, VTraits::vlanes()); } bool operator==(const Data & other) const { for (int i = 0; i < VTraits::vlanes(); ++i) if (d[i] != other.d[i]) return false; return true; } void clear() { fill(0); } bool isZero() const { return isValue(0); } bool isValue(uchar val) const { for (int i = 0; i < VTraits::vlanes(); ++i) if (d[i] != val) return false; return true; } LaneType d[VTraits::max_nlanes]; }; template struct AlignedData { Data CV_DECL_ALIGNED(sizeof(typename VTraits::lane_type)*VTraits::max_nlanes) a; // aligned char dummy; Data u; // unaligned }; template std::ostream & operator<<(std::ostream & out, const Data & d) { out << "{ "; for (int i = 0; i < VTraits::vlanes(); ++i) { // out << std::hex << +V_TypeTraits::lane_type>::reinterpret_int(d.d[i]); out << +d.d[i]; if (i + 1 < VTraits::vlanes()) out << ", "; } out << " }"; return out; } template static inline void EXPECT_COMPARE_EQ_(const T a, const T b) { EXPECT_EQ(a, b); } template<> inline void EXPECT_COMPARE_EQ_(const float a, const float b) { EXPECT_FLOAT_EQ( a, b ); } template<> inline void EXPECT_COMPARE_EQ_(const double a, const double b) { EXPECT_DOUBLE_EQ( a, b ); } // pack functions do not do saturation when converting from 64-bit types template inline T pack_saturate_cast(W a) { return saturate_cast(a); } template<> inline int pack_saturate_cast(int64 a) { return static_cast(a); } template<> inline unsigned pack_saturate_cast(uint64 a) { return static_cast(a); } template struct TheTest { typedef typename VTraits::lane_type LaneType; template static inline void EXPECT_COMPARE_EQ(const T1 a, const T2 b) { EXPECT_COMPARE_EQ_((LaneType)a, (LaneType)b); } TheTest & test_loadstore() { AlignedData data; AlignedData out; // check if addresses are aligned and unaligned respectively EXPECT_EQ((size_t)0, (size_t)&data.a.d % (sizeof(typename VTraits::lane_type) * VTraits::vlanes())); EXPECT_NE((size_t)0, (size_t)&data.u.d % (sizeof(typename VTraits::lane_type) * VTraits::vlanes())); EXPECT_EQ((size_t)0, (size_t)&out.a.d % (sizeof(typename VTraits::lane_type) * VTraits::vlanes())); EXPECT_NE((size_t)0, (size_t)&out.u.d % (sizeof(typename VTraits::lane_type) * VTraits::vlanes())); // check some initialization methods R r1 = data.a; R r2 = vx_load(data.u.d); R r3 = vx_load_aligned(data.a.d); R r4(r2); EXPECT_EQ(data.a[0], v_get0(r1)); EXPECT_EQ(data.u[0], v_get0(r2)); EXPECT_EQ(data.a[0], v_get0(r3)); EXPECT_EQ(data.u[0], v_get0(r4)); R r_low = vx_load_low((LaneType*)data.u.d); EXPECT_EQ(data.u[0], v_get0(r_low)); v_store(out.u.d, r_low); for (int i = 0; i < VTraits::vlanes()/2; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((LaneType)data.u[i], (LaneType)out.u[i]); } R r_low_align8byte = vx_load_low((LaneType*)((char*)data.u.d + (sizeof(typename VTraits::lane_type) * VTraits::vlanes() / 2))); EXPECT_EQ(data.u[VTraits::vlanes()/2], v_get0(r_low_align8byte)); v_store(out.u.d, r_low_align8byte); for (int i = 0; i < VTraits::vlanes()/2; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((LaneType)data.u[i + VTraits::vlanes()/2], (LaneType)out.u[i]); } // check some store methods out.u.clear(); out.a.clear(); v_store(out.u.d, r1); v_store_aligned(out.a.d, r2); EXPECT_EQ(data.a, out.a); EXPECT_EQ(data.u, out.u); // check more store methods Data d, res(0); R r5 = d; v_store_high(res.mid(), r5); v_store_low(res.d, r5); EXPECT_EQ(d, res); // check halves load correctness res.clear(); R r6 = vx_load_halves(d.d, d.mid()); v_store(res.d, r6); EXPECT_EQ(d, res); // zero, all Data resZ, resV; resZ.fill((LaneType)0); resV.fill((LaneType)8); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((LaneType)0, resZ[i]); EXPECT_EQ((LaneType)8, resV[i]); } // reinterpret_as AlignedData out_u8; v_uint8 vu8 = v_reinterpret_as_u8(r1); v_store((uchar*)out_u8.a.d, vu8); EXPECT_EQ(data.a, out_u8.a); AlignedData out_s8; v_int8 vs8 = v_reinterpret_as_s8(r1); v_store((schar*)out_s8.a.d, vs8); EXPECT_EQ(data.a, out_s8.a); AlignedData out_u16; v_uint16 vu16 = v_reinterpret_as_u16(r1); v_store((ushort*)out_u16.a.d, vu16); EXPECT_EQ(data.a, out_u16.a); AlignedData out_s16; v_int16 vs16 = v_reinterpret_as_s16(r1); v_store((short*)out_s16.a.d, vs16); EXPECT_EQ(data.a, out_s16.a); AlignedData out_u32; v_uint32 vu32 = v_reinterpret_as_u32(r1); v_store((unsigned*)out_u32.a.d, vu32); EXPECT_EQ(data.a, out_u32.a); AlignedData out_s32; v_int32 vs32 = v_reinterpret_as_s32(r1); v_store((int*)out_s32.a.d, vs32); EXPECT_EQ(data.a, out_s32.a); AlignedData out_u64; v_uint64 vu64 = v_reinterpret_as_u64(r1); v_store((uint64*)out_u64.a.d, vu64); EXPECT_EQ(data.a, out_u64.a); AlignedData out_s64; v_int64 vs64 = v_reinterpret_as_s64(r1); v_store((int64*)out_s64.a.d, vs64); EXPECT_EQ(data.a, out_s64.a); AlignedData out_f32; v_float32 vf32 = v_reinterpret_as_f32(r1); v_store((float*)out_f32.a.d, vf32); EXPECT_EQ(data.a, out_f32.a); #if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F) AlignedData out_f64; v_float64 vf64 = v_reinterpret_as_f64(r1); v_store((double*)out_f64.a.d, vf64); EXPECT_EQ(data.a, out_f64.a); #endif #if CV_SIMD_WIDTH == 16 R setall_res1 = v_setall((LaneType)5); R setall_res2 = v_setall(6); #elif CV_SIMD_WIDTH == 32 R setall_res1 = v256_setall((LaneType)5); R setall_res2 = v256_setall(6); #elif CV_SIMD_WIDTH == 64 R setall_res1 = v512_setall((LaneType)5); R setall_res2 = v512_setall(6); #elif CV_SIMD_SCALABLE R setall_res1 = v_setall((LaneType)5); R setall_res2 = v_setall(6); #else #error "Configuration error" #endif R setall_res3 = v_setall_((LaneType)7); R setall_resz = v_setzero_(); #if CV_SIMD_WIDTH > 0 Data setall_res1_; v_store(setall_res1_.d, setall_res1); Data setall_res2_; v_store(setall_res2_.d, setall_res2); Data setall_res3_; v_store(setall_res3_.d, setall_res3); Data setall_resz_; v_store(setall_resz_.d, setall_resz); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((LaneType)5, setall_res1_[i]); EXPECT_EQ((LaneType)6, setall_res2_[i]); EXPECT_EQ((LaneType)7, setall_res3_[i]); EXPECT_EQ((LaneType)0, setall_resz_[i]); } #endif R vx_setall_res1 = vx_setall((LaneType)11); R vx_setall_res2 = vx_setall(12); Data vx_setall_res1_; v_store(vx_setall_res1_.d, vx_setall_res1); Data vx_setall_res2_; v_store(vx_setall_res2_.d, vx_setall_res2); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((LaneType)11, vx_setall_res1_[i]); EXPECT_EQ((LaneType)12, vx_setall_res2_[i]); } #if CV_SIMD_WIDTH == 16 { uint64 a = CV_BIG_INT(0x7fffffffffffffff); uint64 b = (uint64)CV_BIG_INT(0xcfffffffffffffff); v_uint64x2 uint64_vec(a, b); EXPECT_EQ(a, v_get0(uint64_vec)); EXPECT_EQ(b, v_extract_n<1>(uint64_vec)); } { int64 a = CV_BIG_INT(0x7fffffffffffffff); int64 b = CV_BIG_INT(-1); v_int64x2 int64_vec(a, b); EXPECT_EQ(a, v_get0(int64_vec)); EXPECT_EQ(b, v_extract_n<1>(int64_vec)); } #endif return *this; } TheTest & test_interleave() { Data data1, data2, data3, data4; data2 += 20; data3 += 40; data4 += 60; R a = data1, b = data2, c = data3; R d = data1, e = data2, f = data3, g = data4; LaneType buf3[VTraits::max_nlanes * 3]; LaneType buf4[VTraits::max_nlanes * 4]; v_store_interleave(buf3, a, b, c); v_store_interleave(buf4, d, e, f, g); Data z(0); a = b = c = d = e = f = g = z; v_load_deinterleave(buf3, a, b, c); v_load_deinterleave(buf4, d, e, f, g); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(data1, Data(a)); EXPECT_EQ(data2, Data(b)); EXPECT_EQ(data3, Data(c)); EXPECT_EQ(data1, Data(d)); EXPECT_EQ(data2, Data(e)); EXPECT_EQ(data3, Data(f)); EXPECT_EQ(data4, Data(g)); } return *this; } TheTest & test_interleave_pq() { Data dataA; R a = dataA; Data resP = v_interleave_pairs(a); Data resQ = v_interleave_quads(a); for (int i = 0; i < VTraits::vlanes()/4; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(resP[4*i], dataA[4*i ]); EXPECT_EQ(resP[4*i + 1], dataA[4*i+2]); EXPECT_EQ(resP[4*i + 2], dataA[4*i+1]); EXPECT_EQ(resP[4*i + 3], dataA[4*i+3]); } for (int i = 0; i < VTraits::vlanes()/8; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(resQ[8*i], dataA[8*i ]); EXPECT_EQ(resQ[8*i + 1], dataA[8*i+4]); EXPECT_EQ(resQ[8*i + 2], dataA[8*i+1]); EXPECT_EQ(resQ[8*i + 3], dataA[8*i+5]); EXPECT_EQ(resQ[8*i + 4], dataA[8*i+2]); EXPECT_EQ(resQ[8*i + 5], dataA[8*i+6]); EXPECT_EQ(resQ[8*i + 6], dataA[8*i+3]); EXPECT_EQ(resQ[8*i + 7], dataA[8*i+7]); } return *this; } // float32x4 only TheTest & test_interleave_2channel() { Data data1, data2; data2 += 20; R a = data1, b = data2; LaneType buf2[VTraits::max_nlanes * 2]; v_store_interleave(buf2, a, b); Data z(0); a = b = z; v_load_deinterleave(buf2, a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(data1, Data(a)); EXPECT_EQ(data2, Data(b)); } return *this; } // v_expand and v_load_expand TheTest & test_expand() { typedef typename V_RegTraits::w_reg Rx2; Data dataA; R a = dataA; Data resB = vx_load_expand(dataA.d); Rx2 c, d, e, f; v_expand(a, c, d); e = v_expand_low(a); f = v_expand_high(a); Data resC = c, resD = d, resE = e, resF = f; const int n = VTraits::vlanes(); for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); 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; } TheTest & test_expand_q() { typedef typename V_RegTraits::q_reg Rx4; Data data; Data out = vx_load_expand_q(data.d); const int n = VTraits::vlanes(); for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(data[i], out[i]); } return *this; } TheTest & test_addsub() { Data dataA, dataB, dataC; dataB.reverse(); dataA[1] = static_cast(std::numeric_limits::max()); R a = dataA, b = dataB, c = dataC; Data resD = v_add(a, b), resE = v_add(a, b, c), resF = v_sub(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(saturate_cast(dataA[i] + dataB[i]), resD[i]); EXPECT_EQ(saturate_cast(dataA[i] + dataB[i] + dataC[i]), resE[i]); EXPECT_EQ(saturate_cast(dataA[i] - dataB[i]), resF[i]); } return *this; } TheTest & test_arithm_wrap() { Data dataA, dataB; dataB.reverse(); R a = dataA, b = dataB; Data resC = v_add_wrap(a, b), resD = v_sub_wrap(a, b), resE = v_mul_wrap(a, b); for (int i = 0; i < VTraits::vlanes(); ++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; } TheTest & test_mul() { Data dataA, dataB, dataC; dataA[1] = static_cast(std::numeric_limits::max()); dataB.reverse(); R a = dataA, b = dataB, c = dataC; Data resD = v_mul(a, b); Data resE = v_mul(a, b, c); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(saturate_cast(dataA[i] * dataB[i]), resD[i]); EXPECT_EQ(saturate_cast(dataA[i] * dataB[i] * dataC[i]), resE[i]); } return *this; } TheTest & test_div() { Data dataA, dataB; dataB.reverse(); R a = dataA, b = dataB; Data resC = v_div(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[i] / dataB[i], resC[i]); } return *this; } TheTest & test_mul_expand() { typedef typename V_RegTraits::w_reg Rx2; Data dataA, dataB(2); R a = dataA, b = dataB; Rx2 c, d; v_mul_expand(a, b, c, d); Data resC = c, resD = d; const int n = VTraits::vlanes() / 2; for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((typename VTraits::lane_type)dataA[i] * dataB[i], resC[i]); EXPECT_EQ((typename VTraits::lane_type)dataA[i + n] * dataB[i + n], resD[i]); } return *this; } TheTest & test_mul_hi() { // typedef typename V_RegTraits::w_reg Rx2; Data dataA, dataB(32767); R a = dataA, b = dataB; R c = v_mul_hi(a, b); Data resC = c; const int n = VTraits::vlanes() / 2; for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((typename VTraits::lane_type)((dataA[i] * dataB[i]) >> 16), resC[i]); } return *this; } TheTest & test_abs() { typedef typename V_RegTraits::u_reg Ru; typedef typename VTraits::lane_type u_type; typedef typename VTraits::lane_type R_type; Data dataA, dataB(10); R a = dataA, b = dataB; a = v_sub(a, b); Data resC = v_abs(a); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); R_type ssub = dataA[i] - dataB[i] < std::numeric_limits::lowest() ? std::numeric_limits::lowest() : dataA[i] - dataB[i]; EXPECT_EQ((u_type)std::abs(ssub), resC[i]); } return *this; } template TheTest & test_shift() { SCOPED_TRACE(s); Data dataA; dataA[0] = static_cast(std::numeric_limits::max()); R a = dataA; Data resB = v_shl(a), resC = v_shl(a), resD = v_shr(a), resE = v_shr(a); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(static_cast(dataA[i] << s), resB[i]); EXPECT_EQ(static_cast(dataA[i] << s), resC[i]); EXPECT_EQ(static_cast(dataA[i] >> s), resD[i]); EXPECT_EQ(static_cast(dataA[i] >> s), resE[i]); } return *this; } TheTest & test_cmp() { Data dataA, dataB; dataB.reverse(); dataB += 1; R a = dataA, b = dataB; Data resC = (v_eq(a, b)); Data resD = (v_ne(a, b)); Data resE = (v_gt(a, b)); Data resF = (v_ge(a, b)); Data resG = (v_lt(a, b)); Data resH = (v_le(a, b)); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[i] == dataB[i], resC[i] != 0); EXPECT_EQ(dataA[i] != dataB[i], resD[i] != 0); EXPECT_EQ(dataA[i] > dataB[i], resE[i] != 0); EXPECT_EQ(dataA[i] >= dataB[i], resF[i] != 0); EXPECT_EQ(dataA[i] < dataB[i], resG[i] != 0); EXPECT_EQ(dataA[i] <= dataB[i], resH[i] != 0); } return *this; } TheTest & test_dotprod() { typedef typename V_RegTraits::w_reg Rx2; typedef typename VTraits::lane_type w_type; Data dataA, dataB; dataA += std::numeric_limits::max() - VTraits::vlanes(); dataB += std::numeric_limits::min() + VTraits::vlanes(); R a = dataA, b = dataB; Data dataC; dataC += std::numeric_limits::is_signed ? std::numeric_limits::min() : std::numeric_limits::max() - VTraits::vlanes() * (dataB[0] + 1); Rx2 c = dataC; Data resD = v_dotprod(a, b), resE = v_dotprod(a, b, c); const int n = VTraits::vlanes() / 2; w_type sumAB = 0, sumABC = 0, tmp_sum; for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); tmp_sum = (w_type)dataA[i*2] * (w_type)dataB[i*2] + (w_type)dataA[i*2 + 1] * (w_type)dataB[i*2 + 1]; sumAB += tmp_sum; EXPECT_EQ(tmp_sum, resD[i]); tmp_sum = tmp_sum + dataC[i]; sumABC += tmp_sum; EXPECT_EQ(tmp_sum, resE[i]); } w_type resF = v_reduce_sum(v_dotprod_fast(a, b)), resG = v_reduce_sum(v_dotprod_fast(a, b, c)); EXPECT_EQ(sumAB, resF); EXPECT_EQ(sumABC, resG); return *this; } TheTest & test_dotprod_expand() { typedef typename V_RegTraits::q_reg Rx4; typedef typename VTraits::lane_type l4_type; Data dataA, dataB; dataA += std::numeric_limits::max() - VTraits::vlanes(); dataB += std::numeric_limits::min() + VTraits::vlanes(); R a = dataA, b = dataB; Data dataC; Rx4 c = dataC; Data resD = v_dotprod_expand(a, b), resE = v_dotprod_expand(a, b, c); l4_type sumAB = 0, sumABC = 0, tmp_sum; for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); tmp_sum = (l4_type)dataA[i*4] * (l4_type)dataB[i*4] + (l4_type)dataA[i*4 + 1] * (l4_type)dataB[i*4 + 1] + (l4_type)dataA[i*4 + 2] * (l4_type)dataB[i*4 + 2] + (l4_type)dataA[i*4 + 3] * (l4_type)dataB[i*4 + 3]; sumAB += tmp_sum; EXPECT_EQ(tmp_sum, resD[i]); tmp_sum = tmp_sum + dataC[i]; sumABC += tmp_sum; EXPECT_EQ(tmp_sum, resE[i]); } l4_type resF = v_reduce_sum(v_dotprod_expand_fast(a, b)), resG = v_reduce_sum(v_dotprod_expand_fast(a, b, c)); EXPECT_EQ(sumAB, resF); EXPECT_EQ(sumABC, resG); return *this; } TheTest & test_dotprod_expand_f64() { #if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F) Data dataA, dataB; dataA += std::numeric_limits::max() - VTraits::vlanes(); dataB += std::numeric_limits::min(); R a = dataA, b = dataB; Data dataC; v_float64 c = dataC; Data resA = v_dotprod_expand(a, a), resB = v_dotprod_expand(b, b), resC = v_dotprod_expand(a, b, c); const int n = VTraits::vlanes() / 2; for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_COMPARE_EQ((double)dataA[i*2] * (double)dataA[i*2] + (double)dataA[i*2 + 1] * (double)dataA[i*2 + 1], resA[i]); EXPECT_COMPARE_EQ((double)dataB[i*2] * (double)dataB[i*2] + (double)dataB[i*2 + 1] * (double)dataB[i*2 + 1], resB[i]); EXPECT_COMPARE_EQ((double)dataA[i*2] * (double)dataB[i*2] + (double)dataA[i*2 + 1] * (double)dataB[i*2 + 1] + dataC[i], resC[i]); } #endif return *this; } TheTest & test_logic() { Data dataA, dataB(2); R a = dataA, b = dataB; Data resC = v_and(a, b), resD = v_or(a, b), resE = v_xor(a, b), resF = v_not(a); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[i] & dataB[i], resC[i]); EXPECT_EQ(dataA[i] | dataB[i], resD[i]); EXPECT_EQ(dataA[i] ^ dataB[i], resE[i]); EXPECT_EQ((LaneType)~dataA[i], resF[i]); } return *this; } TheTest & test_sqrt_abs() { Data dataA, dataD; dataD *= -1.0; R a = dataA, d = dataD; Data resB = v_sqrt(a), resC = v_invsqrt(a), resE = v_abs(d); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_COMPARE_EQ((float)std::sqrt(dataA[i]), (float)resB[i]); EXPECT_COMPARE_EQ((float)(1/std::sqrt(dataA[i])), (float)resC[i]); EXPECT_COMPARE_EQ((float)abs(dataA[i]), (float)resE[i]); } return *this; } TheTest & test_min_max() { Data dataA, dataB; dataB.reverse(); R a = dataA, b = dataB; Data resC = v_min(a, b), resD = v_max(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(std::min(dataA[i], dataB[i]), resC[i]); EXPECT_EQ(std::max(dataA[i], dataB[i]), resD[i]); } return *this; } TheTest & test_popcount() { typedef typename V_RegTraits::u_reg Ru; static unsigned popcountTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, //0x00-0x0f 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, //0x10-0x1f 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, //0x20-0x2f 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, //0x30-0x3f 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, //0x40-0x4f 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, //0x50-0x5f 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, //0x60-0x6f 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, //0x70-0x7f 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, //0x80-0x8f 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, //0x90-0x9f 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, //0xa0-0xaf 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, //0xb0-0xbf 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, //0xc0-0xcf 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, //0xd0-0xdf 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, //0xe0-0xef 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, //0xf0-0xff 0 }; Data dataA; R a = dataA; Data resB = v_popcount(a); for (int i = 0; i < VTraits::vlanes(); ++i) EXPECT_EQ(popcountTable[i + 1], resB[i]); return *this; } TheTest & test_absdiff() { typedef typename V_RegTraits::u_reg Ru; typedef typename VTraits::lane_type u_type; Data dataA(std::numeric_limits::max()), dataB(std::numeric_limits::min()); dataA[0] = (LaneType)-1; dataB[0] = 1; dataA[1] = 2; dataB[1] = (LaneType)-2; R a = dataA, b = dataB; Data resC = v_absdiff(a, b); const u_type mask = std::numeric_limits::is_signed ? (u_type)(1 << (sizeof(u_type)*8 - 1)) : 0; for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); u_type uA = dataA[i] ^ mask; u_type uB = dataB[i] ^ mask; EXPECT_EQ(uA > uB ? uA - uB : uB - uA, resC[i]); } return *this; } TheTest & test_float_absdiff() { Data dataA(std::numeric_limits::max()), dataB(std::numeric_limits::min()); dataA[0] = -1; dataB[0] = 1; dataA[1] = 2; dataB[1] = -2; R a = dataA, b = dataB; Data resC = v_absdiff(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[i] > dataB[i] ? dataA[i] - dataB[i] : dataB[i] - dataA[i], resC[i]); } return *this; } TheTest & test_absdiffs() { Data dataA(std::numeric_limits::max()), dataB(std::numeric_limits::min()); dataA[0] = (LaneType)-1; dataB[0] = 1; dataA[1] = 2; dataB[1] = (LaneType)-2; R a = dataA, b = dataB; Data resC = v_absdiffs(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { EXPECT_EQ(saturate_cast(std::abs(dataA[i] - dataB[i])), resC[i]); } return *this; } TheTest & test_reduce() { Data dataA; LaneType min = (LaneType)VTraits::vlanes(), max = 0; int sum = 0; for (int i = 0; i < VTraits::vlanes(); ++i) { min = std::min(min, dataA[i]); max = std::max(max, dataA[i]); sum += (int)(dataA[i]); // To prevent a constant overflow with int8 } R a = dataA; EXPECT_EQ((LaneType)min, (LaneType)v_reduce_min(a)); EXPECT_EQ((LaneType)max, (LaneType)v_reduce_max(a)); EXPECT_EQ((int)(sum), (int)v_reduce_sum(a)); dataA[0] += (LaneType)VTraits::vlanes(); R an = dataA; min = (LaneType)VTraits::vlanes(); for (int i = 0; i < VTraits::vlanes(); ++i) { min = std::min(min, dataA[i]); } EXPECT_EQ((LaneType)min, (LaneType)v_reduce_min(an)); return *this; } TheTest & test_reduce_sad() { Data dataA, dataB((LaneType)VTraits::vlanes() /2); R a = dataA; R b = dataB; uint sum = 0; for (int i = 0; i < VTraits::vlanes(); ++i) { sum += std::abs(int(dataA[i] - dataB[i])); } EXPECT_EQ(sum, v_reduce_sad(a, b)); return *this; } TheTest & test_mask() { typedef typename V_RegTraits::int_reg int_reg; typedef typename V_RegTraits::u_reg uint_reg; typedef typename VTraits::lane_type int_type; typedef typename VTraits::lane_type uint_type; Data dataA, dataB(0), dataC, dataD(1), dataE(2); dataA[0] = (LaneType)std::numeric_limits::max(); dataA[1] *= (LaneType)-1; union { LaneType l; uint_type ui; } all1s; all1s.ui = (uint_type)-1; LaneType mask_one = all1s.l; dataB[VTraits::vlanes() - 1] = mask_one; R l = dataB; dataB[1] = mask_one; dataB[VTraits::vlanes() / 2] = mask_one; for (int i = 0; i < VTraits::vlanes(); i++) { auto c_signed = dataC.as_int(i); dataC[i] = (LaneType)(c_signed == 0 ? -1 : -std::abs(c_signed)); } R a = dataA, b = dataB, c = dataC, d = dataD, e = dataE; dataC[VTraits::vlanes() - 1] = 0; R nl = dataC; EXPECT_EQ(2, v_signmask(a)); #if (CV_SIMD_WIDTH <= 32) && (!CV_SIMD_SCALABLE) EXPECT_EQ(2 | (1 << (VTraits::vlanes() / 2)) | (1 << (VTraits::vlanes() - 1)), v_signmask(b)); #endif EXPECT_EQ(false, v_check_all(a)); EXPECT_EQ(false, v_check_all(b)); EXPECT_EQ(true, v_check_all(c)); EXPECT_EQ(false, v_check_all(nl)); EXPECT_EQ(true, v_check_any(a)); EXPECT_EQ(true, v_check_any(b)); EXPECT_EQ(true, v_check_any(c)); EXPECT_EQ(true, v_check_any(l)); R f = v_select(b, d, e); Data resF = f; for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); int_type m2 = dataB.as_int(i); EXPECT_EQ((dataD.as_int(i) & m2) | (dataE.as_int(i) & ~m2), resF.as_int(i)); } return *this; } template TheTest & test_pack() { SCOPED_TRACE(s); typedef typename V_RegTraits::w_reg Rx2; typedef typename VTraits::lane_type w_type; Data dataA, dataB; dataA += std::numeric_limits::is_signed ? -10 : 10; dataB *= 10; dataB[0] = static_cast(std::numeric_limits::max()) + 17; // to check saturation Rx2 a = dataA, b = dataB; Data resC = v_pack(a, b); Data resD = v_rshr_pack(a, b); Data resE(0); v_pack_store(resE.d, b); Data resF(0); v_rshr_pack_store(resF.d, b); const int n = VTraits::vlanes(); const w_type add = (w_type)1 << (s - 1); for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(pack_saturate_cast(dataA[i]), resC[i]); EXPECT_EQ(pack_saturate_cast(dataB[i]), resC[i + n]); EXPECT_EQ(pack_saturate_cast((dataA[i] + add) >> s), resD[i]); EXPECT_EQ(pack_saturate_cast((dataB[i] + add) >> s), resD[i + n]); EXPECT_EQ(pack_saturate_cast(dataB[i]), resE[i]); EXPECT_EQ((LaneType)0, resE[i + n]); EXPECT_EQ(pack_saturate_cast((dataB[i] + add) >> s), resF[i]); EXPECT_EQ((LaneType)0, resF[i + n]); } return *this; } TheTest & test_pack_triplets() { Data dataA; R a = dataA; Data res = v_pack_triplets(a); for (int i = 0; i < VTraits::vlanes()/4; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[4*i], res[3*i]); EXPECT_EQ(dataA[4*i+1], res[3*i+1]); EXPECT_EQ(dataA[4*i+2], res[3*i+2]); } return *this; } template TheTest & test_pack_u() { SCOPED_TRACE(s); //typedef typename V_RegTraits::w_type LaneType_w; typedef typename V_RegTraits::w_reg R2; typedef typename V_RegTraits::int_reg Ri2; typedef typename VTraits::lane_type w_type; Data dataA, dataB; dataA += -10; dataB *= 10; dataB[0] = static_cast(std::numeric_limits::max()) + 17; // to check saturation Ri2 a = dataA, b = dataB; Data resC = v_pack_u(a, b); Data resD = v_rshr_pack_u(a, b); Data resE(0); v_pack_u_store(resE.d, b); Data resF(0); v_rshr_pack_u_store(resF.d, b); const int n = VTraits::vlanes(); const w_type add = (w_type)1 << (s - 1); for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(pack_saturate_cast(dataA[i]), resC[i]); EXPECT_EQ(pack_saturate_cast(dataB[i]), resC[i + n]); EXPECT_EQ(pack_saturate_cast((dataA[i] + add) >> s), resD[i]); EXPECT_EQ(pack_saturate_cast((dataB[i] + add) >> s), resD[i + n]); EXPECT_EQ(pack_saturate_cast(dataB[i]), resE[i]); EXPECT_EQ((LaneType)0, resE[i + n]); EXPECT_EQ(pack_saturate_cast((dataB[i] + add) >> s), resF[i]); EXPECT_EQ((LaneType)0, resF[i + n]); } return *this; } // v_uint8 only TheTest & test_pack_b() { // 16-bit Data dataA, dataB; dataB.fill(0, VTraits::vlanes() / 2); R a = dataA, b = dataB; Data maskA = v_eq(a, b), maskB = v_ne(a, b); a = maskA; b = maskB; Data res = v_pack_b(v_reinterpret_as_u16(a), v_reinterpret_as_u16(b)); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(maskA[i * 2], res[i]); EXPECT_EQ(maskB[i * 2], res[i + VTraits::vlanes()]); } // 32-bit Data dataC, dataD; dataD.fill(0, VTraits::vlanes() / 2); R c = dataC, d = dataD; Data maskC = v_eq(c, d), maskD = v_ne(c, d); c = maskC; d = maskD; res = v_pack_b ( v_reinterpret_as_u32(a), v_reinterpret_as_u32(b), v_reinterpret_as_u32(c), v_reinterpret_as_u32(d) ); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(maskA[i * 4], res[i]); EXPECT_EQ(maskB[i * 4], res[i + VTraits::vlanes()]); EXPECT_EQ(maskC[i * 4], res[i + VTraits::vlanes() * 2]); EXPECT_EQ(maskD[i * 4], res[i + VTraits::vlanes() * 3]); } // 64-bit Data dataE, dataF, dataG(0), dataH(0xFF); dataF.fill(0, VTraits::vlanes() / 2); R e = dataE, f = dataF, g = dataG, h = dataH; Data maskE = v_eq(e, f), maskF = v_ne(e, f); e = maskE; f = maskF; res = v_pack_b ( v_reinterpret_as_u64(a), v_reinterpret_as_u64(b), v_reinterpret_as_u64(c), v_reinterpret_as_u64(d), v_reinterpret_as_u64(e), v_reinterpret_as_u64(f), v_reinterpret_as_u64(g), v_reinterpret_as_u64(h) ); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(maskA[i * 8], res[i]); EXPECT_EQ(maskB[i * 8], res[i + VTraits::vlanes()]); EXPECT_EQ(maskC[i * 8], res[i + VTraits::vlanes() * 2]); EXPECT_EQ(maskD[i * 8], res[i + VTraits::vlanes() * 3]); EXPECT_EQ(maskE[i * 8], res[i + VTraits::vlanes() * 4]); EXPECT_EQ(maskF[i * 8], res[i + VTraits::vlanes() * 5]); EXPECT_EQ(dataG[i * 8], res[i + VTraits::vlanes() * 6]); EXPECT_EQ(dataH[i * 8], res[i + VTraits::vlanes() * 7]); } return *this; } TheTest & test_unpack() { Data dataA, dataB; dataB *= 10; R a = dataA, b = dataB; R c, d, e, f, lo, hi; v_zip(a, b, c, d); v_recombine(a, b, e, f); lo = v_combine_low(a, b); hi = v_combine_high(a, b); Data resC = c, resD = d, resE = e, resF = f, resLo = lo, resHi = hi; const int n = VTraits::vlanes()/2; for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[i], resC[i*2]); EXPECT_EQ(dataB[i], resC[i*2+1]); EXPECT_EQ(dataA[i+n], resD[i*2]); EXPECT_EQ(dataB[i+n], resD[i*2+1]); EXPECT_EQ(dataA[i], resE[i]); EXPECT_EQ(dataB[i], resE[i+n]); EXPECT_EQ(dataA[i+n], resF[i]); EXPECT_EQ(dataB[i+n], resF[i+n]); EXPECT_EQ(dataA[i], resLo[i]); EXPECT_EQ(dataB[i], resLo[i+n]); EXPECT_EQ(dataA[i+n], resHi[i]); EXPECT_EQ(dataB[i+n], resHi[i+n]); } return *this; } TheTest & test_reverse() { Data dataA; R a = dataA; Data resB = v_reverse(a); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(dataA[VTraits::vlanes() - i - 1], resB[i]); } return *this; } template TheTest & test_extract() { SCOPED_TRACE(s); Data dataA, dataB; dataB *= 10; R a = dataA, b = dataB; Data resC = v_extract(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); if (i + s >= VTraits::vlanes()) EXPECT_EQ(dataB[i - VTraits::vlanes() + s], resC[i]); else EXPECT_EQ(dataA[i + s], resC[i]); } return *this; } template TheTest & test_rotate() { SCOPED_TRACE(s); Data dataA, dataB; dataB *= 10; R a = dataA, b = dataB; Data resC = v_rotate_right(a); Data resD = v_rotate_right(a, b); Data resE = v_rotate_left(a); Data resF = v_rotate_left(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); if (i + s >= VTraits::vlanes()) { EXPECT_EQ((LaneType)0, resC[i]); EXPECT_EQ(dataB[i - VTraits::vlanes() + s], resD[i]); EXPECT_EQ((LaneType)0, resE[i - VTraits::vlanes() + s]); EXPECT_EQ(dataB[i], resF[i - VTraits::vlanes() + s]); } else { EXPECT_EQ(dataA[i + s], resC[i]); EXPECT_EQ(dataA[i + s], resD[i]); EXPECT_EQ(dataA[i], resE[i + s]); EXPECT_EQ(dataA[i], resF[i + s]); } } return *this; } template TheTest & test_extract_n() { SCOPED_TRACE(s); Data dataA; LaneType test_value = (LaneType)(s + 50); dataA[s] = test_value; R a = dataA; LaneType res = v_extract_n(a); EXPECT_EQ(test_value, res); return *this; } TheTest & test_extract_highest() { Data dataA; LaneType test_value = (LaneType)(VTraits::vlanes()-1 + 50); dataA[VTraits::vlanes()-1] = test_value; R a = dataA; LaneType res = v_extract_highest(a); EXPECT_EQ(test_value, res); return *this; } template TheTest & test_broadcast_element() { SCOPED_TRACE(s); Data dataA; LaneType test_value = (LaneType)(s + 50); dataA[s] = test_value; R a = dataA; Data res = v_broadcast_element(a); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(i); EXPECT_EQ(test_value, res[i]); } return *this; } TheTest & test_broadcast_highest() { Data dataA; LaneType test_value = (LaneType)(VTraits::vlanes()-1 + 50); dataA[VTraits::vlanes()-1] = test_value; R a = dataA; Data res = v_broadcast_highest(a); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(i); EXPECT_EQ(test_value, res[i]); } return *this; } TheTest & test_float_math() { typedef typename V_RegTraits::round_reg Ri; Data data1, data1_border, data2, data3; // See https://github.com/opencv/opencv/issues/24213 data1_border *= 0.5; data1 *= 1.1; data2 += 10; R a1 = data1, a1_border = data1_border, a2 = data2, a3 = data3; Data resB = v_round(a1), resB_border = v_round(a1_border), resC = v_trunc(a1), resD = v_floor(a1), resE = v_ceil(a1); Data resF = v_magnitude(a1, a2), resG = v_sqr_magnitude(a1, a2), resH = v_muladd(a1, a2, a3); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ(cvRound(data1[i]), resB[i]); EXPECT_EQ(cvRound(data1_border[i]), resB_border[i]); EXPECT_EQ((typename VTraits::lane_type)data1[i], resC[i]); EXPECT_EQ(cvFloor(data1[i]), resD[i]); EXPECT_EQ(cvCeil(data1[i]), resE[i]); EXPECT_COMPARE_EQ(std::sqrt(data1[i]*data1[i] + data2[i]*data2[i]), resF[i]); EXPECT_COMPARE_EQ(data1[i]*data1[i] + data2[i]*data2[i], resG[i]); EXPECT_COMPARE_EQ(data1[i]*data2[i] + data3[i], resH[i]); } return *this; } #if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F) TheTest & test_round_pair_f64() { typedef typename V_RegTraits::round_reg Ri; Data data1, data1_border, data2; // See https://github.com/opencv/opencv/issues/24213 // https://github.com/opencv/opencv/issues/24163 // https://github.com/opencv/opencv/pull/24271 data1_border *= 0.5; data1 *= 1.1; data2 += 10; R a1 = data1, a1_border = data1_border, a2 = data2; Data resA = v_round(a1, a1), resB = v_round(a1_border, a1_border), resC = v_round(a2, a2); for (int i = 0; i < VTraits::vlanes(); ++i) { EXPECT_EQ(cvRound(data1[i]), resA[i]); EXPECT_EQ(cvRound(data1_border[i]), resB[i]); EXPECT_EQ(cvRound(data2[i]), resC[i]); } return *this; } #endif TheTest & test_float_cvt32() { typedef v_float32 Rt; Data dataA; dataA *= 1.1; R a = dataA; Rt b = v_cvt_f32(a); Data resB = b; int n = std::min(VTraits::vlanes(), VTraits::vlanes()); for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((typename VTraits::lane_type)dataA[i], resB[i]); } return *this; } TheTest & test_float_cvt64() { #if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F) typedef v_float64 Rt; Data dataA; dataA *= 1.1; R a = dataA; Rt b = v_cvt_f64(a); Rt c = v_cvt_f64_high(a); Data resB = b; Data resC = c; int n = std::min(VTraits::vlanes(), VTraits::vlanes()); for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((typename VTraits::lane_type)dataA[i], resB[i]); } for (int i = 0; i < n; ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((typename VTraits::lane_type)dataA[i+n], resC[i]); } #endif return *this; } TheTest & test_cvt64_double() { #if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F) Data dataA(std::numeric_limits::max()), dataB(std::numeric_limits::min()); dataB += VTraits::vlanes(); R a = dataA, b = dataB; v_float64 c = v_cvt_f64(a), d = v_cvt_f64(b); Data resC = c; Data resD = d; for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_EQ((double)dataA[i], resC[i]); EXPECT_EQ((double)dataB[i], resD[i]); } #endif return *this; } TheTest & test_matmul() { Data dataV, dataA, dataB, dataC, dataD; dataB.reverse(); dataC += 2; dataD *= 0.3; R v = dataV, a = dataA, b = dataB, c = dataC, d = dataD; Data res = v_matmul(v, a, b, c, d); for (int i = 0; i < VTraits::vlanes(); i += 4) { for (int j = i; j < i + 4; ++j) { SCOPED_TRACE(cv::format("i=%d j=%d", i, j)); LaneType val = dataV[i] * dataA[j] + dataV[i + 1] * dataB[j] + dataV[i + 2] * dataC[j] + dataV[i + 3] * dataD[j]; EXPECT_COMPARE_EQ(val, res[j]); } } Data resAdd = v_matmuladd(v, a, b, c, d); for (int i = 0; i < VTraits::vlanes(); i += 4) { for (int j = i; j < i + 4; ++j) { SCOPED_TRACE(cv::format("i=%d j=%d", i, j)); LaneType val = dataV[i] * dataA[j] + dataV[i + 1] * dataB[j] + dataV[i + 2] * dataC[j] + dataD[j]; EXPECT_COMPARE_EQ(val, resAdd[j]); } } return *this; } TheTest & test_transpose() { Data dataA, dataB, dataC, dataD; dataB *= 5; dataC *= 10; dataD *= 15; R a = dataA, b = dataB, c = dataC, d = dataD; R e, f, g, h; v_transpose4x4(a, b, c, d, e, f, g, h); // Data res[4] = {e, f, g, h}; // Generates incorrect data in certain RVV case. Data res0 = e, res1 = f, res2 = g, res3 = h; EXPECT_EQ(dataA[0], res0[0]); EXPECT_EQ(dataB[0], res0[1]); EXPECT_EQ(dataC[0], res0[2]); EXPECT_EQ(dataD[0], res0[3]); EXPECT_EQ(dataA[1], res1[0]); EXPECT_EQ(dataB[1], res1[1]); EXPECT_EQ(dataC[1], res1[2]); EXPECT_EQ(dataD[1], res1[3]); EXPECT_EQ(dataA[2], res2[0]); EXPECT_EQ(dataB[2], res2[1]); EXPECT_EQ(dataC[2], res2[2]); EXPECT_EQ(dataD[2], res2[3]); EXPECT_EQ(dataA[3], res3[0]); EXPECT_EQ(dataB[3], res3[1]); EXPECT_EQ(dataC[3], res3[2]); EXPECT_EQ(dataD[3], res3[3]); return *this; } TheTest & test_reduce_sum4() { Data dataA, dataB, dataC, dataD; dataB *= 0.01f; dataC *= 0.001f; dataD *= 0.002f; R a = dataA, b = dataB, c = dataC, d = dataD; Data res = v_reduce_sum4(a, b, c, d); for (int i = 0; i < VTraits::vlanes(); i += 4) { SCOPED_TRACE(cv::format("i=%d", i)); EXPECT_COMPARE_EQ(dataA.sum(i, 4), res[i]); EXPECT_COMPARE_EQ(dataB.sum(i, 4), res[i + 1]); EXPECT_COMPARE_EQ(dataC.sum(i, 4), res[i + 2]); EXPECT_COMPARE_EQ(dataD.sum(i, 4), res[i + 3]); } return *this; } TheTest & test_loadstore_fp16_f32() { printf("test_loadstore_fp16_f32 ...\n"); AlignedData data; data.a.clear(); data.a.d[0] = 0x3c00; // 1.0 data.a.d[VTraits::vlanes() - 1] = (unsigned short)0xc000; // -2.0 AlignedData data_f32; data_f32.a.clear(); AlignedData out; R r1 = vx_load_expand((const cv::hfloat*)data.a.d); R r2(r1); EXPECT_EQ(1.0f, v_get0(r1)); v_store(data_f32.a.d, r2); EXPECT_EQ(-2.0f, data_f32.a.d[VTraits::vlanes() - 1]); out.a.clear(); v_pack_store((cv::hfloat*)out.a.d, r2); for (int i = 0; i < VTraits::vlanes(); ++i) { EXPECT_EQ(data.a[i], out.a[i]) << "i=" << i; } return *this; } #if 0 TheTest & test_loadstore_fp16() { printf("test_loadstore_fp16 ...\n"); AlignedData data; AlignedData out; // check if addresses are aligned and unaligned respectively EXPECT_EQ((size_t)0, (size_t)&data.a.d % VTraits::max_nlanes); EXPECT_NE((size_t)0, (size_t)&data.u.d % VTraits::max_nlanes); EXPECT_EQ((size_t)0, (size_t)&out.a.d % VTraits::max_nlanes); EXPECT_NE((size_t)0, (size_t)&out.u.d % VTraits::max_nlanes); // check some initialization methods R r1 = data.u; R r2 = vx_load_expand((const hfloat*)data.a.d); R r3(r2); EXPECT_EQ(data.u[0], v_get0(r1)); EXPECT_EQ(data.a[0], v_get0(r2)); EXPECT_EQ(data.a[0], v_get0(r3)); // check some store methods out.a.clear(); v_store(out.a.d, r1); EXPECT_EQ(data.a, out.a); return *this; } TheTest & test_float_cvt_fp16() { printf("test_float_cvt_fp16 ...\n"); AlignedData data; // check conversion v_float32 r1 = vx_load(data.a.d); v_float16 r2 = v_cvt_f16(r1, vx_setzero_f32()); v_float32 r3 = v_cvt_f32(r2); EXPECT_EQ(0x3c00, v_get0(r2)); EXPECT_EQ(v_get0(r3), v_get0(r1)); return *this; } #endif void do_check_cmp64(const Data& dataA, const Data& dataB) { R a = dataA; R b = dataB; Data dataEQ = v_eq(a, b); Data dataNE = v_ne(a, b); for (int i = 0; i < VTraits::vlanes(); ++i) { SCOPED_TRACE(cv::format("i=%d", i)); if (cvtest::debugLevel > 0) cout << "i=" << i << " ( " << dataA[i] << " vs " << dataB[i] << " ): eq=" << dataEQ[i] << " ne=" << dataNE[i] << endl; EXPECT_NE((LaneType)dataEQ[i], (LaneType)dataNE[i]); if (dataA[i] == dataB[i]) EXPECT_EQ((LaneType)-1, (LaneType)dataEQ[i]); else EXPECT_EQ((LaneType)0, (LaneType)dataEQ[i]); if (dataA[i] != dataB[i]) EXPECT_EQ((LaneType)-1, (LaneType)dataNE[i]); else EXPECT_EQ((LaneType)0, (LaneType)dataNE[i]); } } TheTest & test_cmp64() { Data dataA; Data dataB; for (int i = 0; i < VTraits::vlanes(); ++i) { dataA[i] = dataB[i]; } dataA[0]++; do_check_cmp64(dataA, dataB); do_check_cmp64(dataB, dataA); dataA[0] = dataB[0]; dataA[1] += (((LaneType)1) << 32); do_check_cmp64(dataA, dataB); do_check_cmp64(dataB, dataA); dataA[0] = (LaneType)-1; dataB[0] = (LaneType)-1; dataA[1] = (LaneType)-1; dataB[1] = (LaneType)2; do_check_cmp64(dataA, dataB); do_check_cmp64(dataB, dataA); return *this; } void __test_exp(LaneType dataMax, LaneType diff_thr, LaneType enlarge_factor, LaneType flt_min) { int n = VTraits::vlanes(); // Test overflow and underflow values with step const LaneType step = (LaneType) 0.01; for (LaneType i = dataMax + 1; i <= dataMax + 11;) { Data dataUpperBound, dataLowerBound, resOverflow, resUnderflow; for (int j = 0; j < n; ++j) { dataUpperBound[j] = i; dataLowerBound[j] = -i; i += step; } R upperBound = dataUpperBound, lowerBound = dataLowerBound; resOverflow = v_exp(upperBound); resUnderflow = v_exp(lowerBound); for (int j = 0; j < n; ++j) { SCOPED_TRACE(cv::format("Overflow/Underflow test value: %f", i)); EXPECT_TRUE(resOverflow[j] > 0 && std::isinf(resOverflow[j])); EXPECT_GE(resUnderflow[j], 0); EXPECT_LT(resUnderflow[j], flt_min); } } // Test random values combined with special values std::vector specialValues = {0, 1, INFINITY, -INFINITY, NAN, dataMax}; const int testRandNum = 10000; const double specialValueProbability = 0.1; // 10% chance to insert a special value cv::RNG_MT19937 rng; for (int i = 0; i < testRandNum; i++) { Data dataRand, resRand; for (int j = 0; j < n; ++j) { if (rng.uniform(0.f, 1.f) <= specialValueProbability) { // Insert a special value int specialValueIndex = rng.uniform(0, (int) specialValues.size()); dataRand[j] = specialValues[specialValueIndex]; } else { // Generate random data in [-dataMax*1.1, dataMax*1.1] dataRand[j] = (LaneType) rng.uniform(-dataMax * 1.1, dataMax * 1.1); } } // Compare with std::exp R x = dataRand; resRand = v_exp(x); for (int j = 0; j < n; ++j) { SCOPED_TRACE(cv::format("Random test value: %f", dataRand[j])); LaneType std_exp = std::exp(dataRand[j]); if (dataRand[j] == 0) { // input 0 -> output 1 EXPECT_EQ(resRand[j], 1); } else if (dataRand[j] == 1) { // input 1 -> output e EXPECT_NEAR((LaneType) M_E, resRand[j], 1e-15); } else if (dataRand[j] > 0 && std::isinf(dataRand[j])) { // input INF -> output INF EXPECT_TRUE(resRand[j] > 0 && std::isinf(resRand[j])); } else if (dataRand[j] < 0 && std::isinf(dataRand[j])) { // input -INF -> output 0 EXPECT_EQ(resRand[j], 0); } else if (std::isnan(dataRand[j])) { // input NaN -> output NaN EXPECT_TRUE(std::isnan(resRand[j])); } else if (dataRand[j] == dataMax) { // input dataMax -> output less than INFINITY EXPECT_LT(resRand[j], (LaneType) INFINITY); } else if (std::isinf(resRand[j])) { // output INF -> input close to edge EXPECT_GT(dataRand[j], dataMax); } else { EXPECT_GE(resRand[j], 0); EXPECT_LT(std::abs(resRand[j] - std_exp), diff_thr * (std_exp + flt_min * enlarge_factor)); } } } } TheTest &test_exp_fp16() { #if CV_SIMD_FP16 float16_t flt16_min; uint16_t flt16_min_hex = 0x0400; std::memcpy(&flt16_min, &flt16_min_hex, sizeof(float16_t)); __test_exp((float16_t) 10, (float16_t) 1e-2, (float16_t) 1e2, flt16_min); #endif return *this; } TheTest &test_exp_fp32() { __test_exp(88.0f, 1e-6f, 1e6f, FLT_MIN); return *this; } TheTest &test_exp_fp64() { #if CV_SIMD_64F || CV_SIMD_SCALABLE_64F __test_exp(709.0, 1e-15, 1e15, DBL_MIN); #endif return *this; } void __test_log(LaneType expBound, LaneType diff_thr, LaneType flt_min) { int n = VTraits::vlanes(); // Test special values std::vector specialValues = {0, 1, (LaneType) M_E, INFINITY, -INFINITY, NAN}; const int testRandNum = 10000; const double specialValueProbability = 0.1; // 10% chance to insert a special value cv::RNG_MT19937 rng; for (int i = 0; i < testRandNum; i++) { Data dataRand, resRand; for (int j = 0; j < n; ++j) { if (rng.uniform(0.f, 1.f) <= specialValueProbability) { // Insert a special value int specialValueIndex = rng.uniform(0, (int) specialValues.size()); dataRand[j] = specialValues[specialValueIndex]; } else { // Generate uniform random data in [-expBound, expBound] dataRand[j] = (LaneType) std::exp(rng.uniform(-expBound, expBound)); } } // Compare with std::log R x = dataRand; resRand = v_log(x); for (int j = 0; j < n; ++j) { SCOPED_TRACE(cv::format("Random test value: %f", dataRand[j])); LaneType std_log = std::log(dataRand[j]); if (dataRand[j] == 0) { // input 0 -> output -INF EXPECT_TRUE(std::isinf(resRand[j]) && resRand[j] < 0); } else if (dataRand[j] < 0 || std::isnan(dataRand[j])) { // input less than 0 -> output NAN // input NaN -> output NaN EXPECT_TRUE(std::isnan(resRand[j])); } else if (dataRand[j] == 1) { // input 1 -> output 0 EXPECT_EQ((LaneType) 0, resRand[j]); } else if (std::isinf(dataRand[j]) && dataRand[j] > 0) { // input INF -> output INF EXPECT_TRUE(std::isinf(resRand[j]) && resRand[j] > 0); } else { EXPECT_LT(std::abs(resRand[j] - std_log), diff_thr * (std::abs(std_log) + flt_min * 100)); } } } } TheTest &test_log_fp16() { #if CV_SIMD_FP16 float16_t flt16_min; uint16_t flt16_min_hex = 0x0400; std::memcpy(&flt16_min, &flt16_min_hex, sizeof(float16_t)); __test_log((float16_t) 9, (float16_t) 1e-3, flt16_min); #endif return *this; } TheTest &test_log_fp32() { __test_log(25.f, 1e-6f, FLT_MIN); return *this; } TheTest &test_log_fp64() { #if CV_SIMD_64F || CV_SIMD_SCALABLE_64F __test_log(200., 1e-15, DBL_MIN); #endif return *this; } TheTest &test_erf_fp32() { int n = VTraits::vlanes(); constexpr int num_loops = 10000; const std::vector singular_inputs{INFINITY, -INFINITY, NAN}; constexpr double insert_singular_input_probability = 0.1; cv::RNG_MT19937 rng; for (int i = 0; i < num_loops; i++) { Data inputs; for (int j = 0; j < n; j++) { if (rng.uniform(0.f, 1.f) <= insert_singular_input_probability) { int singular_input_index = rng.uniform(0, int(singular_inputs.size())); inputs[j] = singular_inputs[singular_input_index]; } else { // std::exp(float) overflows at about 88.0f. // In v_erf, exp is called on input*input. So test range is [-sqrt(88.0f), sqrt(88.0f)] inputs[j] = (LaneType) rng.uniform(-9.4f, 9.4f); } } Data outputs = v_erf(R(inputs)); for (int j = 0; j < n; j++) { SCOPED_TRACE(cv::format("Random test value: %f", inputs[j])); if (std::isinf(inputs[j])) { if (inputs[j] < 0) { EXPECT_EQ(-1, outputs[j]); } else { EXPECT_EQ(1, outputs[j]); } } else if (std::isnan(inputs[j])) { EXPECT_TRUE(std::isnan(outputs[j])); } else { LaneType ref_output = std::erf(inputs[j]); EXPECT_LT(std::abs(outputs[j] - ref_output), 9e-3f * (std::abs(ref_output) + FLT_MIN * 1e4f)); } } } return *this; } void __test_sincos(LaneType diff_thr, LaneType flt_min) { int n = VTraits::vlanes(); // Test each value for a period, from -PI to PI const LaneType step = (LaneType) 0.01; for (LaneType i = 0; i <= (LaneType)M_PI;) { Data dataPosPI, dataNegPI; for (int j = 0; j < n; ++j) { dataPosPI[j] = i; dataNegPI[j] = -i; i += step; } R posPI = dataPosPI, negPI = dataNegPI, sinPos, cosPos, sinNeg, cosNeg; v_sincos(posPI, sinPos, cosPos); v_sincos(negPI, sinNeg, cosNeg); Data resSinPos = sinPos, resCosPos = cosPos, resSinNeg = sinNeg, resCosNeg = cosNeg; for (int j = 0; j < n; ++j) { LaneType std_sin_pos = (LaneType) std::sin(dataPosPI[j]); LaneType std_cos_pos = (LaneType) std::cos(dataPosPI[j]); LaneType std_sin_neg = (LaneType) std::sin(dataNegPI[j]); LaneType std_cos_neg = (LaneType) std::cos(dataNegPI[j]); SCOPED_TRACE(cv::format("Period test value: %lf and %lf", (double) dataPosPI[j], (double) dataNegPI[j])); EXPECT_LT(std::abs(resSinPos[j] - std_sin_pos), diff_thr * (std::abs(std_sin_pos) + flt_min * 100)); EXPECT_LT(std::abs(resCosPos[j] - std_cos_pos), diff_thr * (std::abs(std_cos_pos) + flt_min * 100)); EXPECT_LT(std::abs(resSinNeg[j] - std_sin_neg), diff_thr * (std::abs(std_sin_neg) + flt_min * 100)); EXPECT_LT(std::abs(resCosNeg[j] - std_cos_neg), diff_thr * (std::abs(std_cos_neg) + flt_min * 100)); } } // Test special values std::vector specialValues = {(LaneType) 0, (LaneType) M_PI, (LaneType) (M_PI / 2), (LaneType) INFINITY, (LaneType) -INFINITY, (LaneType) NAN}; const int testRandNum = 10000; const double specialValueProbability = 0.1; // 10% chance to insert a special value cv::RNG_MT19937 rng; for (int i = 0; i < testRandNum; i++) { Data dataRand; for (int j = 0; j < n; ++j) { if (rng.uniform(0.f, 1.f) <= specialValueProbability) { // Insert a special value int specialValueIndex = rng.uniform(0, (int) specialValues.size()); dataRand[j] = specialValues[specialValueIndex]; } else { // Generate uniform random data in [-1000, 1000] dataRand[j] = (LaneType) rng.uniform(-1000, 1000); } } // Compare with std::sin and std::cos R x = dataRand, s, c; v_sincos(x, s, c); Data resSin = s, resCos = c; for (int j = 0; j < n; ++j) { SCOPED_TRACE(cv::format("Random test value: %lf", (double) dataRand[j])); LaneType std_sin = (LaneType) std::sin(dataRand[j]); LaneType std_cos = (LaneType) std::cos(dataRand[j]); // input NaN, +INF, -INF -> output NaN if (std::isnan(dataRand[j]) || std::isinf(dataRand[j])) { EXPECT_TRUE(std::isnan(resSin[j])); EXPECT_TRUE(std::isnan(resCos[j])); } else if(dataRand[j] == 0) { // sin(0) -> 0, cos(0) -> 1 EXPECT_EQ(resSin[j], 0); EXPECT_EQ(resCos[j], 1); } else { EXPECT_LT(std::abs(resSin[j] - std_sin), diff_thr * (std::abs(std_sin) + flt_min * 100)); EXPECT_LT(std::abs(resCos[j] - std_cos), diff_thr * (std::abs(std_cos) + flt_min * 100)); } } } } TheTest &test_sincos_fp16() { #if CV_SIMD_FP16 hfloat flt16_min; uint16_t flt16_min_hex = 0x0400; std::memcpy(&flt16_min, &flt16_min_hex, sizeof(hfloat)); __test_sincos((hfloat) 1e-3, flt16_min); #endif return *this; } TheTest &test_sincos_fp32() { __test_sincos(1e-6f, FLT_MIN); return *this; } TheTest &test_sincos_fp64() { #if CV_SIMD_64F || CV_SIMD_SCALABLE_64F __test_sincos(1e-11, DBL_MIN); #endif return *this; } }; #define DUMP_ENTRY(type) printf("SIMD%d: %s\n", 8*VTraits::vlanes(), CV__TRACE_FUNCTION); //============= 8-bit integer ===================================================================== void test_hal_intrin_uint8() { DUMP_ENTRY(v_uint8); TheTest() .test_loadstore() .test_interleave() .test_interleave_pq() .test_expand() .test_expand_q() .test_addsub() .test_arithm_wrap() .test_mul() .test_mul_expand() .test_cmp() .test_logic() .test_dotprod_expand() .test_min_max() .test_absdiff() .test_reduce() .test_reduce_sad() .test_mask() .test_popcount() .test_pack<1>().test_pack<2>().test_pack<3>().test_pack<8>() .test_pack_u<1>().test_pack_u<2>().test_pack_u<3>().test_pack_u<8>() .test_pack_b() .test_unpack() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<8>().test_extract<15>() .test_rotate<0>().test_rotate<1>().test_rotate<8>().test_rotate<15>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() .test_pack_triplets() //.test_broadcast_element<0>().test_broadcast_element<1>() #if CV_SIMD_WIDTH == 32 .test_pack<9>().test_pack<10>().test_pack<13>().test_pack<15>() .test_pack_u<9>().test_pack_u<10>().test_pack_u<13>().test_pack_u<15>() .test_extract<16>().test_extract<17>().test_extract<23>().test_extract<31>() .test_rotate<16>().test_rotate<17>().test_rotate<23>().test_rotate<31>() #endif ; } void test_hal_intrin_int8() { DUMP_ENTRY(v_int8); TheTest() .test_loadstore() .test_interleave() .test_interleave_pq() .test_expand() .test_expand_q() .test_addsub() .test_arithm_wrap() .test_mul() .test_mul_expand() .test_cmp() .test_logic() .test_dotprod_expand() .test_min_max() .test_absdiff() .test_absdiffs() .test_abs() .test_reduce() .test_reduce_sad() .test_mask() .test_popcount() .test_pack<1>().test_pack<2>().test_pack<3>().test_pack<8>() .test_unpack() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<8>().test_extract<15>() .test_rotate<0>().test_rotate<1>().test_rotate<8>().test_rotate<15>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() .test_pack_triplets() //.test_broadcast_element<0>().test_broadcast_element<1>() ; } //============= 16-bit integer ===================================================================== void test_hal_intrin_uint16() { DUMP_ENTRY(v_uint16); TheTest() .test_loadstore() .test_interleave() .test_interleave_pq() .test_expand() .test_addsub() .test_arithm_wrap() .test_mul() .test_mul_expand() .test_mul_hi() .test_cmp() .test_shift<1>() .test_shift<8>() .test_dotprod_expand() .test_logic() .test_min_max() .test_absdiff() .test_reduce() .test_reduce_sad() .test_mask() .test_popcount() .test_pack<1>().test_pack<2>().test_pack<7>().test_pack<16>() .test_pack_u<1>().test_pack_u<2>().test_pack_u<7>().test_pack_u<16>() .test_unpack() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<4>().test_extract<7>() .test_rotate<0>().test_rotate<1>().test_rotate<4>().test_rotate<7>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() .test_pack_triplets() //.test_broadcast_element<0>().test_broadcast_element<1>() ; } void test_hal_intrin_int16() { DUMP_ENTRY(v_int16); TheTest() .test_loadstore() .test_interleave() .test_interleave_pq() .test_expand() .test_addsub() .test_arithm_wrap() .test_mul() .test_mul_expand() .test_mul_hi() .test_cmp() .test_shift<1>() .test_shift<8>() .test_dotprod() .test_dotprod_expand() .test_logic() .test_min_max() .test_absdiff() .test_absdiffs() .test_abs() .test_reduce() .test_reduce_sad() .test_mask() .test_popcount() .test_pack<1>().test_pack<2>().test_pack<7>().test_pack<16>() .test_unpack() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<4>().test_extract<7>() .test_rotate<0>().test_rotate<1>().test_rotate<4>().test_rotate<7>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() .test_pack_triplets() //.test_broadcast_element<0>().test_broadcast_element<1>() ; } //============= 32-bit integer ===================================================================== void test_hal_intrin_uint32() { DUMP_ENTRY(v_uint32); TheTest() .test_loadstore() .test_interleave() // .test_interleave_pq() //not implemented in AVX .test_expand() .test_addsub() .test_mul() .test_mul_expand() .test_cmp() .test_shift<1>() .test_shift<8>() .test_logic() .test_min_max() .test_absdiff() .test_reduce() .test_reduce_sad() .test_mask() .test_popcount() .test_pack<1>().test_pack<2>().test_pack<15>().test_pack<32>() .test_unpack() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<2>().test_extract<3>() .test_rotate<0>().test_rotate<1>().test_rotate<2>().test_rotate<3>() .test_extract_n<0>().test_extract_n<1>() .test_broadcast_element<0>().test_broadcast_element<1>() .test_extract_highest() .test_broadcast_highest() .test_transpose() .test_pack_triplets() ; } void test_hal_intrin_int32() { DUMP_ENTRY(v_int32); TheTest() .test_loadstore() .test_interleave() // .test_interleave_pq() //not implemented in AVX .test_expand() .test_addsub() .test_mul() .test_abs() .test_cmp() .test_popcount() .test_shift<1>().test_shift<8>() .test_dotprod() .test_dotprod_expand_f64() .test_logic() .test_min_max() .test_absdiff() .test_reduce() .test_reduce_sad() .test_mask() .test_pack<1>().test_pack<2>().test_pack<15>().test_pack<32>() .test_unpack() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<2>().test_extract<3>() .test_rotate<0>().test_rotate<1>().test_rotate<2>().test_rotate<3>() .test_extract_n<0>().test_extract_n<1>() .test_broadcast_element<0>().test_broadcast_element<1>() .test_float_cvt32() .test_float_cvt64() .test_transpose() .test_extract_highest() .test_broadcast_highest() .test_pack_triplets() ; } //============= 64-bit integer ===================================================================== void test_hal_intrin_uint64() { DUMP_ENTRY(v_uint64); TheTest() .test_loadstore() .test_addsub() .test_cmp64() //.test_cmp() - not declared as supported .test_shift<1>().test_shift<8>() .test_logic() .test_reverse() .test_extract<0>().test_extract<1>() .test_rotate<0>().test_rotate<1>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() .test_popcount() //.test_broadcast_element<0>().test_broadcast_element<1>() ; } void test_hal_intrin_int64() { DUMP_ENTRY(v_int64); TheTest() .test_loadstore() .test_addsub() .test_cmp64() //.test_cmp() - not declared as supported .test_shift<1>().test_shift<8>() .test_logic() .test_reverse() .test_extract<0>().test_extract<1>() .test_rotate<0>().test_rotate<1>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() //.test_broadcast_element<0>().test_broadcast_element<1>() .test_cvt64_double() .test_popcount() ; } //============= Floating point ===================================================================== void test_hal_intrin_float32() { DUMP_ENTRY(v_float32); TheTest() .test_loadstore() .test_interleave() .test_interleave_2channel() // .test_interleave_pq() //not implemented in AVX .test_addsub() .test_mul() .test_div() .test_abs() .test_cmp() .test_sqrt_abs() .test_min_max() .test_float_absdiff() .test_reduce() .test_reduce_sad() .test_mask() .test_unpack() .test_float_math() .test_float_cvt64() .test_matmul() .test_transpose() .test_reduce_sum4() .test_reverse() .test_extract<0>().test_extract<1>().test_extract<2>().test_extract<3>() .test_rotate<0>().test_rotate<1>().test_rotate<2>().test_rotate<3>() .test_extract_n<0>().test_extract_n<1>() .test_broadcast_element<0>().test_broadcast_element<1>() .test_extract_highest() .test_broadcast_highest() .test_pack_triplets() .test_exp_fp32() .test_log_fp32() .test_sincos_fp32() .test_erf_fp32() #if CV_SIMD_WIDTH == 32 .test_extract<4>().test_extract<5>().test_extract<6>().test_extract<7>() .test_rotate<4>().test_rotate<5>().test_rotate<6>().test_rotate<7>() #endif ; } void test_hal_intrin_float64() { DUMP_ENTRY(v_float64); #if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F) TheTest() .test_loadstore() .test_addsub() .test_mul() .test_div() .test_abs() .test_cmp() .test_sqrt_abs() .test_min_max() .test_float_absdiff() .test_mask() .test_unpack() .test_float_math() .test_round_pair_f64() .test_float_cvt32() .test_reverse() .test_extract<0>().test_extract<1>() .test_rotate<0>().test_rotate<1>() .test_extract_n<0>().test_extract_n<1>() .test_extract_highest() .test_exp_fp64() .test_log_fp64() .test_sincos_fp64() //.test_broadcast_element<0>().test_broadcast_element<1>() #if CV_SIMD_WIDTH == 32 .test_extract<2>().test_extract<3>() .test_rotate<2>().test_rotate<3>() #endif ; #else std::cout << "SKIP: CV_SIMD_64F is not available" << std::endl; #endif } void test_hal_intrin_float16() { DUMP_ENTRY(v_float16); #if CV_FP16 TheTest() .test_loadstore_fp16_f32() #if CV_SIMD_FP16 .test_loadstore_fp16() .test_float_cvt_fp16() .test_exp_fp16() .test_log_fp16() .test_sincos_fp16() #endif ; #else std::cout << "SKIP: CV_FP16 is not available" << std::endl; #endif } /*#if defined(CV_CPU_DISPATCH_MODE_FP16) && CV_CPU_DISPATCH_MODE == FP16 void test_hal_intrin_float16() { TheTest() .test_loadstore_fp16() .test_float_cvt_fp16() ; } #endif*/ #if defined (CV_DISABLE_GCC_MAYBE_UNINITIALIZED_WARNINGS) #pragma GCC diagnostic pop #endif #endif //CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY //CV_CPU_OPTIMIZATION_NAMESPACE_END //}}} // namespace