Unverified Commit e180cc05 authored by Alexander Alekhin's avatar Alexander Alekhin Committed by GitHub

Merge pull request #16236 from alalek:fix_core_simd_emulator

* core: fix intrin_cpp, allow to build modules with SIMD emulator

* core(arithm): fix v_zero initialization

* core(simd): 'strict' types for binary/bitwise operations

* features2d: avoid aligned load issue in GCC 5.4 with emulated SIMD

* core(simd): alignment checks in SIMD emulator
parent c75d9333
...@@ -99,6 +99,7 @@ enum StoreMode ...@@ -99,6 +99,7 @@ enum StoreMode
} }
// TODO FIXIT: Don't use "God" traits. Split on separate cases.
template<typename _Tp> struct V_TypeTraits template<typename _Tp> struct V_TypeTraits
{ {
}; };
...@@ -130,21 +131,51 @@ template<typename _Tp> struct V_TypeTraits ...@@ -130,21 +131,51 @@ template<typename _Tp> struct V_TypeTraits
} \ } \
} }
#define CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(type, int_type_, uint_type_, abs_type_, w_type_, sum_type_, nlanes128_) \
template<> struct V_TypeTraits<type> \
{ \
typedef type value_type; \
typedef int_type_ int_type; \
typedef abs_type_ abs_type; \
typedef uint_type_ uint_type; \
typedef w_type_ w_type; \
typedef sum_type_ sum_type; \
enum { nlanes128 = nlanes128_ }; \
\
static inline int_type reinterpret_int(type x) \
{ \
union { type l; int_type i; } v; \
v.l = x; \
return v.i; \
} \
\
static inline type reinterpret_from_int(int_type x) \
{ \
union { type l; int_type i; } v; \
v.i = x; \
return v.l; \
} \
}
CV_INTRIN_DEF_TYPE_TRAITS(uchar, schar, uchar, uchar, ushort, unsigned, unsigned, 16); CV_INTRIN_DEF_TYPE_TRAITS(uchar, schar, uchar, uchar, ushort, unsigned, unsigned, 16);
CV_INTRIN_DEF_TYPE_TRAITS(schar, schar, uchar, uchar, short, int, int, 16); CV_INTRIN_DEF_TYPE_TRAITS(schar, schar, uchar, uchar, short, int, int, 16);
CV_INTRIN_DEF_TYPE_TRAITS(ushort, short, ushort, ushort, unsigned, uint64, unsigned, 8); CV_INTRIN_DEF_TYPE_TRAITS(ushort, short, ushort, ushort, unsigned, uint64, unsigned, 8);
CV_INTRIN_DEF_TYPE_TRAITS(short, short, ushort, ushort, int, int64, int, 8); CV_INTRIN_DEF_TYPE_TRAITS(short, short, ushort, ushort, int, int64, int, 8);
CV_INTRIN_DEF_TYPE_TRAITS(unsigned, int, unsigned, unsigned, uint64, void, unsigned, 4); CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(unsigned, int, unsigned, unsigned, uint64, unsigned, 4);
CV_INTRIN_DEF_TYPE_TRAITS(int, int, unsigned, unsigned, int64, void, int, 4); CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int, int, unsigned, unsigned, int64, int, 4);
CV_INTRIN_DEF_TYPE_TRAITS(float, int, unsigned, float, double, void, float, 4); CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(float, int, unsigned, float, double, float, 4);
CV_INTRIN_DEF_TYPE_TRAITS(uint64, int64, uint64, uint64, void, void, uint64, 2); CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(uint64, int64, uint64, uint64, void, uint64, 2);
CV_INTRIN_DEF_TYPE_TRAITS(int64, int64, uint64, uint64, void, void, int64, 2); CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int64, int64, uint64, uint64, void, int64, 2);
CV_INTRIN_DEF_TYPE_TRAITS(double, int64, uint64, double, void, void, double, 2); CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(double, int64, uint64, double, void, double, 2);
#ifndef CV_DOXYGEN #ifndef CV_DOXYGEN
#ifndef CV_CPU_OPTIMIZATION_HAL_NAMESPACE #ifndef CV_CPU_OPTIMIZATION_HAL_NAMESPACE
#ifdef CV_CPU_DISPATCH_MODE #ifdef CV_FORCE_SIMD128_CPP
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE hal_EMULATOR_CPP
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace hal_EMULATOR_CPP {
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END }
#elif defined(CV_CPU_DISPATCH_MODE)
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE __CV_CAT(hal_, CV_CPU_DISPATCH_MODE)
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) { #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) {
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END }
...@@ -197,7 +228,6 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE; ...@@ -197,7 +228,6 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE;
#else #else
#define CV_SIMD128_CPP 1
#include "opencv2/core/hal/intrin_cpp.hpp" #include "opencv2/core/hal/intrin_cpp.hpp"
#endif #endif
...@@ -242,6 +272,10 @@ CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN ...@@ -242,6 +272,10 @@ CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
#define CV_SIMD128 0 #define CV_SIMD128 0
#endif #endif
#ifndef CV_SIMD128_CPP
#define CV_SIMD128_CPP 0
#endif
#ifndef CV_SIMD128_64F #ifndef CV_SIMD128_64F
#define CV_SIMD128_64F 0 #define CV_SIMD128_64F 0
#endif #endif
...@@ -346,7 +380,7 @@ template<typename _Tp> struct V_RegTraits ...@@ -346,7 +380,7 @@ template<typename _Tp> struct V_RegTraits
CV_DEF_REG_TRAITS(v, v_int16x8, short, s16, v_uint16x8, v_int32x4, v_int64x2, v_int16x8, void); CV_DEF_REG_TRAITS(v, v_int16x8, short, s16, v_uint16x8, v_int32x4, v_int64x2, v_int16x8, void);
CV_DEF_REG_TRAITS(v, v_uint32x4, unsigned, u32, v_uint32x4, v_uint64x2, void, v_int32x4, void); CV_DEF_REG_TRAITS(v, v_uint32x4, unsigned, u32, v_uint32x4, v_uint64x2, void, v_int32x4, void);
CV_DEF_REG_TRAITS(v, v_int32x4, int, s32, v_uint32x4, v_int64x2, void, v_int32x4, void); CV_DEF_REG_TRAITS(v, v_int32x4, int, s32, v_uint32x4, v_int64x2, void, v_int32x4, void);
#if CV_SIMD128_64F #if CV_SIMD128_64F || CV_SIMD128_CPP
CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, v_float64x2, void, v_int32x4, v_int32x4); CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, v_float64x2, void, v_int32x4, v_int32x4);
#else #else
CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, void, void, v_int32x4, v_int32x4); CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, void, void, v_int32x4, v_int32x4);
...@@ -433,7 +467,11 @@ namespace CV__SIMD_NAMESPACE { ...@@ -433,7 +467,11 @@ namespace CV__SIMD_NAMESPACE {
} // namespace } // namespace
using namespace CV__SIMD_NAMESPACE; using namespace CV__SIMD_NAMESPACE;
#elif (CV_SIMD128 || CV_SIMD128_CPP) && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 128) #elif (CV_SIMD128 || CV_SIMD128_CPP) && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 128)
#if defined CV_SIMD128_CPP
#define CV__SIMD_NAMESPACE simd128_cpp
#else
#define CV__SIMD_NAMESPACE simd128 #define CV__SIMD_NAMESPACE simd128
#endif
namespace CV__SIMD_NAMESPACE { namespace CV__SIMD_NAMESPACE {
#define CV_SIMD CV_SIMD128 #define CV_SIMD CV_SIMD128
#define CV_SIMD_64F CV_SIMD128_64F #define CV_SIMD_64F CV_SIMD128_64F
......
...@@ -1522,7 +1522,8 @@ struct InRange_SIMD<float> ...@@ -1522,7 +1522,8 @@ struct InRange_SIMD<float>
v_float32 low2 = vx_load(src2 + x + v_float32::nlanes); v_float32 low2 = vx_load(src2 + x + v_float32::nlanes);
v_float32 high2 = vx_load(src3 + x + v_float32::nlanes); v_float32 high2 = vx_load(src3 + x + v_float32::nlanes);
v_pack_store(dst + x, v_pack(v_reinterpret_as_u32((values1 >= low1) & (high1 >= values1)), v_reinterpret_as_u32((values2 >= low2) & (high2 >= values2)))); v_pack_store(dst + x, v_pack(v_reinterpret_as_u32(values1 >= low1) & v_reinterpret_as_u32(high1 >= values1),
v_reinterpret_as_u32(values2 >= low2) & v_reinterpret_as_u32(high2 >= values2)));
} }
vx_cleanup(); vx_cleanup();
return x; return x;
......
...@@ -1593,7 +1593,7 @@ struct op_div_f ...@@ -1593,7 +1593,7 @@ struct op_div_f
{ {
static inline Tvec r(const Tvec& a, const Tvec& b) static inline Tvec r(const Tvec& a, const Tvec& b)
{ {
const Tvec v_zero = Tvec(); const Tvec v_zero = vx_setall<typename Tvec::lane_type>(0);
return v_select(b == v_zero, v_zero, a / b); return v_select(b == v_zero, v_zero, a / b);
} }
static inline T1 r(T1 a, T1 b) static inline T1 r(T1 a, T1 b)
...@@ -1620,7 +1620,7 @@ struct op_div_scale ...@@ -1620,7 +1620,7 @@ struct op_div_scale
} }
static inline Tvec pre(const Tvec& denom, const Tvec& res) static inline Tvec pre(const Tvec& denom, const Tvec& res)
{ {
const Tvec v_zero = Tvec(); const Tvec v_zero = vx_setall<typename Tvec::lane_type>(0);
return v_select(denom == v_zero, v_zero, res); return v_select(denom == v_zero, v_zero, res);
} }
static inline T1 r(T1 a, T1 denom, const T2* scalar) static inline T1 r(T1 a, T1 denom, const T2* scalar)
...@@ -1860,7 +1860,7 @@ struct op_recip ...@@ -1860,7 +1860,7 @@ struct op_recip
} }
static inline Tvec pre(const Tvec& denom, const Tvec& res) static inline Tvec pre(const Tvec& denom, const Tvec& res)
{ {
const Tvec v_zero = Tvec(); const Tvec v_zero = vx_setall<typename Tvec::lane_type>(0);
return v_select(denom == v_zero, v_zero, res); return v_select(denom == v_zero, v_zero, res);
} }
static inline T1 r(T1 denom, const T2* scalar) static inline T1 r(T1 denom, const T2* scalar)
......
...@@ -916,8 +916,9 @@ double cv::invert( InputArray _src, OutputArray _dst, int method ) ...@@ -916,8 +916,9 @@ double cv::invert( InputArray _src, OutputArray _dst, int method )
result = true; result = true;
d = 1./d; d = 1./d;
#if CV_SIMD128 #if CV_SIMD128
static const float CV_DECL_ALIGNED(16) inv[4] = { 0.f,-0.f,-0.f,0.f }; const float d_32f = (float)d;
v_float32x4 s0 = (v_load_halves((const float*)srcdata, (const float*)(srcdata + srcstep)) * v_setall_f32((float)d)) ^ v_load((const float *)inv);//0123//3120 const v_float32x4 d_vec(d_32f, -d_32f, -d_32f, d_32f);
v_float32x4 s0 = v_load_halves((const float*)srcdata, (const float*)(srcdata + srcstep)) * d_vec;//0123//3120
s0 = v_extract<3>(s0, v_combine_low(v_rotate_right<1>(s0), s0)); s0 = v_extract<3>(s0, v_combine_low(v_rotate_right<1>(s0), s0));
v_store_low((float*)dstdata, s0); v_store_low((float*)dstdata, s0);
v_store_high((float*)(dstdata + dststep), s0); v_store_high((float*)(dstdata + dststep), s0);
...@@ -946,7 +947,7 @@ double cv::invert( InputArray _src, OutputArray _dst, int method ) ...@@ -946,7 +947,7 @@ double cv::invert( InputArray _src, OutputArray _dst, int method )
v_float64x2 s0 = v_load((const double*)srcdata) * det; v_float64x2 s0 = v_load((const double*)srcdata) * det;
v_float64x2 s1 = v_load((const double*)(srcdata+srcstep)) * det; v_float64x2 s1 = v_load((const double*)(srcdata+srcstep)) * det;
v_float64x2 sm = v_extract<1>(s1, s0);//30 v_float64x2 sm = v_extract<1>(s1, s0);//30
v_float64x2 ss = v_extract<1>(s0, s1) ^ v_setall_f64(-0.);//12 v_float64x2 ss = v_setall<double>(0) - v_extract<1>(s0, s1);//12
v_store((double*)dstdata, v_combine_low(sm, ss));//31 v_store((double*)dstdata, v_combine_low(sm, ss));//31
v_store((double*)(dstdata + dststep), v_combine_high(ss, sm));//20 v_store((double*)(dstdata + dststep), v_combine_high(ss, sm));//20
#else #else
......
...@@ -725,7 +725,7 @@ void log32f( const float *_x, float *y, int n ) ...@@ -725,7 +725,7 @@ void log32f( const float *_x, float *y, int n )
yf0 = v_fma(v_cvt_f32(yi0), vln2, yf0); yf0 = v_fma(v_cvt_f32(yi0), vln2, yf0);
v_float32 delta = v_reinterpret_as_f32(h0 == vx_setall_s32(510)) & vshift; v_float32 delta = v_select(v_reinterpret_as_f32(h0 == vx_setall_s32(510)), vshift, vx_setall<float>(0));
xf0 = v_fma((v_reinterpret_as_f32(xi0) - v1), xf0, delta); xf0 = v_fma((v_reinterpret_as_f32(xi0) - v1), xf0, delta);
v_float32 zf0 = v_fma(xf0, vA0, vA1); v_float32 zf0 = v_fma(xf0, vA0, vA1);
......
...@@ -3,22 +3,14 @@ ...@@ -3,22 +3,14 @@
// of this distribution and at http://opencv.org/license.html. // of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp" #include "test_precomp.hpp"
// see "opencv2/core/hal/intrin.hpp"
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE hal_EMULATOR_CPP
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace hal_EMULATOR_CPP {
#define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END }
// see "opencv2/core/private/cv_cpu_include_simd_declarations.hpp" // see "opencv2/core/private/cv_cpu_include_simd_declarations.hpp"
//#define CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY //#define CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
#define CV_FORCE_SIMD128_CPP #undef CV_FORCE_SIMD128_CPP
#define CV_FORCE_SIMD128_CPP 1
#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN #undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#undef CV_CPU_OPTIMIZATION_NAMESPACE_END #undef CV_CPU_OPTIMIZATION_NAMESPACE_END
#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace opt_EMULATOR_CPP { #define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace opt_EMULATOR_CPP {
#define CV_CPU_OPTIMIZATION_NAMESPACE_END } #define CV_CPU_OPTIMIZATION_NAMESPACE_END }
#include "test_intrin128.simd.hpp" #include "test_intrin128.simd.hpp"
#undef CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
#undef CV_CPU_OPTIMIZATION_NAMESPACE_END
#undef CV_CPU_DISPATCH_MODE
#undef CV_FORCE_SIMD128_CPP
// tests implementation is in test_intrin_utils.hpp // tests implementation is in test_intrin_utils.hpp
...@@ -222,7 +222,10 @@ template <typename R> std::ostream & operator<<(std::ostream & out, const Data<R ...@@ -222,7 +222,10 @@ template <typename R> std::ostream & operator<<(std::ostream & out, const Data<R
return out; return out;
} }
template<typename T> static inline void EXPECT_COMPARE_EQ_(const T a, const T b); template<typename T> static inline void EXPECT_COMPARE_EQ_(const T a, const T b)
{
EXPECT_EQ(a, b);
}
template<> inline void EXPECT_COMPARE_EQ_<float>(const float a, const float b) template<> inline void EXPECT_COMPARE_EQ_<float>(const float a, const float b)
{ {
EXPECT_FLOAT_EQ( a, b ); EXPECT_FLOAT_EQ( a, b );
...@@ -742,12 +745,12 @@ template<typename R> struct TheTest ...@@ -742,12 +745,12 @@ template<typename R> struct TheTest
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
SCOPED_TRACE(cv::format("i=%d", i)); SCOPED_TRACE(cv::format("i=%d", i));
EXPECT_EQ((double)dataA[i*2] * (double)dataA[i*2] + EXPECT_COMPARE_EQ((double)dataA[i*2] * (double)dataA[i*2] +
(double)dataA[i*2 + 1] * (double)dataA[i*2 + 1], resA[i]); (double)dataA[i*2 + 1] * (double)dataA[i*2 + 1], resA[i]);
EXPECT_EQ((double)dataB[i*2] * (double)dataB[i*2] + EXPECT_COMPARE_EQ((double)dataB[i*2] * (double)dataB[i*2] +
(double)dataB[i*2 + 1] * (double)dataB[i*2 + 1], resB[i]); (double)dataB[i*2 + 1] * (double)dataB[i*2 + 1], resB[i]);
EXPECT_EQ((double)dataA[i*2] * (double)dataB[i*2] + 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]); (double)dataA[i*2 + 1] * (double)dataB[i*2 + 1] + dataC[i], resC[i]);
} }
#endif #endif
return *this; return *this;
......
...@@ -303,7 +303,8 @@ int cornerScore<8>(const uchar* ptr, const int pixel[], int threshold) ...@@ -303,7 +303,8 @@ int cornerScore<8>(const uchar* ptr, const int pixel[], int threshold)
for (k = 0; k < N; k++) for (k = 0; k < N; k++)
d[k] = (short)(v - ptr[pixel[k]]); d[k] = (short)(v - ptr[pixel[k]]);
#if CV_SIMD128 #if CV_SIMD128 \
&& (!defined(CV_SIMD128_CPP) || (!defined(__GNUC__) || __GNUC__ != 5)) // "movdqa" bug on "v_load(d + 1)" line (Ubuntu 16.04 + GCC 5.4)
if (true) if (true)
{ {
v_int16x8 v0 = v_load(d + 1); v_int16x8 v0 = v_load(d + 1);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
#undef CV_FORCE_SIMD128_CPP // expected AVX implementation only
#include "opencv2/core/hal/intrin.hpp" #include "opencv2/core/hal/intrin.hpp"
#include "corner.hpp" #include "corner.hpp"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment