[opus] [Aarch64 09/11] Add Neon intrinsics for Silk noise shape feedback loop.
Jonathan Lennox
jonathan at vidyo.com
Fri Nov 6 18:05:31 PST 2015
---
silk/NSQ.c | 18 ++-------------
silk/NSQ.h | 27 ++++++++++++++++++++++
silk/arm/NSQ_neon.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
silk/arm/NSQ_neon.h | 10 ++++++++
4 files changed, 105 insertions(+), 16 deletions(-)
diff --git a/silk/NSQ.c b/silk/NSQ.c
index d8513dc..ec81f3b 100644
--- a/silk/NSQ.c
+++ b/silk/NSQ.c
@@ -205,7 +205,7 @@ void silk_noise_shape_quantizer(
int arch /* I Architecture */
)
{
- opus_int i, j;
+ opus_int i;
opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
@@ -248,21 +248,7 @@ void silk_noise_shape_quantizer(
/* Noise shape feedback */
silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
- tmp2 = psLPC_Q14[ 0 ];
- tmp1 = NSQ->sAR2_Q14[ 0 ];
- NSQ->sAR2_Q14[ 0 ] = tmp2;
- n_AR_Q12 = silk_RSHIFT( shapingLPCOrder, 1 );
- n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ 0 ] );
- for( j = 2; j < shapingLPCOrder; j += 2 ) {
- tmp2 = NSQ->sAR2_Q14[ j - 1 ];
- NSQ->sAR2_Q14[ j - 1 ] = tmp1;
- n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ j - 1 ] );
- tmp1 = NSQ->sAR2_Q14[ j + 0 ];
- NSQ->sAR2_Q14[ j + 0 ] = tmp2;
- n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ j ] );
- }
- NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
- n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+ n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(psLPC_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch);
n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
diff --git a/silk/NSQ.h b/silk/NSQ.h
index a18a951..df856e6 100644
--- a/silk/NSQ.h
+++ b/silk/NSQ.h
@@ -62,6 +62,33 @@ static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(cons
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
+static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
+{
+ opus_int32 out;
+ opus_int32 tmp1, tmp2;
+ opus_int j;
+
+ tmp2 = data0[0];
+ tmp1 = data1[0];
+ data1[0] = tmp2;
+
+ out = silk_RSHIFT(order, 1);
+ out = silk_SMLAWB(out, tmp2, coef[0]);
+
+ for (j = 2; j < order; j += 2) {
+ tmp2 = data1[j - 1];
+ data1[j - 1] = tmp1;
+ out = silk_SMLAWB(out, tmp1, coef[j - 1]);
+ tmp1 = data1[j + 0];
+ data1[j + 0] = tmp2;
+ out = silk_SMLAWB(out, tmp2, coef[j]);
+ }
+ data1[order - 1] = tmp1;
+ out = silk_SMLAWB(out, tmp1, coef[order - 1]);
+ return out;
+}
+
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order))
#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
#include "arm/NSQ_neon.h"
diff --git a/silk/arm/NSQ_neon.c b/silk/arm/NSQ_neon.c
index 96b672d..fb858f3 100644
--- a/silk/arm/NSQ_neon.c
+++ b/silk/arm/NSQ_neon.c
@@ -62,3 +62,69 @@ opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *bu
opus_int32 out = vget_lane_s32(d, 0);
return out;
}
+
+
+opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
+{
+ opus_int32 out;
+ if (order == 8)
+ {
+ int32x4_t a00 = vdupq_n_s32(data0[0]);
+ int32x4_t a01 = vld1q_s32(data1); // data1[0] ... [3]
+
+ int32x4_t a0 = vextq_s32 (a00, a01, 3); // data0[0] data1[0] ...[2]
+ int32x4_t a1 = vld1q_s32(data1 + 3); // data1[3] ... [6]
+
+ int16x8_t coef16 = vld1q_s16(coef);
+ int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16));
+ int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16));
+
+ int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0));
+ int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0));
+ int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1));
+ int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1));
+
+ int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3));
+ int64x1_t cS = vshr_n_s64(c, 16);
+ int32x2_t d = vreinterpret_s32_s64(cS);
+
+ out = vget_lane_s32(d, 0);
+ vst1q_s32(data1, a0);
+ vst1q_s32(data1 + 4, a1);
+ }
+ else
+ {
+ opus_int32 tmp1, tmp2;
+ opus_int j;
+
+ tmp2 = data0[0];
+ tmp1 = data1[0];
+ data1[0] = tmp2;
+
+ out = silk_RSHIFT(order, 1);
+ out = silk_SMLAWB(out, tmp2, coef[0]);
+
+ for (j = 2; j < order; j += 2) {
+ tmp2 = data1[j - 1];
+ data1[j - 1] = tmp1;
+ out = silk_SMLAWB(out, tmp1, coef[j - 1]);
+ tmp1 = data1[j + 0];
+ data1[j + 0] = tmp2;
+ out = silk_SMLAWB(out, tmp2, coef[j]);
+ }
+ data1[order - 1] = tmp1;
+ out = silk_SMLAWB(out, tmp1, coef[order - 1]);
+ }
+ return out;
+}
+
+#if !defined(OPUS_ARM_PRESUME_NEON_INTR) && defined(OPUS_HAVE_RTCD)
+
+opus_int32 (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_NEON_IMPL[OPUS_ARCHMASK+1])(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) = {
+ silk_NSQ_noise_shape_feedback_loop_c,
+ silk_NSQ_noise_shape_feedback_loop_c,
+ silk_NSQ_noise_shape_feedback_loop_c,
+ silk_NSQ_noise_shape_feedback_loop_neon,
+};
+
+#endif
diff --git a/silk/arm/NSQ_neon.h b/silk/arm/NSQ_neon.h
index 8e67cb9..24db2a6 100644
--- a/silk/arm/NSQ_neon.h
+++ b/silk/arm/NSQ_neon.h
@@ -74,10 +74,15 @@ static OPUS_INLINE void optional_coef_reversal_neon(opus_int32 *out, const opus_
opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32);
+opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order);
+
#if OPUS_ARM_PRESUME_NEON_INTR
#undef silk_noise_shape_quantizer_short_prediction
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev))
+#undef silk_NSQ_noise_shape_feedback_loop
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order))
+
#elif OPUS_HAVE_RTCD
/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch
@@ -85,6 +90,11 @@ opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *bu
#undef silk_noise_shape_quantizer_short_prediction
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) (arch == 3 ? silk_noise_shape_quantizer_short_prediction_neon(in, coefRev) : silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
+extern opus_int32 (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_NEON_IMPL[OPUS_ARCHMASK+1])(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order);
+
+#undef silk_NSQ_noise_shape_feedback_loop
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) (SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_NEON_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, coef, order))
+
#endif
--
2.4.9 (Apple Git-60)
More information about the opus
mailing list