float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) { // CHECK-LABEL: test_vzipq_f32 return vzipq_f32(a, b); // CHECK: zip1 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s // CHECK: zip2 {{v[0-9]+}}.4s, {{v[0-9]+}}.4s }
static void FilterAdaptationNEON( int num_partitions, int x_fft_buf_block_pos, float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1], float e_fft[2][PART_LEN1], float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) { float fft[PART_LEN2]; int i; for (i = 0; i < num_partitions; i++) { int xPos = (i + x_fft_buf_block_pos) * PART_LEN1; int pos = i * PART_LEN1; int j; // Check for wrap if (i + x_fft_buf_block_pos >= num_partitions) { xPos -= num_partitions * PART_LEN1; } // Process the whole array... for (j = 0; j < PART_LEN; j += 4) { // Load x_fft_buf and e_fft. const float32x4_t x_fft_buf_re = vld1q_f32(&x_fft_buf[0][xPos + j]); const float32x4_t x_fft_buf_im = vld1q_f32(&x_fft_buf[1][xPos + j]); const float32x4_t e_fft_re = vld1q_f32(&e_fft[0][j]); const float32x4_t e_fft_im = vld1q_f32(&e_fft[1][j]); // Calculate the product of conjugate(x_fft_buf) by e_fft. // re(conjugate(a) * b) = aRe * bRe + aIm * bIm // im(conjugate(a) * b)= aRe * bIm - aIm * bRe const float32x4_t a = vmulq_f32(x_fft_buf_re, e_fft_re); const float32x4_t e = vmlaq_f32(a, x_fft_buf_im, e_fft_im); const float32x4_t c = vmulq_f32(x_fft_buf_re, e_fft_im); const float32x4_t f = vmlsq_f32(c, x_fft_buf_im, e_fft_re); // Interleave real and imaginary parts. const float32x4x2_t g_n_h = vzipq_f32(e, f); // Store vst1q_f32(&fft[2 * j + 0], g_n_h.val[0]); vst1q_f32(&fft[2 * j + 4], g_n_h.val[1]); } // ... and fixup the first imaginary entry. fft[1] = MulRe(x_fft_buf[0][xPos + PART_LEN], -x_fft_buf[1][xPos + PART_LEN], e_fft[0][PART_LEN], e_fft[1][PART_LEN]); aec_rdft_inverse_128(fft); memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN); // fft scaling { const float scale = 2.0f / PART_LEN2; const float32x4_t scale_ps = vmovq_n_f32(scale); for (j = 0; j < PART_LEN; j += 4) { const float32x4_t fft_ps = vld1q_f32(&fft[j]); const float32x4_t fft_scale = vmulq_f32(fft_ps, scale_ps); vst1q_f32(&fft[j], fft_scale); } } aec_rdft_forward_128(fft); { const float wt1 = h_fft_buf[1][pos]; h_fft_buf[0][pos + PART_LEN] += fft[1]; for (j = 0; j < PART_LEN; j += 4) { float32x4_t wtBuf_re = vld1q_f32(&h_fft_buf[0][pos + j]); float32x4_t wtBuf_im = vld1q_f32(&h_fft_buf[1][pos + j]); const float32x4_t fft0 = vld1q_f32(&fft[2 * j + 0]); const float32x4_t fft4 = vld1q_f32(&fft[2 * j + 4]); const float32x4x2_t fft_re_im = vuzpq_f32(fft0, fft4); wtBuf_re = vaddq_f32(wtBuf_re, fft_re_im.val[0]); wtBuf_im = vaddq_f32(wtBuf_im, fft_re_im.val[1]); vst1q_f32(&h_fft_buf[0][pos + j], wtBuf_re); vst1q_f32(&h_fft_buf[1][pos + j], wtBuf_im); } h_fft_buf[1][pos] = wt1; } } }
static void rftbsub_128_neon(float* a) { const float* c = rdft_w + 32; int j1, j2; const float32x4_t mm_half = vdupq_n_f32(0.5f); a[1] = -a[1]; // Vectorized code (four at once). // Note: commented number are indexes for the first iteration of the loop. for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { // Load 'wk'. const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4, const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31, const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31, const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28, const float32x4_t wki_ = c_j1; // 1, 2, 3, 4, // Load and shuffle 'a'. // 2, 4, 6, 8, 3, 5, 7, 9 float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]); // 120, 122, 124, 126, 121, 123, 125, 127, const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]); // 126, 124, 122, 120 const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]); // 127, 125, 123, 121 const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]); // Calculate 'x'. const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0); // 2-126, 4-124, 6-122, 8-120, const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1); // 3-127, 5-125, 7-123, 9-121, // Calculate product into 'y'. // yr = wkr * xr - wki * xi; // yi = wkr * xi + wki * xr; const float32x4_t a_ = vmulq_f32(wkr_, xr_); const float32x4_t b_ = vmulq_f32(wki_, xi_); const float32x4_t c_ = vmulq_f32(wkr_, xi_); const float32x4_t d_ = vmulq_f32(wki_, xr_); const float32x4_t yr_ = vaddq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120, const float32x4_t yi_ = vsubq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121, // Update 'a'. // a[j2 + 0] -= yr; // a[j2 + 1] -= yi; // a[k2 + 0] += yr; // a[k2 + 1] -= yi; // 126, 124, 122, 120, const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_); // 127, 125, 123, 121, const float32x4_t a_k2_p1n = vsubq_f32(yi_, a_k2_p1); // Shuffle in right order and store. // 2, 3, 4, 5, 6, 7, 8, 9, const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n); const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n); // 124, 125, 126, 127, 120, 121, 122, 123 const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr); // 2, 4, 6, 8, a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_); // 3, 5, 7, 9, a_j2_p.val[1] = vsubq_f32(yi_, a_j2_p.val[1]); // 2, 3, 4, 5, 6, 7, 8, 9, vst2q_f32(&a[0 + j2], a_j2_p); vst1q_f32(&a[122 - j2], a_k2_n.val[1]); vst1q_f32(&a[126 - j2], a_k2_n.val[0]); } // Scalar code for the remaining items. for (; j2 < 64; j1 += 1, j2 += 2) { const int k2 = 128 - j2; const int k1 = 32 - j1; const float wkr = 0.5f - c[k1]; const float wki = c[j1]; const float xr = a[j2 + 0] - a[k2 + 0]; const float xi = a[j2 + 1] + a[k2 + 1]; const float yr = wkr * xr + wki * xi; const float yi = wkr * xi - wki * xr; a[j2 + 0] = a[j2 + 0] - yr; a[j2 + 1] = yi - a[j2 + 1]; a[k2 + 0] = yr + a[k2 + 0]; a[k2 + 1] = yi - a[k2 + 1]; } a[65] = -a[65]; }
static void ne10_fft16_backward_float32_neon (ne10_fft_cpx_float32_t * Fout, ne10_fft_cpx_float32_t * Fin, ne10_fft_cpx_float32_t * twiddles) { ne10_fft_cpx_float32_t *tw1, *tw2, *tw3; // the first stage float32_t *p_src0, *p_src4, *p_src8, *p_src12; float32x4x2_t q2_in_0123, q2_in_4567, q2_in_89ab, q2_in_cdef; float32x4_t q_t0_r, q_t0_i, q_t1_r, q_t1_i, q_t2_r, q_t2_i, q_t3_r, q_t3_i; float32x4_t q_out_r048c, q_out_i048c, q_out_r159d, q_out_i159d; float32x4_t q_out_r26ae, q_out_i26ae, q_out_r37bf, q_out_i37bf; p_src0 = (float32_t*) (& (Fin[0])); p_src4 = (float32_t*) (& (Fin[4])); p_src8 = (float32_t*) (& (Fin[8])); p_src12 = (float32_t*) (& (Fin[12])); q2_in_0123 = vld2q_f32 (p_src0); q2_in_4567 = vld2q_f32 (p_src4); q2_in_89ab = vld2q_f32 (p_src8); q2_in_cdef = vld2q_f32 (p_src12); q_t2_r = vsubq_f32 (q2_in_0123.val[0], q2_in_89ab.val[0]); q_t2_i = vsubq_f32 (q2_in_0123.val[1], q2_in_89ab.val[1]); q_t3_r = vaddq_f32 (q2_in_0123.val[0], q2_in_89ab.val[0]); q_t3_i = vaddq_f32 (q2_in_0123.val[1], q2_in_89ab.val[1]); q_t0_r = vaddq_f32 (q2_in_4567.val[0], q2_in_cdef.val[0]); q_t0_i = vaddq_f32 (q2_in_4567.val[1], q2_in_cdef.val[1]); q_t1_r = vsubq_f32 (q2_in_4567.val[0], q2_in_cdef.val[0]); q_t1_i = vsubq_f32 (q2_in_4567.val[1], q2_in_cdef.val[1]); q_out_r26ae = vsubq_f32 (q_t3_r, q_t0_r); q_out_i26ae = vsubq_f32 (q_t3_i, q_t0_i); q_out_r048c = vaddq_f32 (q_t3_r, q_t0_r); q_out_i048c = vaddq_f32 (q_t3_i, q_t0_i); q_out_r159d = vsubq_f32 (q_t2_r, q_t1_i); q_out_i159d = vaddq_f32 (q_t2_i, q_t1_r); q_out_r37bf = vaddq_f32 (q_t2_r, q_t1_i); q_out_i37bf = vsubq_f32 (q_t2_i, q_t1_r); // second stages float32_t *p_dst0, *p_dst1, *p_dst2, *p_dst3; float32_t *p_tw1, *p_tw2, *p_tw3; float32x4_t q_s0_r, q_s0_i, q_s1_r, q_s1_i, q_s2_r, q_s2_i; float32x4_t q_s3_r, q_s3_i, q_s4_r, q_s4_i, q_s5_r, q_s5_i; float32x4x2_t q2_tmp_0, q2_tmp_1, q2_tmp_2, q2_tmp_3; float32x4_t q_in_r0123, q_in_r4567, q_in_r89ab, q_in_rcdef; float32x4_t q_in_i0123, q_in_i4567, q_in_i89ab, q_in_icdef; float32x4x2_t q2_tw1, q2_tw2, q2_tw3; float32x4x2_t q2_out_0123, q2_out_4567, q2_out_89ab, q2_out_cdef; float32x4_t q_one_by_nfft; tw1 = twiddles; tw2 = twiddles + 4; tw3 = twiddles + 8; p_dst0 = (float32_t*) (&Fout[0]); p_dst1 = (float32_t*) (&Fout[4]); p_dst2 = (float32_t*) (&Fout[8]); p_dst3 = (float32_t*) (&Fout[12]); p_tw1 = (float32_t*) tw1; p_tw2 = (float32_t*) tw2; p_tw3 = (float32_t*) tw3; q2_tmp_0 = vzipq_f32 (q_out_r048c, q_out_r159d); q2_tmp_1 = vzipq_f32 (q_out_i048c, q_out_i159d); q2_tmp_2 = vzipq_f32 (q_out_r26ae, q_out_r37bf); q2_tmp_3 = vzipq_f32 (q_out_i26ae, q_out_i37bf); q_in_r0123 = vcombine_f32 (vget_low_f32 (q2_tmp_0.val[0]), vget_low_f32 (q2_tmp_2.val[0])); q_in_i0123 = vcombine_f32 (vget_low_f32 (q2_tmp_1.val[0]), vget_low_f32 (q2_tmp_3.val[0])); q_in_r4567 = vcombine_f32 (vget_high_f32 (q2_tmp_0.val[0]), vget_high_f32 (q2_tmp_2.val[0])); q_in_i4567 = vcombine_f32 (vget_high_f32 (q2_tmp_1.val[0]), vget_high_f32 (q2_tmp_3.val[0])); q_in_r89ab = vcombine_f32 (vget_low_f32 (q2_tmp_0.val[1]), vget_low_f32 (q2_tmp_2.val[1])); q_in_i89ab = vcombine_f32 (vget_low_f32 (q2_tmp_1.val[1]), vget_low_f32 (q2_tmp_3.val[1])); q_in_rcdef = vcombine_f32 (vget_high_f32 (q2_tmp_0.val[1]), vget_high_f32 (q2_tmp_2.val[1])); q_in_icdef = vcombine_f32 (vget_high_f32 (q2_tmp_1.val[1]), vget_high_f32 (q2_tmp_3.val[1])); q2_tw1 = vld2q_f32 (p_tw1); q2_tw2 = vld2q_f32 (p_tw2); q2_tw3 = vld2q_f32 (p_tw3); q_s0_r = vmulq_f32 (q_in_r4567, q2_tw1.val[0]); q_s0_i = vmulq_f32 (q_in_i4567, q2_tw1.val[0]); q_s1_r = vmulq_f32 (q_in_r89ab, q2_tw2.val[0]); q_s1_i = vmulq_f32 (q_in_i89ab, q2_tw2.val[0]); q_s2_r = vmulq_f32 (q_in_rcdef, q2_tw3.val[0]); q_s2_i = vmulq_f32 (q_in_icdef, q2_tw3.val[0]); q_s0_r = vmlaq_f32 (q_s0_r, q_in_i4567, q2_tw1.val[1]); q_s0_i = vmlsq_f32 (q_s0_i, q_in_r4567, q2_tw1.val[1]); q_s1_r = vmlaq_f32 (q_s1_r, q_in_i89ab, q2_tw2.val[1]); q_s1_i = vmlsq_f32 (q_s1_i, q_in_r89ab, q2_tw2.val[1]); q_s2_r = vmlaq_f32 (q_s2_r, q_in_icdef, q2_tw3.val[1]); q_s2_i = vmlsq_f32 (q_s2_i, q_in_rcdef, q2_tw3.val[1]); q_s5_r = vsubq_f32 (q_in_r0123, q_s1_r); q_s5_i = vsubq_f32 (q_in_i0123, q_s1_i); q2_out_0123.val[0] = vaddq_f32 (q_in_r0123, q_s1_r); q2_out_0123.val[1] = vaddq_f32 (q_in_i0123, q_s1_i); q_s3_r = vaddq_f32 (q_s0_r, q_s2_r); q_s3_i = vaddq_f32 (q_s0_i, q_s2_i); q_s4_r = vsubq_f32 (q_s0_r, q_s2_r); q_s4_i = vsubq_f32 (q_s0_i, q_s2_i); q_one_by_nfft = vdupq_n_f32 (0.0625f); q2_out_89ab.val[0] = vsubq_f32 (q2_out_0123.val[0], q_s3_r); q2_out_89ab.val[1] = vsubq_f32 (q2_out_0123.val[1], q_s3_i); q2_out_0123.val[0] = vaddq_f32 (q2_out_0123.val[0], q_s3_r); q2_out_0123.val[1] = vaddq_f32 (q2_out_0123.val[1], q_s3_i); q2_out_4567.val[0] = vsubq_f32 (q_s5_r, q_s4_i); q2_out_4567.val[1] = vaddq_f32 (q_s5_i, q_s4_r); q2_out_cdef.val[0] = vaddq_f32 (q_s5_r, q_s4_i); q2_out_cdef.val[1] = vsubq_f32 (q_s5_i, q_s4_r); q2_out_89ab.val[0] = vmulq_f32 (q2_out_89ab.val[0], q_one_by_nfft); q2_out_89ab.val[1] = vmulq_f32 (q2_out_89ab.val[1], q_one_by_nfft); q2_out_0123.val[0] = vmulq_f32 (q2_out_0123.val[0], q_one_by_nfft); q2_out_0123.val[1] = vmulq_f32 (q2_out_0123.val[1], q_one_by_nfft); q2_out_4567.val[0] = vmulq_f32 (q2_out_4567.val[0], q_one_by_nfft); q2_out_4567.val[1] = vmulq_f32 (q2_out_4567.val[1], q_one_by_nfft); q2_out_cdef.val[0] = vmulq_f32 (q2_out_cdef.val[0], q_one_by_nfft); q2_out_cdef.val[1] = vmulq_f32 (q2_out_cdef.val[1], q_one_by_nfft); vst2q_f32 (p_dst0, q2_out_0123); vst2q_f32 (p_dst1, q2_out_4567); vst2q_f32 (p_dst2, q2_out_89ab); vst2q_f32 (p_dst3, q2_out_cdef); }