// Copyright 2022 Google LLC | |
// | |
// This source code is licensed under the BSD-style license found in the | |
// LICENSE file in the root directory of this source tree. | |
#include <xnnpack/assembly.h> | |
.syntax unified | |
// void xnn_cs16_fftr_ukernel__asm_aarch32_neon_x4( | |
// size_t samples, r0 (256) | |
// int16_t* data, r1 | |
// const int16_t* twiddle) r2 | |
// d8-d15, r12-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. | |
// Register usage | |
// vilr r1 d0 | |
// vili d1 | |
// virr r3 d2 | |
// viri d3 | |
// vdiv2 d4 | |
// vtwr r2 d6 | |
// vtwi d7 | |
// vacc1r q8 = vilr + virr; | |
// vacc1i q9 = vili + viri; | |
// vacc2r d0 = vilr - virr; | |
// vacc2i d1 = vili - viri; | |
// vaccr q10 (d20/d21) | |
// vacci q11 (d22/d23) | |
// voutlr q12 (vaccr + vacc1r) / 2 | |
// voutli q13 (vacci + vacc1i) / 2 | |
// voutrr q14 (vacc1r - vaccr) / 2 | |
// voutri q15 (vacci - vacc1i) / 2 | |
// unused d5, d8-d15 | |
BEGIN_FUNCTION xnn_cs16_fftr_ukernel__asm_aarch32_neon_x4 | |
#ifndef __APPLE__ | |
.arch armv7-a | |
.fpu neon | |
#endif | |
ADD r3, r1, r0, lsl #2 // dr = data + samples * 4 | |
VMOV.U16 q0, 0 | |
VMVN.U16 d4, 49152 // 16383 | |
VLD2.16 {d0[0],d1[0]}, [r1] // first value | |
VQRDMULH.S16 q0, q0, d4[0] // vilr /= 2 | |
VADD.I16 d16, d0, d1 // dl[0] = vicr + vici; | |
VSUB.I16 d18, d0, d1 // dr[0] = vicr - vici; | |
VST1.32 {d16[0]}, [r1]! | |
VST1.32 {d18[0]}, [r3] | |
// Main loop of 4 cs16 value at a time | |
0: | |
SUB r3, r3, 16 // dr -= 16 | |
VLD2.16 {d0,d1}, [r1] // load left r and i | |
VLD2.16 {d2,d3}, [r3] // load right r and i | |
VLD2.16 {d6,d7}, [r2]! // load twiddle values vtwr, vtwi | |
VREV64.16 q1, q1 // reverse right side | |
VQRDMULH.S16 q0, q0, d4[0] // vilr /= 2 | |
VQRDMULH.S16 q1, q1, d4[0] // virr /= 2 | |
VADDL.S16 q8, d0, d2 // vacc1r = vilr + virr; | |
VSUBL.S16 q9, d1, d3 // vacc1i = vili - viri; | |
VSUB.I16 d0, d0, d2 // vacc2r = vilr - virr; | |
VADD.I16 d1, d1, d3 // vacc2i = vili + viri; | |
VMULL.S16 q10, d0, d6 // vaccr = vacc2r * vtwr | |
VMULL.S16 q11, d0, d7 // vacci = vacc2r * vtwi | |
VMLSL.S16 q10, d1, d7 // vaccr -= vacc2i * vtwi | |
VMLAL.S16 q11, d1, d6 // vacci += vacc2i * vtwr | |
VRSHR.S32 q10, q10, 15 // (vaccr + 16384) >> 15 | |
VRSHR.S32 q11, q11, 15 // (vacci + 16384) >> 15 | |
VHADD.S32 q12, q10, q8 // (vaccr + vacc1r) / 2 | |
VHADD.S32 q13, q11, q9 // (vacci + vacc1i) / 2 | |
VHSUB.S32 q14, q8, q10 // (vacc1r - vaccr) / 2 | |
VHSUB.S32 q15, q11, q9 // (vacci - vacc1i) / 2 | |
VMOVN.S32 d0, q12 | |
VMOVN.S32 d1, q13 | |
VMOVN.S32 d2, q14 | |
VMOVN.S32 d3, q15 | |
SUBS r0, r0, 8 // 8 samples (left and right) per loop | |
VREV64.16 q1, q1 // reverse right side | |
VST2.16 {d0,d1}, [r1]! // store left r and i | |
VST2.16 {d2,d3}, [r3] // store right r and i | |
BHI 0b | |
BX lr | |
END_FUNCTION xnn_cs16_fftr_ukernel__asm_aarch32_neon_x4 | |
#ifdef __ELF__ | |
.section ".note.GNU-stack","",%progbits | |
#endif | |