fix NEON port, use vget_lane_*() instead of temporary variables (saves extra

load/store), following advice by  Josh Bleecher Snyder <josharian@gmail.com>.
Also implement pmadd() using vmla instead of nested padd/pmul.
This commit is contained in:
Konstantinos Margaritis 2012-07-04 11:12:02 +03:00
parent 9a97dac4d9
commit f737536744

View File

@ -252,15 +252,12 @@ template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vabsq_s
template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a) template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a)
{ {
float32x2_t a_lo, a_hi, sum; float32x2_t a_lo, a_hi, sum;
float s[2];
a_lo = vget_low_f32(a); a_lo = vget_low_f32(a);
a_hi = vget_high_f32(a); a_hi = vget_high_f32(a);
sum = vpadd_f32(a_lo, a_hi); sum = vpadd_f32(a_lo, a_hi);
sum = vpadd_f32(sum, sum); sum = vpadd_f32(sum, sum);
vst1_f32(s, sum); return vget_lane_f32(sum, 0);
return s[0];
} }
template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs) template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs)
@ -286,15 +283,12 @@ template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs)
template<> EIGEN_STRONG_INLINE int predux<Packet4i>(const Packet4i& a) template<> EIGEN_STRONG_INLINE int predux<Packet4i>(const Packet4i& a)
{ {
int32x2_t a_lo, a_hi, sum; int32x2_t a_lo, a_hi, sum;
int32_t s[2];
a_lo = vget_low_s32(a); a_lo = vget_low_s32(a);
a_hi = vget_high_s32(a); a_hi = vget_high_s32(a);
sum = vpadd_s32(a_lo, a_hi); sum = vpadd_s32(a_lo, a_hi);
sum = vpadd_s32(sum, sum); sum = vpadd_s32(sum, sum);
vst1_s32(s, sum); return vget_lane_s32(sum, 0);
return s[0];
} }
template<> EIGEN_STRONG_INLINE Packet4i preduxp<Packet4i>(const Packet4i* vecs) template<> EIGEN_STRONG_INLINE Packet4i preduxp<Packet4i>(const Packet4i* vecs)
@ -322,7 +316,6 @@ template<> EIGEN_STRONG_INLINE Packet4i preduxp<Packet4i>(const Packet4i* vecs)
template<> EIGEN_STRONG_INLINE float predux_mul<Packet4f>(const Packet4f& a) template<> EIGEN_STRONG_INLINE float predux_mul<Packet4f>(const Packet4f& a)
{ {
float32x2_t a_lo, a_hi, prod; float32x2_t a_lo, a_hi, prod;
float s[2];
// Get a_lo = |a1|a2| and a_hi = |a3|a4| // Get a_lo = |a1|a2| and a_hi = |a3|a4|
a_lo = vget_low_f32(a); a_lo = vget_low_f32(a);
@ -331,14 +324,12 @@ template<> EIGEN_STRONG_INLINE float predux_mul<Packet4f>(const Packet4f& a)
prod = vmul_f32(a_lo, a_hi); prod = vmul_f32(a_lo, a_hi);
// Multiply prod with its swapped value |a2*a4|a1*a3| // Multiply prod with its swapped value |a2*a4|a1*a3|
prod = vmul_f32(prod, vrev64_f32(prod)); prod = vmul_f32(prod, vrev64_f32(prod));
vst1_f32(s, prod);
return s[0]; return vget_lane_f32(prod, 0);
} }
template<> EIGEN_STRONG_INLINE int predux_mul<Packet4i>(const Packet4i& a) template<> EIGEN_STRONG_INLINE int predux_mul<Packet4i>(const Packet4i& a)
{ {
int32x2_t a_lo, a_hi, prod; int32x2_t a_lo, a_hi, prod;
int32_t s[2];
// Get a_lo = |a1|a2| and a_hi = |a3|a4| // Get a_lo = |a1|a2| and a_hi = |a3|a4|
a_lo = vget_low_s32(a); a_lo = vget_low_s32(a);
@ -347,29 +338,26 @@ template<> EIGEN_STRONG_INLINE int predux_mul<Packet4i>(const Packet4i& a)
prod = vmul_s32(a_lo, a_hi); prod = vmul_s32(a_lo, a_hi);
// Multiply prod with its swapped value |a2*a4|a1*a3| // Multiply prod with its swapped value |a2*a4|a1*a3|
prod = vmul_s32(prod, vrev64_s32(prod)); prod = vmul_s32(prod, vrev64_s32(prod));
vst1_s32(s, prod);
return s[0]; return vget_lane_s32(prod, 0);
} }
// min // min
template<> EIGEN_STRONG_INLINE float predux_min<Packet4f>(const Packet4f& a) template<> EIGEN_STRONG_INLINE float predux_min<Packet4f>(const Packet4f& a)
{ {
float32x2_t a_lo, a_hi, min; float32x2_t a_lo, a_hi, min;
float s[2];
a_lo = vget_low_f32(a); a_lo = vget_low_f32(a);
a_hi = vget_high_f32(a); a_hi = vget_high_f32(a);
min = vpmin_f32(a_lo, a_hi); min = vpmin_f32(a_lo, a_hi);
min = vpmin_f32(min, min); min = vpmin_f32(min, min);
vst1_f32(s, min);
return s[0]; return vget_lane_f32(min, 0);
} }
template<> EIGEN_STRONG_INLINE int predux_min<Packet4i>(const Packet4i& a) template<> EIGEN_STRONG_INLINE int predux_min<Packet4i>(const Packet4i& a)
{ {
int32x2_t a_lo, a_hi, min; int32x2_t a_lo, a_hi, min;
int32_t s[2];
a_lo = vget_low_s32(a); a_lo = vget_low_s32(a);
a_hi = vget_high_s32(a); a_hi = vget_high_s32(a);
@ -377,35 +365,31 @@ template<> EIGEN_STRONG_INLINE int predux_min<Packet4i>(const Packet4i& a)
min = vpmin_s32(min, min); min = vpmin_s32(min, min);
vst1_s32(s, min); vst1_s32(s, min);
return s[0]; return vget_lane_s32(min, 0);
} }
// max // max
template<> EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a) template<> EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a)
{ {
float32x2_t a_lo, a_hi, max; float32x2_t a_lo, a_hi, max;
float s[2];
a_lo = vget_low_f32(a); a_lo = vget_low_f32(a);
a_hi = vget_high_f32(a); a_hi = vget_high_f32(a);
max = vpmax_f32(a_lo, a_hi); max = vpmax_f32(a_lo, a_hi);
max = vpmax_f32(max, max); max = vpmax_f32(max, max);
vst1_f32(s, max);
return s[0]; return vget_lane_s32(max, 0);
} }
template<> EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a) template<> EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a)
{ {
int32x2_t a_lo, a_hi, max; int32x2_t a_lo, a_hi, max;
int32_t s[2];
a_lo = vget_low_s32(a); a_lo = vget_low_s32(a);
a_hi = vget_high_s32(a); a_hi = vget_high_s32(a);
max = vpmax_s32(a_lo, a_hi); max = vpmax_s32(a_lo, a_hi);
max = vpmax_s32(max, max);
vst1_s32(s, max);
return s[0]; return vget_lane_s32(max, 0);
} }
// this PALIGN_NEON business is to work around a bug in LLVM Clang 3.0 causing incorrect compilation errors, // this PALIGN_NEON business is to work around a bug in LLVM Clang 3.0 causing incorrect compilation errors,