[opus] [PATCH] Optimize silk_LPC_analysis_filter() for ARM NEON
Linfeng Zhang
linfengz at google.com
Thu Jul 28 17:18:39 UTC 2016
Created corresponding unit test.
---
silk/LPC_analysis_filter.c | 8 +-
silk/SigProc_FIX.h | 8 +-
silk/arm/LPC_analysis_filter_arm.h | 60 +++++++
silk/arm/LPC_analysis_filter_neon_intr.c | 176 +++++++++++++++++++++
silk/arm/arm_silk_map.c | 14 ++
.../test_unit_optimization_LPC_analysis_filter.c | 85 ++++++++++
silk_headers.mk | 1 +
silk_sources.mk | 1 +
tests/test_unit_optimization.c | 2 +
9 files changed, 348 insertions(+), 7 deletions(-)
create mode 100644 silk/arm/LPC_analysis_filter_arm.h
create mode 100644 silk/arm/LPC_analysis_filter_neon_intr.c
create mode 100644 silk/tests/test_unit_optimization_LPC_analysis_filter.c
diff --git a/silk/LPC_analysis_filter.c b/silk/LPC_analysis_filter.c
index 20330d5..d3027f3 100644
--- a/silk/LPC_analysis_filter.c
+++ b/silk/LPC_analysis_filter.c
@@ -44,9 +44,8 @@ POSSIBILITY OF SUCH DAMAGE.
current implementation silences by casting to unsigned. Enabling
this should be safe in pretty much all cases, even though it is not technically
C89-compliant. */
-#define USE_CELT_FIR 0
-void silk_LPC_analysis_filter(
+void silk_LPC_analysis_filter_c(
opus_int16 *out, /* O Output signal */
const opus_int16 *in, /* I Input signal */
const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
@@ -74,9 +73,6 @@ void silk_LPC_analysis_filter(
num[ j ] = -B[ j ];
}
celt_fir( in + d, num, out + d, len - d, d, arch );
- for ( j = 0; j < d; j++ ) {
- out[ j ] = 0;
- }
#else
(void)arch;
for( ix = d; ix < len; ix++ ) {
@@ -104,8 +100,8 @@ void silk_LPC_analysis_filter(
/* Saturate output */
out[ ix ] = (opus_int16)silk_SAT16( out32 );
}
+#endif
/* Set first d output samples to zero */
silk_memset( out, 0, d * sizeof( opus_int16 ) );
-#endif
}
diff --git a/silk/SigProc_FIX.h b/silk/SigProc_FIX.h
index 72df6d3..0e619d0 100644
--- a/silk/SigProc_FIX.h
+++ b/silk/SigProc_FIX.h
@@ -35,6 +35,7 @@ extern "C"
/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */
+#define USE_CELT_FIR 0
#define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */
#include <string.h> /* for memset(), memcpy(), memmove() */
@@ -48,6 +49,7 @@ extern "C"
#endif
#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
+#include "arm/LPC_analysis_filter_arm.h"
#include "arm/LPC_inv_pred_gain_arm.h"
#endif
@@ -111,7 +113,7 @@ void silk_biquad_alt(
);
/* Variable order MA prediction error filter. */
-void silk_LPC_analysis_filter(
+void silk_LPC_analysis_filter_c(
opus_int16 *out, /* O Output signal */
const opus_int16 *in, /* I Input signal */
const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
@@ -156,6 +158,10 @@ void silk_ana_filt_bank_1(
const opus_int32 N /* I Number of input samples */
);
+#if !defined(OVERRIDE_SILK_LPC_ANALYSIS_FILTER)
+#define silk_LPC_analysis_filter(out, in, B, len, d, arch) (silk_LPC_analysis_filter_c(out, in, B, len, d, arch))
+#endif
+
#if !defined(OVERRIDE_silk_LPC_inverse_pred_gain)
#define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch),silk_LPC_inverse_pred_gain_c(A_Q12, order))
#endif
diff --git a/silk/arm/LPC_analysis_filter_arm.h b/silk/arm/LPC_analysis_filter_arm.h
new file mode 100644
index 0000000..96615d2
--- /dev/null
+++ b/silk/arm/LPC_analysis_filter_arm.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2016 Google Inc. */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(LPC_ANALYSIS_FILTER_ARM_H)
+# define LPC_ANALYSIS_FILTER_ARM_H
+
+# include "celt/arm/armcpu.h"
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+void silk_LPC_analysis_filter_neon(
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d, /* I Filter order */
+ int arch /* I Run-time architecture */
+);
+# endif
+
+# if !defined(OPUS_HAVE_RTCD)
+# define OVERRIDE_SILK_LPC_ANALYSIS_FILTER (1)
+# define silk_LPC_analysis_filter(out, in, B, len, d, arch) (PRESUME_NEON(silk_LPC_analysis_filter)(out, in, B, len, d, arch))
+# endif
+
+# if !defined(OVERRIDE_SILK_LPC_ANALYSIS_FILTER)
+/*Is run-time CPU detection enabled on this platform?*/
+# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
+extern void (*const SILK_LPC_ANALYSIS_FILTER_IMPL[OPUS_ARCHMASK+1])(opus_int16 *out, const opus_int16 *in, const opus_int16 *B, const opus_int32 len, const opus_int32 d, int arch);
+# define OVERRIDE_SILK_LPC_ANALYSIS_FILTER (1)
+# define silk_LPC_analysis_filter(out, in, B, len, d, arch) ((*SILK_LPC_ANALYSIS_FILTER_IMPL[(arch)&OPUS_ARCHMASK])(out, in, B, len, d, arch))
+# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
+# define OVERRIDE_SILK_LPC_ANALYSIS_FILTER (1)
+# define silk_LPC_analysis_filter(out, in, B, len, d, arch) (silk_LPC_analysis_filter_neon(out, in, B, len, d, arch))
+# endif
+# endif
+
+#endif /* end LPC_ANALYSIS_FILTER_ARM_H */
diff --git a/silk/arm/LPC_analysis_filter_neon_intr.c b/silk/arm/LPC_analysis_filter_neon_intr.c
new file mode 100644
index 0000000..56d26fb
--- /dev/null
+++ b/silk/arm/LPC_analysis_filter_neon_intr.c
@@ -0,0 +1,176 @@
+/* Copyright (c) 2016 Google Inc. */
+/**
+ @file celt_lpc_neon_intr.c
+ @brief ARM Neon Intrinsic optimizations for celt lpc functions
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <arm_neon.h>
+#include "SigProc_FIX.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+
+/*******************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first d output samples are set to zero */
+/*******************************************/
+
+/* OPT: Using celt_fir() for this function should be faster, but it may cause
+ integer overflows in intermediate values (not final results), which the
+ current implementation silences by casting to unsigned. Enabling
+ this should be safe in pretty much all cases, even though it is not technically
+ C89-compliant. */
+
+void silk_LPC_analysis_filter_neon(
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d, /* I Filter order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int j;
+#if USE_CELT_FIR
+ opus_int16 num[SILK_MAX_ORDER_LPC];
+#else
+ int ix;
+ const int leftover = (len - d) & 7;
+#endif
+
+ silk_assert( d >= 6 );
+ silk_assert( (d & 1) == 0 );
+ silk_assert( d <= len );
+
+#if USE_CELT_FIR
+ silk_assert( d <= SILK_MAX_ORDER_LPC );
+ for ( j = 0; j < d; j++ ) {
+ num[ j ] = -B[ j ];
+ }
+ celt_fir( in + d, num, out + d, len - d, d, arch );
+#else
+ VARDECL(opus_int16, rB);
+ (void)arch;
+ SAVE_STACK;
+
+ /* Extend rB by 3 zeros to handle the case that (d % 4) is non-zero. */
+ ALLOC(rB, d + 3, opus_int16);
+ for (ix = 0; ix < d - 3; ix += 4) {
+ vst1_s16(rB + ix, vrev64_s16(vld1_s16(B + d - ix - 4)));
+ }
+ for (; ix < d; ix++) {
+ rB[ix] = B[d - ix - 1];
+ }
+ rB[d] = rB[d + 1] = rB[d + 2] = 0;
+
+ for (ix = d; ix < len - 7; ix += 8) {
+ int16x8_t in_s16x8 = vld1q_s16(in + ix);
+ int32x4_t out32_Q12_0_s32x4 = vshll_n_s16(vget_low_s16 (in_s16x8), 12);
+ int32x4_t out32_Q12_1_s32x4 = vshll_n_s16(vget_high_s16(in_s16x8), 12);
+ for (j = 0; j < d; j += 4) {
+ const int16x4_t rB_s16x4 = vld1_s16(rB + j);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 0);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 0);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 0);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 1);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 1);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 1);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 2);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 2);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 2);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 3);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 3);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 3);
+ }
+ vst1q_s16(out + ix, vcombine_s16(vqrshrn_n_s32(out32_Q12_0_s32x4, 12), vqrshrn_n_s32(out32_Q12_1_s32x4, 12)));
+ }
+ if (leftover) {
+ if (leftover > 4) {
+ int16x8_t in_s16x8 = vld1q_s16(in + ix);
+ int32x4_t out32_Q12_0_s32x4 = vshll_n_s16(vget_low_s16 (in_s16x8), 12);
+ int32x4_t out32_Q12_1_s32x4 = vshll_n_s16(vget_high_s16(in_s16x8), 12);
+ for (j = 0; j < d; j += 4) {
+ const int16x4_t rB_s16x4 = vld1_s16(rB + j);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 0);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 0);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 0);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 1);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 1);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 1);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 2);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 2);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 2);
+ in_s16x8 = vld1q_s16(in - d + ix + j + 3);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vget_low_s16 (in_s16x8), rB_s16x4, 3);
+ out32_Q12_1_s32x4 = vmlsl_lane_s16(out32_Q12_1_s32x4, vget_high_s16(in_s16x8), rB_s16x4, 3);
+ }
+ const int16x8_t out_s16x8 = vcombine_s16(vqrshrn_n_s32(out32_Q12_0_s32x4, 12), vqrshrn_n_s32(out32_Q12_1_s32x4, 12));
+ vst1_s16 (out + ix, vget_low_s16(out_s16x8));
+ vst1q_lane_s16(out + ix + 4, out_s16x8, 4);
+ if (leftover >= 6) {
+ vst1q_lane_s16(out + ix + 5, out_s16x8, 5);
+ if (leftover == 7) {
+ vst1q_lane_s16(out + ix + 6, out_s16x8, 6);
+ }
+ }
+ }
+ else {
+ int32x4_t out32_Q12_0_s32x4 = vshll_n_s16(vld1_s16(in + ix), 12);
+ for (j = 0; j < d; j += 4) {
+ const int16x4_t rB_s16x4 = vld1_s16(rB + j);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vld1_s16(in - d + ix + j + 0), rB_s16x4, 0);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vld1_s16(in - d + ix + j + 1), rB_s16x4, 1);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vld1_s16(in - d + ix + j + 2), rB_s16x4, 2);
+ out32_Q12_0_s32x4 = vmlsl_lane_s16(out32_Q12_0_s32x4, vld1_s16(in - d + ix + j + 3), rB_s16x4, 3);
+ }
+ const int16x4_t out32_Q12_s16x4 = vqrshrn_n_s32(out32_Q12_0_s32x4, 12);
+ if (leftover == 4) {
+ vst1_s16(out + ix, out32_Q12_s16x4);
+ }
+ else {
+ vst1_lane_s16(out + ix, out32_Q12_s16x4, 0);
+ if (leftover >= 2) {
+ vst1_lane_s16(out + ix + 1, out32_Q12_s16x4, 1);
+ if (leftover == 3) {
+ vst1_lane_s16(out + ix + 2, out32_Q12_s16x4, 2);
+ }
+ }
+ }
+ }
+ }
+ RESTORE_STACK;
+#endif
+
+ /* Set first d output samples to zero */
+ silk_memset( out, 0, d * sizeof( opus_int16 ) );
+}
diff --git a/silk/arm/arm_silk_map.c b/silk/arm/arm_silk_map.c
index 59ceb6e..b1783c7 100644
--- a/silk/arm/arm_silk_map.c
+++ b/silk/arm/arm_silk_map.c
@@ -36,6 +36,20 @@ POSSIBILITY OF SUCH DAMAGE.
# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
+void (*const SILK_LPC_ANALYSIS_FILTER_IMPL[OPUS_ARCHMASK + 1])( /* O Returns inverse prediction gain in energy domain, Q30 */
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d, /* I Filter order */
+ int arch /* I Run-time architecture */
+) = {
+ silk_LPC_analysis_filter_c, /* ARMv4 */
+ silk_LPC_analysis_filter_c, /* EDSP */
+ silk_LPC_analysis_filter_c, /* Media */
+ MAY_HAVE_NEON(silk_LPC_analysis_filter), /* Neon */
+};
+
opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK + 1])( /* O Returns inverse prediction gain in energy domain, Q30 */
const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
const opus_int order /* I Prediction order */
diff --git a/silk/tests/test_unit_optimization_LPC_analysis_filter.c b/silk/tests/test_unit_optimization_LPC_analysis_filter.c
new file mode 100644
index 0000000..eae2daa
--- /dev/null
+++ b/silk/tests/test_unit_optimization_LPC_analysis_filter.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2016 Google Inc. */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "modes.h"
+#include "SigProc_FIX.h"
+
+#define MAX_ORDER 32
+
+static int test_silk_LPC_analysis_filter(int arch)
+{
+ opus_int16 out_org[MAX_PERIOD], out_opt[MAX_PERIOD]; /* O Output signal */
+ opus_int16 in[MAX_PERIOD + MAX_ORDER]; /* I Input signal */
+ opus_int16 B[MAX_ORDER]; /* I MA prediction coefficients, Q12 [order] */
+ opus_int32 len; /* I Signal length */
+ opus_int32 d; /* I Filter order */
+ unsigned int i;
+
+ printf("%44s() ...", __func__);
+ for(d=6;d<=MAX_ORDER;d+=2)
+ {
+ for(len=d;len<=MAX_PERIOD;len++) /* len is larger than or equal to d. */
+ {
+ for (i=0;i<MAX_PERIOD+MAX_ORDER;++i)
+ {
+ in[i] = (rand() % 32767) - 16384;
+ }
+ for (i=0;i<MAX_PERIOD;++i)
+ {
+ out_org[i] = (rand() % 32767) - 16384;
+ }
+ for (i=0;i<MAX_ORDER;++i)
+ {
+ B[i] = (rand() % 32767) - 16384;
+ }
+ memcpy(out_opt, out_org, sizeof(out_org));
+
+ silk_LPC_analysis_filter_c(out_org, in, B, len, d, arch);
+ silk_LPC_analysis_filter (out_opt, in, B, len, d, arch);
+ if (memcmp(out_org, out_opt, sizeof(out_org)))
+ {
+ printf("d=%2d len=%3d failed!\nError in lpc unit test!!!\n", d, len);
+ for (i=0;i<sizeof(out_org) / sizeof(*out_org);i++)
+ {
+ if (out_org[i] != out_opt[i])
+ {
+ printf("out_org[%3d]=%d, out_opt[%3d]=%d\n", i, out_org[i], i, out_opt[i]);
+ }
+ }
+ return -1;
+ }
+ }
+ }
+ printf(" passed!\n");
+ return 0;
+}
diff --git a/silk_headers.mk b/silk_headers.mk
index 10a169a..d3dce08 100644
--- a/silk_headers.mk
+++ b/silk_headers.mk
@@ -22,6 +22,7 @@ silk/resampler_rom.h \
silk/resampler_structs.h \
silk/SigProc_FIX.h \
silk/x86/SigProc_FIX_sse.h \
+silk/arm/LPC_analysis_filter_arm.h \
silk/arm/LPC_inv_pred_gain_arm.h \
silk/arm/macros_armv4.h \
silk/arm/macros_armv5e.h \
diff --git a/silk_sources.mk b/silk_sources.mk
index ac5647b..d2d5b35 100644
--- a/silk_sources.mk
+++ b/silk_sources.mk
@@ -85,6 +85,7 @@ silk/x86/VQ_WMat_EC_sse.c
SILK_SOURCES_ARM_NEON_INTR = \
silk/arm/arm_silk_map.c \
+silk/arm/LPC_analysis_filter_neon_intr.c \
silk/arm/LPC_inv_pred_gain_neon_intr.c \
silk/arm/NSQ_neon.c
diff --git a/tests/test_unit_optimization.c b/tests/test_unit_optimization.c
index 1e54caf..55425c4 100644
--- a/tests/test_unit_optimization.c
+++ b/tests/test_unit_optimization.c
@@ -45,6 +45,7 @@
#endif
+# include "silk/tests/test_unit_optimization_LPC_analysis_filter.c"
# include "silk/tests/test_unit_optimization_LPC_inv_pred_gain.c"
#define NUM_UNIT_TEST_LOOP 10
@@ -65,6 +66,7 @@ int main(void)
result |= test_silk_LPC_inverse_pred_gain_Q24(arch);
result |= test_warped_autocorrelation(arch);
#endif /* FIXED_POINT */
+ result |= test_silk_LPC_analysis_filter(arch);
result |= test_silk_LPC_inverse_pred_gain(arch);
}
return result;
--
2.8.0.rc3.226.g39d4020
More information about the opus
mailing list