1
0
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:
Vadim Pisarevsky
2018-07-16 18:57:24 +03:00
committed by GitHub
parent 481829a81b
commit f058b5fb1e
13 changed files with 3167 additions and 1261 deletions
+2 -2
View File
@@ -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");
}
+2 -2
View File
@@ -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()
;
+67 -51
View File
@@ -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
+3 -1
View File
@@ -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;
}
}