Skip to content

Commit 7f1c6fa

Browse files
Jonathan LennoxTimothy B. Terriberry
authored andcommitted
Add Neon intrinsics for Silk noise shape feedback loop.
Signed-off-by: Timothy B. Terriberry <[email protected]>
1 parent 81a1942 commit 7f1c6fa

File tree

6 files changed

+148
-18
lines changed

6 files changed

+148
-18
lines changed

silk/NSQ.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ void silk_noise_shape_quantizer(
205205
int arch /* I Architecture */
206206
)
207207
{
208-
opus_int i, j;
208+
opus_int i;
209209
opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
210210
opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
211211
opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
@@ -250,23 +250,8 @@ void silk_noise_shape_quantizer(
250250

251251
/* Noise shape feedback */
252252
silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
253-
tmp2 = psLPC_Q14[ 0 ];
254-
tmp1 = NSQ->sAR2_Q14[ 0 ];
255-
NSQ->sAR2_Q14[ 0 ] = tmp2;
256-
n_AR_Q12 = silk_RSHIFT( shapingLPCOrder, 1 );
257-
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ 0 ] );
258-
for( j = 2; j < shapingLPCOrder; j += 2 ) {
259-
tmp2 = NSQ->sAR2_Q14[ j - 1 ];
260-
NSQ->sAR2_Q14[ j - 1 ] = tmp1;
261-
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ j - 1 ] );
262-
tmp1 = NSQ->sAR2_Q14[ j + 0 ];
263-
NSQ->sAR2_Q14[ j + 0 ] = tmp2;
264-
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ j ] );
265-
}
266-
NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
267-
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
253+
n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(psLPC_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch);
268254

269-
n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */
270255
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
271256

272257
n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );

silk/NSQ.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,35 @@ static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(cons
6464

6565
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
6666

67+
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)
68+
{
69+
opus_int32 out;
70+
opus_int32 tmp1, tmp2;
71+
opus_int j;
72+
73+
tmp2 = data0[0];
74+
tmp1 = data1[0];
75+
data1[0] = tmp2;
76+
77+
out = silk_RSHIFT(order, 1);
78+
out = silk_SMLAWB(out, tmp2, coef[0]);
79+
80+
for (j = 2; j < order; j += 2) {
81+
tmp2 = data1[j - 1];
82+
data1[j - 1] = tmp1;
83+
out = silk_SMLAWB(out, tmp1, coef[j - 1]);
84+
tmp1 = data1[j + 0];
85+
data1[j + 0] = tmp2;
86+
out = silk_SMLAWB(out, tmp2, coef[j]);
87+
}
88+
data1[order - 1] = tmp1;
89+
out = silk_SMLAWB(out, tmp1, coef[order - 1]);
90+
/* Q11 -> Q12 */
91+
out = silk_LSHIFT32( out, 1 );
92+
return out;
93+
}
94+
95+
#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))
6796

6897
#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
6998
#include "arm/NSQ_neon.h"

silk/arm/NSQ_neon.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,46 @@ opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *bu
6767

6868
return out;
6969
}
70+
71+
72+
opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
73+
{
74+
opus_int32 out;
75+
if (order == 8)
76+
{
77+
int32x4_t a00 = vdupq_n_s32(data0[0]);
78+
int32x4_t a01 = vld1q_s32(data1); /* data1[0] ... [3] */
79+
80+
int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */
81+
int32x4_t a1 = vld1q_s32(data1 + 3); /* data1[3] ... [6] */
82+
83+
/*TODO: Convert these once in advance instead of once per sample, like
84+
silk_noise_shape_quantizer_short_prediction_neon() does.*/
85+
int16x8_t coef16 = vld1q_s16(coef);
86+
int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16));
87+
int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16));
88+
89+
/*This is not bit-exact with the C version, since we do not drop the
90+
lower 16 bits of each multiply, but wait until the end to truncate
91+
precision. This is an encoder-specific calculation (and unlike
92+
silk_noise_shape_quantizer_short_prediction_neon(), is not meant to
93+
simulate what the decoder will do). We still could use vqdmulhq_s32()
94+
like silk_noise_shape_quantizer_short_prediction_neon() and save
95+
half the multiplies, but the speed difference is not large, since we
96+
then need two extra adds.*/
97+
int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0));
98+
int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0));
99+
int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1));
100+
int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1));
101+
102+
int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3));
103+
int64x1_t cS = vrshr_n_s64(c, 15);
104+
int32x2_t d = vreinterpret_s32_s64(cS);
105+
106+
out = vget_lane_s32(d, 0);
107+
vst1q_s32(data1, a0);
108+
vst1q_s32(data1 + 4, a1);
109+
return out;
110+
}
111+
return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order);
112+
}

silk/arm/NSQ_neon.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ POSSIBILITY OF SUCH DAMAGE.
2727
#ifndef SILK_NSQ_NEON_H
2828
#define SILK_NSQ_NEON_H
2929

30+
#include "cpu_support.h"
31+
3032
#undef silk_short_prediction_create_arch_coef
3133
/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */
3234
static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order)
@@ -76,11 +78,16 @@ static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *
7678

7779
opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order);
7880

81+
opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order);
82+
7983
#if defined(OPUS_ARM_PRESUME_NEON_INTR)
8084
#undef silk_noise_shape_quantizer_short_prediction
8185
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \
8286
((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order))
8387

88+
#undef silk_NSQ_noise_shape_feedback_loop
89+
#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))
90+
8491
#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
8592

8693
/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch
@@ -91,6 +98,15 @@ opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *bu
9198
silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \
9299
silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
93100

101+
extern opus_int32
102+
(*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
103+
const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
104+
opus_int order);
105+
106+
#undef silk_NSQ_noise_shape_feedback_loop
107+
#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \
108+
(SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \
109+
coef, order))
94110

95111
#endif
96112

silk/arm/arm_silk_map.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/***********************************************************************
2+
Copyright (C) 2014 Vidyo
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions
5+
are met:
6+
- Redistributions of source code must retain the above copyright notice,
7+
this list of conditions and the following disclaimer.
8+
- Redistributions in binary form must reproduce the above copyright
9+
notice, this list of conditions and the following disclaimer in the
10+
documentation and/or other materials provided with the distribution.
11+
- Neither the name of Internet Society, IETF or IETF Trust, nor the
12+
names of specific contributors, may be used to endorse or promote
13+
products derived from this software without specific prior written
14+
permission.
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25+
POSSIBILITY OF SUCH DAMAGE.
26+
***********************************************************************/
27+
#ifdef HAVE_CONFIG_H
28+
# include "config.h"
29+
#endif
30+
31+
#include "NSQ.h"
32+
33+
#if defined(OPUS_HAVE_RTCD)
34+
35+
# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \
36+
!defined(OPUS_ARM_PRESUME_NEON_INTR))
37+
38+
/*There is no table for silk_noise_shape_quantizer_short_prediction because the
39+
NEON version takes different parameters than the C version.
40+
Instead RTCD is done via if statements at the call sites.
41+
See NSQ_neon.h for details.*/
42+
43+
opus_int32
44+
(*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
45+
const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
46+
opus_int order) = {
47+
silk_NSQ_noise_shape_feedback_loop_c, /* ARMv4 */
48+
silk_NSQ_noise_shape_feedback_loop_c, /* EDSP */
49+
silk_NSQ_noise_shape_feedback_loop_c, /* Media */
50+
silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */
51+
};
52+
53+
# endif
54+
55+
#endif /* OPUS_HAVE_RTCD */

silk_sources.mk

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ silk/x86/x86_silk_map.c \
8282
silk/x86/VAD_sse.c \
8383
silk/x86/VQ_WMat_EC_sse.c
8484

85-
SILK_SOURCES_ARM_NEON_INTR = silk/arm/NSQ_neon.c
85+
SILK_SOURCES_ARM_NEON_INTR = \
86+
silk/arm/arm_silk_map.c \
87+
silk/arm/NSQ_neon.c
8688

8789
SILK_SOURCES_FIXED = \
8890
silk/fixed/LTP_analysis_filter_FIX.c \

0 commit comments

Comments
 (0)