mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Wide univ intrinsics (#11953)
* core:OE-27 prepare universal intrinsics to expand (#11022) * core:OE-27 prepare universal intrinsics to expand (#11022) * core: Add universal intrinsics for AVX2 * updated implementation of wide univ. intrinsics; converted several OpenCV HAL functions: sqrt, invsqrt, magnitude, phase, exp to the wide universal intrinsics. * converted log to universal intrinsics; cleaned up the code a bit; added v_lut_deinterleave intrinsics. * core: Add universal intrinsics for AVX2 * fixed multiple compile errors * fixed many more compile errors and hopefully some test failures * fixed some more compile errors * temporarily disabled IPP to debug exp & log; hopefully fixed Doxygen complains * fixed some more compile errors * fixed v_store(short*, v_float16&) signatures * trying to fix the test failures on Linux * fixed some issues found by alalek * restored IPP optimization after the patch with AVX wide intrinsics has been properly tested * restored IPP optimization after the patch with AVX wide intrinsics has been properly tested
This commit is contained in:
@@ -241,9 +241,9 @@ TEST(hal_intrin, float64x2) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(hal_intrin,float16x4)
|
||||
TEST(hal_intrin,float16)
|
||||
{
|
||||
CV_CPU_CALL_FP16_(test_hal_intrin_float16x4, ());
|
||||
CV_CPU_CALL_FP16_(test_hal_intrin_float16, ());
|
||||
throw SkipTestException("Unsupported hardware: FP16 is not available");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
namespace opencv_test { namespace hal {
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
|
||||
|
||||
void test_hal_intrin_float16x4()
|
||||
void test_hal_intrin_float16()
|
||||
{
|
||||
TheTest<v_float16x4>()
|
||||
TheTest<v_float16x8>()
|
||||
.test_loadstore_fp16()
|
||||
.test_float_cvt_fp16()
|
||||
;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
namespace opencv_test { namespace hal {
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
|
||||
|
||||
void test_hal_intrin_float16x4();
|
||||
void test_hal_intrin_float16();
|
||||
|
||||
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
@@ -50,6 +50,8 @@ template <> struct initializer<2>
|
||||
template <typename R> struct Data
|
||||
{
|
||||
typedef typename R::lane_type LaneType;
|
||||
typedef typename V_TypeTraits<LaneType>::int_type int_type;
|
||||
|
||||
Data()
|
||||
{
|
||||
for (int i = 0; i < R::nlanes; ++i)
|
||||
@@ -104,6 +106,17 @@ template <typename R> struct Data
|
||||
CV_Assert(i >= 0 && i < R::nlanes);
|
||||
return d[i];
|
||||
}
|
||||
int_type as_int(int i) const
|
||||
{
|
||||
CV_Assert(i >= 0 && i < R::nlanes);
|
||||
union
|
||||
{
|
||||
LaneType l;
|
||||
int_type i;
|
||||
} v;
|
||||
v.l = d[i];
|
||||
return v.i;
|
||||
}
|
||||
const LaneType * mid() const
|
||||
{
|
||||
return d + R::nlanes / 2;
|
||||
@@ -247,8 +260,9 @@ template<typename R> struct TheTest
|
||||
EXPECT_EQ(d, res);
|
||||
|
||||
// zero, all
|
||||
Data<R> resZ = V_RegTrait128<LaneType>::zero();
|
||||
Data<R> resV = V_RegTrait128<LaneType>::all(8);
|
||||
Data<R> resZ, resV;
|
||||
resZ.fill((LaneType)0);
|
||||
resV.fill((LaneType)8);
|
||||
for (int i = 0; i < R::nlanes; ++i)
|
||||
{
|
||||
EXPECT_EQ((LaneType)0, resZ[i]);
|
||||
@@ -339,7 +353,7 @@ template<typename R> struct TheTest
|
||||
// v_expand and v_load_expand
|
||||
TheTest & test_expand()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
|
||||
typedef typename V_RegTraits<R>::w_reg Rx2;
|
||||
Data<R> dataA;
|
||||
R a = dataA;
|
||||
|
||||
@@ -362,7 +376,7 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_expand_q()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::q_reg Rx4;
|
||||
typedef typename V_RegTraits<R>::q_reg Rx4;
|
||||
Data<R> data;
|
||||
Data<Rx4> out = v_load_expand_q(data.d);
|
||||
const int n = Rx4::nlanes;
|
||||
@@ -436,7 +450,7 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_mul_expand()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
|
||||
typedef typename V_RegTraits<R>::w_reg Rx2;
|
||||
Data<R> dataA, dataB(2);
|
||||
R a = dataA, b = dataB;
|
||||
Rx2 c, d;
|
||||
@@ -456,7 +470,7 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_abs()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::u_reg Ru;
|
||||
typedef typename V_RegTraits<R>::u_reg Ru;
|
||||
typedef typename Ru::lane_type u_type;
|
||||
Data<R> dataA, dataB(10);
|
||||
R a = dataA, b = dataB;
|
||||
@@ -520,7 +534,7 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_dot_prod()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
|
||||
typedef typename V_RegTraits<R>::w_reg Rx2;
|
||||
typedef typename Rx2::lane_type w_type;
|
||||
|
||||
Data<R> dataA, dataB(2);
|
||||
@@ -608,7 +622,7 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_absdiff()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::u_reg Ru;
|
||||
typedef typename V_RegTraits<R>::u_reg Ru;
|
||||
typedef typename Ru::lane_type u_type;
|
||||
Data<R> dataA(std::numeric_limits<LaneType>::max()),
|
||||
dataB(std::numeric_limits<LaneType>::min());
|
||||
@@ -657,12 +671,21 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_mask()
|
||||
{
|
||||
typedef V_TypeTraits<LaneType> Traits;
|
||||
typedef typename Traits::int_type int_type;
|
||||
typedef typename V_RegTraits<R>::int_reg int_reg;
|
||||
typedef typename V_RegTraits<int_reg>::u_reg uint_reg;
|
||||
typedef typename int_reg::lane_type int_type;
|
||||
typedef typename uint_reg::lane_type uint_type;
|
||||
|
||||
Data<R> dataA, dataB(0), dataC, dataD(1), dataE(2);
|
||||
dataA[1] *= (LaneType)-1;
|
||||
const LaneType mask_one = Traits::reinterpret_from_int(~(typename Traits::uint_type)(0));
|
||||
union
|
||||
{
|
||||
LaneType l;
|
||||
uint_type ui;
|
||||
}
|
||||
all1s;
|
||||
all1s.ui = (uint_type)-1;
|
||||
LaneType mask_one = all1s.l;
|
||||
dataB[1] = mask_one;
|
||||
dataB[R::nlanes / 2] = mask_one;
|
||||
dataB[R::nlanes - 1] = mask_one;
|
||||
@@ -684,10 +707,8 @@ template<typename R> struct TheTest
|
||||
Data<R> resF = f;
|
||||
for (int i = 0; i < R::nlanes; ++i)
|
||||
{
|
||||
int_type m2 = Traits::reinterpret_int(dataB[i]);
|
||||
EXPECT_EQ((Traits::reinterpret_int(dataD[i]) & m2)
|
||||
| (Traits::reinterpret_int(dataE[i]) & ~m2),
|
||||
Traits::reinterpret_int(resF[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;
|
||||
@@ -697,7 +718,7 @@ template<typename R> struct TheTest
|
||||
TheTest & test_pack()
|
||||
{
|
||||
SCOPED_TRACE(s);
|
||||
typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
|
||||
typedef typename V_RegTraits<R>::w_reg Rx2;
|
||||
typedef typename Rx2::lane_type w_type;
|
||||
Data<Rx2> dataA, dataB;
|
||||
dataA += std::numeric_limits<LaneType>::is_signed ? -10 : 10;
|
||||
@@ -734,8 +755,9 @@ template<typename R> struct TheTest
|
||||
TheTest & test_pack_u()
|
||||
{
|
||||
SCOPED_TRACE(s);
|
||||
typedef typename V_TypeTraits<LaneType>::w_type LaneType_w;
|
||||
typedef typename V_RegTrait128<LaneType_w>::int_reg Ri2;
|
||||
//typedef typename V_RegTraits<LaneType>::w_type LaneType_w;
|
||||
typedef typename V_RegTraits<R>::w_reg R2;
|
||||
typedef typename V_RegTraits<R2>::int_reg Ri2;
|
||||
typedef typename Ri2::lane_type w_type;
|
||||
|
||||
Data<Ri2> dataA, dataB;
|
||||
@@ -864,7 +886,7 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_float_math()
|
||||
{
|
||||
typedef typename V_RegTrait128<LaneType>::int_reg Ri;
|
||||
typedef typename V_RegTraits<R>::round_reg Ri;
|
||||
Data<R> data1, data2, data3;
|
||||
data1 *= 1.1;
|
||||
data2 += 10;
|
||||
@@ -1005,31 +1027,28 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_loadstore_fp16()
|
||||
{
|
||||
#if CV_FP16 && CV_SIMD128
|
||||
#if CV_FP16 && CV_SIMD
|
||||
AlignedData<R> data;
|
||||
AlignedData<R> out;
|
||||
|
||||
if(1 /* checkHardwareSupport(CV_CPU_FP16) */ )
|
||||
{
|
||||
// check if addresses are aligned and unaligned respectively
|
||||
EXPECT_EQ((size_t)0, (size_t)&data.a.d % 16);
|
||||
EXPECT_NE((size_t)0, (size_t)&data.u.d % 16);
|
||||
EXPECT_EQ((size_t)0, (size_t)&out.a.d % 16);
|
||||
EXPECT_NE((size_t)0, (size_t)&out.u.d % 16);
|
||||
// check if addresses are aligned and unaligned respectively
|
||||
EXPECT_EQ((size_t)0, (size_t)&data.a.d % 16);
|
||||
EXPECT_NE((size_t)0, (size_t)&data.u.d % 16);
|
||||
EXPECT_EQ((size_t)0, (size_t)&out.a.d % 16);
|
||||
EXPECT_NE((size_t)0, (size_t)&out.u.d % 16);
|
||||
|
||||
// check some initialization methods
|
||||
R r1 = data.u;
|
||||
R r2 = v_load_f16(data.a.d);
|
||||
R r3(r2);
|
||||
EXPECT_EQ(data.u[0], r1.get0());
|
||||
EXPECT_EQ(data.a[0], r2.get0());
|
||||
EXPECT_EQ(data.a[0], r3.get0());
|
||||
// check some initialization methods
|
||||
R r1 = data.u;
|
||||
R r2 = v_load_f16(data.a.d);
|
||||
R r3(r2);
|
||||
EXPECT_EQ(data.u[0], r1.get0());
|
||||
EXPECT_EQ(data.a[0], r2.get0());
|
||||
EXPECT_EQ(data.a[0], r3.get0());
|
||||
|
||||
// check some store methods
|
||||
out.a.clear();
|
||||
v_store_f16(out.a.d, r1);
|
||||
EXPECT_EQ(data.a, out.a);
|
||||
}
|
||||
// check some store methods
|
||||
out.a.clear();
|
||||
v_store(out.a.d, r1);
|
||||
EXPECT_EQ(data.a, out.a);
|
||||
|
||||
return *this;
|
||||
#endif
|
||||
@@ -1037,18 +1056,15 @@ template<typename R> struct TheTest
|
||||
|
||||
TheTest & test_float_cvt_fp16()
|
||||
{
|
||||
#if CV_FP16 && CV_SIMD128
|
||||
AlignedData<v_float32x4> data;
|
||||
#if CV_FP16 && CV_SIMD
|
||||
AlignedData<v_float32> data;
|
||||
|
||||
if(1 /* checkHardwareSupport(CV_CPU_FP16) */)
|
||||
{
|
||||
// check conversion
|
||||
v_float32x4 r1 = v_load(data.a.d);
|
||||
v_float16x4 r2 = v_cvt_f16(r1);
|
||||
v_float32x4 r3 = v_cvt_f32(r2);
|
||||
EXPECT_EQ(0x3c00, r2.get0());
|
||||
EXPECT_EQ(r3.get0(), r1.get0());
|
||||
}
|
||||
// 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, r2.get0());
|
||||
EXPECT_EQ(r3.get0(), r1.get0());
|
||||
|
||||
return *this;
|
||||
#endif
|
||||
|
||||
@@ -134,7 +134,9 @@ double Core_PowTest::get_success_error_level( int test_case_idx, int i, int j )
|
||||
if( depth < CV_32F )
|
||||
return power == cvRound(power) && power >= 0 ? 0 : 1;
|
||||
else
|
||||
return Base::get_success_error_level( test_case_idx, i, j );
|
||||
{
|
||||
return depth != CV_64F ? Base::get_success_error_level( test_case_idx, i, j ) : DBL_EPSILON*1024*1.1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user