replace inline assembly WebRtcAecm_StoreAdaptiveChannelNeon by intrinsics.
The modification only uses the unique part of the StoreAdaptiveChannel
function. Pass byte to byte conformance test both on ARM32 and ARM64,
and the single function performance is similar with original assembly
version on different platforms. If not specified, the code is compiled
by GCC 4.6. The result is the "X version / C version" ratio, and the
less is better.
| run 100k times | cortex-a7 | cortex-a9 | cortex-a15 |
| use C as the base on each | (1.2Ghz) | (1.0Ghz) | (1.7Ghz) |
| CPU target | | | |
|----------------------------+-----------+-----------+------------|
| Neon asm | 20.97% | 37.70% | 25.41% |
| Neon inline | 36.93% | 51.80% | 38.14% |
| Neon intrinsics (GCC 4.6) | 27.78% | 43.71% | 26.50% |
| Neon intrinsics (GCC 4.8) | 27.16% | 38.22% | 26.87% |
| Neon intrinsics (LLVM 3.4) | 27.82% | 39.90% | 26.69% |
Change-Id: Ia55d8a268a70164b50676c604ae40b68fc183106
BUG=3580
R=andrew@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/30029004
Patch from Zhongwei Yao <zhongwei.yao@arm.com>.
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7685 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core_neon.c b/webrtc/modules/audio_processing/aecm/aecm_core_neon.c
index 7908ae5..48d63f7 100644
--- a/webrtc/modules/audio_processing/aecm/aecm_core_neon.c
+++ b/webrtc/modules/audio_processing/aecm/aecm_core_neon.c
@@ -298,27 +298,59 @@
void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore_t* aecm,
const uint16_t* far_spectrum,
int32_t* echo_est) {
- int i;
-
assert((uintptr_t)echo_est % 32 == 0);
assert((uintptr_t)(aecm->channelStored) % 16 == 0);
assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0);
+ // This is C code of following optimized code.
// During startup we store the channel every block.
- // Recalculate echo estimate.
- for (i = 0; i < PART_LEN - 7; i += 8) {
- // aecm->channelStored[i] = acem->channelAdapt16[i];
- // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
- __asm __volatile("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13");
- __asm __volatile("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12");
- __asm __volatile("vst1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12");
- __asm __volatile("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
- __asm __volatile("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
- __asm __volatile("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
- "r"(&echo_est[i]) : "q10", "q11");
+ // memcpy(aecm->channelStored,
+ // aecm->channelAdapt16,
+ // sizeof(int16_t) * PART_LEN1);
+ // Recalculate echo estimate
+ // for (i = 0; i < PART_LEN; i += 4) {
+ // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
+ // far_spectrum[i]);
+ // echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
+ // far_spectrum[i + 1]);
+ // echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
+ // far_spectrum[i + 2]);
+ // echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
+ // far_spectrum[i + 3]);
+ // }
+ // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
+ // far_spectrum[i]);
+ const uint16_t* far_spectrum_p = far_spectrum;
+ int16_t* start_adapt_p = aecm->channelAdapt16;
+ int16_t* start_stored_p = aecm->channelStored;
+ const int16_t* end_stored_p = aecm->channelStored + PART_LEN;
+ int32_t* echo_est_p = echo_est;
+
+ int16x8_t far_spectrum_v, adapt_v;
+ int32x4_t echo_est_v_low, echo_est_v_high;
+
+ while (start_stored_p < end_stored_p) {
+ far_spectrum_v = vld1q_u16(far_spectrum_p);
+ adapt_v = vld1q_s16(start_adapt_p);
+
+ vst1q_s16(start_stored_p, adapt_v);
+
+ echo_est_v_low = vmull_u16(vget_low_u16(far_spectrum_v),
+ vget_low_u16(adapt_v));
+ echo_est_v_high = vmull_u16(vget_high_u16(far_spectrum_v),
+ vget_high_u16(adapt_v));
+
+ vst1q_s32(echo_est_p, echo_est_v_low);
+ vst1q_s32(echo_est_p + 4, echo_est_v_high);
+
+ far_spectrum_p += 8;
+ start_adapt_p += 8;
+ start_stored_p += 8;
+ echo_est_p += 8;
}
- aecm->channelStored[i] = aecm->channelAdapt16[i];
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+ aecm->channelStored[PART_LEN] = aecm->channelAdapt16[PART_LEN];
+ echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN],
+ far_spectrum[PART_LEN]);
}
void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore_t* aecm) {