Change behaviour of 16-bit multiply operator

- redefine 16-bit multiply operator to perform saturating multiply
    instead of non-saturating multiply
  - implement 8-bit multiply operator to perform saturating multiply
  - implement v_mul_wrap() for 8-bit, 16-bit non-saturating multiply
  - improve performance of v_mul_hi() for VSX
  - update intrin tests with new changes
  - replace unv 16-bit multiplication operator with v_mul_wrap due behavior changes

  - Several improvements depend on vpisarev review

    * initial forward declarations for universal intrinsics
    * move emulating SSE intrinsics into separate file
    * implement v_mul_expand for 8-bit
    * reimplement saturating multiply using v_mul_expand + v_pack
    * map v_expand, v_load_expand, v_load_expand_q to sse4.1
    * fix overflow avx2::v_pack(uint32)
    * implement two universal intrinsics v_expand_low and v_expand_high
This commit is contained in:
Sayed Adel
2018-09-12 21:32:34 +02:00
parent 1ff11c84ab
commit 5771fd693d
13 changed files with 744 additions and 193 deletions

View File

@@ -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()