/* * Copyright (c) 2023, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ #ifndef AOM_AV1_ENCODER_ARM_PICKRST_NEON_H_ #define AOM_AV1_ENCODER_ARM_PICKRST_NEON_H_ #include #include "av1/common/restoration.h" #define WIN_7 ((WIENER_WIN - 1) * 2) #define WIN_CHROMA ((WIENER_WIN_CHROMA - 1) * 2) // Aligned sizes for Wiener filters. #define WIENER_WIN2_ALIGN2 ALIGN_POWER_OF_TWO(WIENER_WIN2, 2) #define WIENER_WIN2_ALIGN3 ALIGN_POWER_OF_TWO(WIENER_WIN2, 3) #define WIENER_WIN2_REDUCED ((WIENER_WIN_REDUCED) * (WIENER_WIN_REDUCED)) #define WIENER_WIN2_REDUCED_ALIGN2 ALIGN_POWER_OF_TWO(WIENER_WIN2_REDUCED, 2) #define WIENER_WIN2_REDUCED_ALIGN3 ALIGN_POWER_OF_TWO(WIENER_WIN2_REDUCED, 3) // Compute 8 values of M (cross correlation) for a single source pixel and // accumulate. static inline void update_M_1pixel(int32_t *M_s32, int16x4_t src_avg, int16x8_t dgd_avg) { int32x4_t lo = vld1q_s32(M_s32 + 0); int32x4_t hi = vld1q_s32(M_s32 + 4); lo = vmlal_s16(lo, vget_low_s16(dgd_avg), src_avg); hi = vmlal_s16(hi, vget_high_s16(dgd_avg), src_avg); vst1q_s32(M_s32 + 0, lo); vst1q_s32(M_s32 + 4, hi); } // Compute 8 values of M (cross correlation) for two source pixels and // accumulate. static inline void update_M_2pixels(int32_t *M_s32, int16x4_t src_avg0, int16x4_t src_avg1, int16x8_t dgd_avg0, int16x8_t dgd_avg1) { int32x4_t lo = vld1q_s32(M_s32 + 0); int32x4_t hi = vld1q_s32(M_s32 + 4); lo = vmlal_s16(lo, vget_low_s16(dgd_avg0), src_avg0); hi = vmlal_s16(hi, vget_high_s16(dgd_avg0), src_avg0); lo = vmlal_s16(lo, vget_low_s16(dgd_avg1), src_avg1); hi = vmlal_s16(hi, vget_high_s16(dgd_avg1), src_avg1); vst1q_s32(M_s32 + 0, lo); vst1q_s32(M_s32 + 4, hi); } static inline void update_H_1pixel(int32_t *H_s32, const int16_t *dgd_avg, int width, int height) { for (int i = 0; i < height; i += 4) { int16x4_t di = vld1_s16(dgd_avg + i); for (int j = i; j < width; j += 4) { int16x4_t dj = vld1_s16(dgd_avg + j); int32x4_t h0 = vld1q_s32(H_s32 + 0 * width + j); int32x4_t h1 = vld1q_s32(H_s32 + 1 * width + j); int32x4_t h2 = vld1q_s32(H_s32 + 2 * width + j); int32x4_t h3 = vld1q_s32(H_s32 + 3 * width + j); h0 = vmlal_lane_s16(h0, dj, di, 0); h1 = vmlal_lane_s16(h1, dj, di, 1); h2 = vmlal_lane_s16(h2, dj, di, 2); h3 = vmlal_lane_s16(h3, dj, di, 3); vst1q_s32(H_s32 + 0 * width + j, h0); vst1q_s32(H_s32 + 1 * width + j, h1); vst1q_s32(H_s32 + 2 * width + j, h2); vst1q_s32(H_s32 + 3 * width + j, h3); } H_s32 += 4 * width; } } static inline void update_H_5x5_2pixels(int32_t *H_s32, const int16_t *dgd_avg0, const int16_t *dgd_avg1) { for (int i = 0; i < 24; i += 4) { int16x4_t di0 = vld1_s16(dgd_avg0 + i); int16x4_t di1 = vld1_s16(dgd_avg1 + i); for (int j = i + 0; j < WIENER_WIN2_REDUCED_ALIGN2; j += 4) { int16x4_t dj0 = vld1_s16(dgd_avg0 + j); int16x4_t dj1 = vld1_s16(dgd_avg1 + j); int32x4_t h0 = vld1q_s32(H_s32 + 0 * WIENER_WIN2_REDUCED_ALIGN2 + j); int32x4_t h1 = vld1q_s32(H_s32 + 1 * WIENER_WIN2_REDUCED_ALIGN2 + j); int32x4_t h2 = vld1q_s32(H_s32 + 2 * WIENER_WIN2_REDUCED_ALIGN2 + j); int32x4_t h3 = vld1q_s32(H_s32 + 3 * WIENER_WIN2_REDUCED_ALIGN2 + j); h0 = vmlal_lane_s16(h0, dj0, di0, 0); h0 = vmlal_lane_s16(h0, dj1, di1, 0); h1 = vmlal_lane_s16(h1, dj0, di0, 1); h1 = vmlal_lane_s16(h1, dj1, di1, 1); h2 = vmlal_lane_s16(h2, dj0, di0, 2); h2 = vmlal_lane_s16(h2, dj1, di1, 2); h3 = vmlal_lane_s16(h3, dj0, di0, 3); h3 = vmlal_lane_s16(h3, dj1, di1, 3); vst1q_s32(H_s32 + 0 * WIENER_WIN2_REDUCED_ALIGN2 + j, h0); vst1q_s32(H_s32 + 1 * WIENER_WIN2_REDUCED_ALIGN2 + j, h1); vst1q_s32(H_s32 + 2 * WIENER_WIN2_REDUCED_ALIGN2 + j, h2); vst1q_s32(H_s32 + 3 * WIENER_WIN2_REDUCED_ALIGN2 + j, h3); } H_s32 += 4 * WIENER_WIN2_REDUCED_ALIGN2; } } static inline void update_H_7x7_2pixels(int32_t *H_s32, const int16_t *dgd_avg0, const int16_t *dgd_avg1) { for (int i = 0; i < 48; i += 4) { int16x4_t di0 = vld1_s16(dgd_avg0 + i); int16x4_t di1 = vld1_s16(dgd_avg1 + i); int32x4_t h0 = vld1q_s32(H_s32 + 0 * WIENER_WIN2_ALIGN2 + i); int32x4_t h1 = vld1q_s32(H_s32 + 1 * WIENER_WIN2_ALIGN2 + i); int32x4_t h2 = vld1q_s32(H_s32 + 2 * WIENER_WIN2_ALIGN2 + i); int32x4_t h3 = vld1q_s32(H_s32 + 3 * WIENER_WIN2_ALIGN2 + i); h0 = vmlal_lane_s16(h0, di0, di0, 0); h0 = vmlal_lane_s16(h0, di1, di1, 0); h1 = vmlal_lane_s16(h1, di0, di0, 1); h1 = vmlal_lane_s16(h1, di1, di1, 1); h2 = vmlal_lane_s16(h2, di0, di0, 2); h2 = vmlal_lane_s16(h2, di1, di1, 2); h3 = vmlal_lane_s16(h3, di0, di0, 3); h3 = vmlal_lane_s16(h3, di1, di1, 3); vst1q_s32(H_s32 + 0 * WIENER_WIN2_ALIGN2 + i, h0); vst1q_s32(H_s32 + 1 * WIENER_WIN2_ALIGN2 + i, h1); vst1q_s32(H_s32 + 2 * WIENER_WIN2_ALIGN2 + i, h2); vst1q_s32(H_s32 + 3 * WIENER_WIN2_ALIGN2 + i, h3); for (int j = i + 4; j < WIENER_WIN2_ALIGN2; j += 4) { int16x4_t dj0 = vld1_s16(dgd_avg0 + j); int16x4_t dj1 = vld1_s16(dgd_avg1 + j); h0 = vld1q_s32(H_s32 + 0 * WIENER_WIN2_ALIGN2 + j); h1 = vld1q_s32(H_s32 + 1 * WIENER_WIN2_ALIGN2 + j); h2 = vld1q_s32(H_s32 + 2 * WIENER_WIN2_ALIGN2 + j); h3 = vld1q_s32(H_s32 + 3 * WIENER_WIN2_ALIGN2 + j); h0 = vmlal_lane_s16(h0, dj0, di0, 0); h0 = vmlal_lane_s16(h0, dj1, di1, 0); h1 = vmlal_lane_s16(h1, dj0, di0, 1); h1 = vmlal_lane_s16(h1, dj1, di1, 1); h2 = vmlal_lane_s16(h2, dj0, di0, 2); h2 = vmlal_lane_s16(h2, dj1, di1, 2); h3 = vmlal_lane_s16(h3, dj0, di0, 3); h3 = vmlal_lane_s16(h3, dj1, di1, 3); vst1q_s32(H_s32 + 0 * WIENER_WIN2_ALIGN2 + j, h0); vst1q_s32(H_s32 + 1 * WIENER_WIN2_ALIGN2 + j, h1); vst1q_s32(H_s32 + 2 * WIENER_WIN2_ALIGN2 + j, h2); vst1q_s32(H_s32 + 3 * WIENER_WIN2_ALIGN2 + j, h3); } H_s32 += 4 * WIENER_WIN2_ALIGN2; } } // Widen 32-bit src data and accumulate into 64-bit dst. Clear src data. static inline void accumulate_and_clear(int64_t *dst, int32_t *src, int length) { do { int32x4_t s32 = vld1q_s32(src); vst1q_s32(src, vdupq_n_s32(0)); src += 4; int64x2_t d_lo = vld1q_s64(dst + 0); int64x2_t d_hi = vld1q_s64(dst + 2); d_lo = vaddw_s32(d_lo, vget_low_s32(s32)); d_hi = vaddw_s32(d_hi, vget_high_s32(s32)); vst1q_s64(dst + 0, d_lo); vst1q_s64(dst + 2, d_hi); dst += 4; length -= 4; } while (length > 0); } // clang-format off // Constant pool to act as a mask to zero n top elements in an int16x8_t vector. // The index we load from depends on n. static const int16_t mask_16bit[32] = { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; // clang-format on static inline void madd_neon_pairwise(int32x4_t *sum, const int16x8_t src, const int16x8_t dgd) { const int32x4_t sd = horizontal_add_2d_s32(vmull_s16(vget_low_s16(src), vget_low_s16(dgd)), vmull_s16(vget_high_s16(src), vget_high_s16(dgd))); *sum = vaddq_s32(*sum, sd); } static inline void madd_neon(int32x4_t *sum, const int16x8_t src, const int16x8_t dgd) { *sum = vmlal_s16(*sum, vget_low_s16(src), vget_low_s16(dgd)); *sum = vmlal_s16(*sum, vget_high_s16(src), vget_high_s16(dgd)); } static inline void msub_neon(int32x4_t *sum, const int16x8_t src, const int16x8_t dgd) { *sum = vmlsl_s16(*sum, vget_low_s16(src), vget_low_s16(dgd)); *sum = vmlsl_s16(*sum, vget_high_s16(src), vget_high_s16(dgd)); } static inline void compute_delta_step3(int32x4_t *sum0, int32x4_t *sum1, const int16x8_t src0, const int16x8_t src1, const int16x8_t dgd0, const int16x8_t dgd1) { *sum0 = vmlsl_s16(*sum0, vget_low_s16(src0), vget_low_s16(dgd0)); *sum0 = vmlal_s16(*sum0, vget_low_s16(src1), vget_low_s16(dgd1)); *sum1 = vmlsl_s16(*sum1, vget_high_s16(src0), vget_high_s16(dgd0)); *sum1 = vmlal_s16(*sum1, vget_high_s16(src1), vget_high_s16(dgd1)); } static inline int32x4_t hadd_four_32_neon(const int32x4_t src0, const int32x4_t src1, const int32x4_t src2, const int32x4_t src3) { int32x4_t src[4] = { src0, src1, src2, src3 }; return horizontal_add_4d_s32x4(src); } static inline void update_4_stats_neon(const int64_t *const src, const int32x4_t delta, int64_t *const dst) { const int64x2_t s1 = vld1q_s64(src); const int64x2_t s2 = vld1q_s64(src + 2); const int64x2_t d1 = vaddw_s32(s1, vget_low_s32(delta)); const int64x2_t d2 = vaddw_s32(s2, vget_high_s32(delta)); vst1q_s64(dst, d1); vst1q_s64(dst + 2, d2); } static inline void load_more_16_neon(const int16_t *const src, const int32_t width, const int16x8_t org[2], int16x8_t dst[2]) { int16x8_t s0 = vld1q_dup_s16(src); int16x8_t s1 = vld1q_dup_s16(src + width); dst[0] = vextq_s16(org[0], s0, 1); dst[1] = vextq_s16(org[1], s1, 1); } static inline void stats_top_win5_neon(const int16x8_t src[2], const int16x8_t dgd[2], const int16_t *const d, const int32_t d_stride, int32x4_t *sum_m, int32x4_t *sum_h) { int16x8_t dgds[WIENER_WIN_CHROMA * 2]; load_s16_8x5(d + 0, d_stride, &dgds[0], &dgds[2], &dgds[4], &dgds[6], &dgds[8]); load_s16_8x5(d + 8, d_stride, &dgds[1], &dgds[3], &dgds[5], &dgds[7], &dgds[9]); madd_neon(&sum_m[0], src[0], dgds[0]); madd_neon(&sum_m[0], src[1], dgds[1]); madd_neon(&sum_m[1], src[0], dgds[2]); madd_neon(&sum_m[1], src[1], dgds[3]); madd_neon(&sum_m[2], src[0], dgds[4]); madd_neon(&sum_m[2], src[1], dgds[5]); madd_neon(&sum_m[3], src[0], dgds[6]); madd_neon(&sum_m[3], src[1], dgds[7]); madd_neon(&sum_m[4], src[0], dgds[8]); madd_neon(&sum_m[4], src[1], dgds[9]); madd_neon(&sum_h[0], dgd[0], dgds[0]); madd_neon(&sum_h[0], dgd[1], dgds[1]); madd_neon(&sum_h[1], dgd[0], dgds[2]); madd_neon(&sum_h[1], dgd[1], dgds[3]); madd_neon(&sum_h[2], dgd[0], dgds[4]); madd_neon(&sum_h[2], dgd[1], dgds[5]); madd_neon(&sum_h[3], dgd[0], dgds[6]); madd_neon(&sum_h[3], dgd[1], dgds[7]); madd_neon(&sum_h[4], dgd[0], dgds[8]); madd_neon(&sum_h[4], dgd[1], dgds[9]); } static inline void stats_left_win5_neon(const int16x8_t src[2], const int16_t *d, const int32_t d_stride, int32x4_t *sum) { int16x8_t dgds[WIN_CHROMA]; load_s16_8x4(d + d_stride + 0, d_stride, &dgds[0], &dgds[2], &dgds[4], &dgds[6]); load_s16_8x4(d + d_stride + 8, d_stride, &dgds[1], &dgds[3], &dgds[5], &dgds[7]); madd_neon(&sum[0], src[0], dgds[0]); madd_neon(&sum[0], src[1], dgds[1]); madd_neon(&sum[1], src[0], dgds[2]); madd_neon(&sum[1], src[1], dgds[3]); madd_neon(&sum[2], src[0], dgds[4]); madd_neon(&sum[2], src[1], dgds[5]); madd_neon(&sum[3], src[0], dgds[6]); madd_neon(&sum[3], src[1], dgds[7]); } static inline void derive_square_win5_neon( const int16x8_t *d_is, const int16x8_t *d_ie, const int16x8_t *d_js, const int16x8_t *d_je, int32x4_t deltas[WIENER_WIN_CHROMA - 1][WIENER_WIN_CHROMA - 1]) { msub_neon(&deltas[0][0], d_is[0], d_js[0]); msub_neon(&deltas[0][0], d_is[1], d_js[1]); msub_neon(&deltas[0][1], d_is[0], d_js[2]); msub_neon(&deltas[0][1], d_is[1], d_js[3]); msub_neon(&deltas[0][2], d_is[0], d_js[4]); msub_neon(&deltas[0][2], d_is[1], d_js[5]); msub_neon(&deltas[0][3], d_is[0], d_js[6]); msub_neon(&deltas[0][3], d_is[1], d_js[7]); msub_neon(&deltas[1][0], d_is[2], d_js[0]); msub_neon(&deltas[1][0], d_is[3], d_js[1]); msub_neon(&deltas[1][1], d_is[2], d_js[2]); msub_neon(&deltas[1][1], d_is[3], d_js[3]); msub_neon(&deltas[1][2], d_is[2], d_js[4]); msub_neon(&deltas[1][2], d_is[3], d_js[5]); msub_neon(&deltas[1][3], d_is[2], d_js[6]); msub_neon(&deltas[1][3], d_is[3], d_js[7]); msub_neon(&deltas[2][0], d_is[4], d_js[0]); msub_neon(&deltas[2][0], d_is[5], d_js[1]); msub_neon(&deltas[2][1], d_is[4], d_js[2]); msub_neon(&deltas[2][1], d_is[5], d_js[3]); msub_neon(&deltas[2][2], d_is[4], d_js[4]); msub_neon(&deltas[2][2], d_is[5], d_js[5]); msub_neon(&deltas[2][3], d_is[4], d_js[6]); msub_neon(&deltas[2][3], d_is[5], d_js[7]); msub_neon(&deltas[3][0], d_is[6], d_js[0]); msub_neon(&deltas[3][0], d_is[7], d_js[1]); msub_neon(&deltas[3][1], d_is[6], d_js[2]); msub_neon(&deltas[3][1], d_is[7], d_js[3]); msub_neon(&deltas[3][2], d_is[6], d_js[4]); msub_neon(&deltas[3][2], d_is[7], d_js[5]); msub_neon(&deltas[3][3], d_is[6], d_js[6]); msub_neon(&deltas[3][3], d_is[7], d_js[7]); madd_neon(&deltas[0][0], d_ie[0], d_je[0]); madd_neon(&deltas[0][0], d_ie[1], d_je[1]); madd_neon(&deltas[0][1], d_ie[0], d_je[2]); madd_neon(&deltas[0][1], d_ie[1], d_je[3]); madd_neon(&deltas[0][2], d_ie[0], d_je[4]); madd_neon(&deltas[0][2], d_ie[1], d_je[5]); madd_neon(&deltas[0][3], d_ie[0], d_je[6]); madd_neon(&deltas[0][3], d_ie[1], d_je[7]); madd_neon(&deltas[1][0], d_ie[2], d_je[0]); madd_neon(&deltas[1][0], d_ie[3], d_je[1]); madd_neon(&deltas[1][1], d_ie[2], d_je[2]); madd_neon(&deltas[1][1], d_ie[3], d_je[3]); madd_neon(&deltas[1][2], d_ie[2], d_je[4]); madd_neon(&deltas[1][2], d_ie[3], d_je[5]); madd_neon(&deltas[1][3], d_ie[2], d_je[6]); madd_neon(&deltas[1][3], d_ie[3], d_je[7]); madd_neon(&deltas[2][0], d_ie[4], d_je[0]); madd_neon(&deltas[2][0], d_ie[5], d_je[1]); madd_neon(&deltas[2][1], d_ie[4], d_je[2]); madd_neon(&deltas[2][1], d_ie[5], d_je[3]); madd_neon(&deltas[2][2], d_ie[4], d_je[4]); madd_neon(&deltas[2][2], d_ie[5], d_je[5]); madd_neon(&deltas[2][3], d_ie[4], d_je[6]); madd_neon(&deltas[2][3], d_ie[5], d_je[7]); madd_neon(&deltas[3][0], d_ie[6], d_je[0]); madd_neon(&deltas[3][0], d_ie[7], d_je[1]); madd_neon(&deltas[3][1], d_ie[6], d_je[2]); madd_neon(&deltas[3][1], d_ie[7], d_je[3]); madd_neon(&deltas[3][2], d_ie[6], d_je[4]); madd_neon(&deltas[3][2], d_ie[7], d_je[5]); madd_neon(&deltas[3][3], d_ie[6], d_je[6]); madd_neon(&deltas[3][3], d_ie[7], d_je[7]); } static inline void load_square_win5_neon(const int16_t *const di, const int16_t *const dj, const int32_t d_stride, const int32_t height, int16x8_t *d_is, int16x8_t *d_ie, int16x8_t *d_js, int16x8_t *d_je) { load_s16_8x4(di + 0, d_stride, &d_is[0], &d_is[2], &d_is[4], &d_is[6]); load_s16_8x4(di + 8, d_stride, &d_is[1], &d_is[3], &d_is[5], &d_is[7]); load_s16_8x4(dj + 0, d_stride, &d_js[0], &d_js[2], &d_js[4], &d_js[6]); load_s16_8x4(dj + 8, d_stride, &d_js[1], &d_js[3], &d_js[5], &d_js[7]); load_s16_8x4(di + height * d_stride + 0, d_stride, &d_ie[0], &d_ie[2], &d_ie[4], &d_ie[6]); load_s16_8x4(di + height * d_stride + 8, d_stride, &d_ie[1], &d_ie[3], &d_ie[5], &d_ie[7]); load_s16_8x4(dj + height * d_stride + 0, d_stride, &d_je[0], &d_je[2], &d_je[4], &d_je[6]); load_s16_8x4(dj + height * d_stride + 8, d_stride, &d_je[1], &d_je[3], &d_je[5], &d_je[7]); } static inline void update_5_stats_neon(const int64_t *const src, const int32x4_t delta, const int64_t delta4, int64_t *const dst) { update_4_stats_neon(src + 0, delta, dst + 0); dst[4] = src[4] + delta4; } static inline void compute_delta_step3_two_lines(int32x4_t *sum, const int16x8_t src, const int16x8_t dgd) { *sum = vmlsl_s16(*sum, vget_low_s16(src), vget_low_s16(dgd)); *sum = vmlal_s16(*sum, vget_high_s16(src), vget_high_s16(dgd)); } static inline void step3_win5_neon(const int16_t *d, const int32_t d_stride, const int32_t width, const int32_t height, int16x8_t *ds, int32x4_t *deltas) { int32_t y = height; do { ds[4] = load_unaligned_s16_4x2(d + 0 * d_stride, width); ds[5] = load_unaligned_s16_4x2(d + 1 * d_stride, width); compute_delta_step3_two_lines(&deltas[0], ds[0], ds[0]); compute_delta_step3_two_lines(&deltas[1], ds[0], ds[1]); compute_delta_step3_two_lines(&deltas[2], ds[0], ds[2]); compute_delta_step3_two_lines(&deltas[3], ds[0], ds[3]); compute_delta_step3_two_lines(&deltas[4], ds[0], ds[4]); compute_delta_step3_two_lines(&deltas[0], ds[1], ds[1]); compute_delta_step3_two_lines(&deltas[1], ds[1], ds[2]); compute_delta_step3_two_lines(&deltas[2], ds[1], ds[3]); compute_delta_step3_two_lines(&deltas[3], ds[1], ds[4]); compute_delta_step3_two_lines(&deltas[4], ds[1], ds[5]); ds[0] = ds[2]; ds[1] = ds[3]; ds[2] = ds[4]; ds[3] = ds[5]; d += 2 * d_stride; y -= 2; } while (y); } static inline void step3_win5_oneline_neon(const int16_t **const d, const int32_t d_stride, const int32_t width, const int32_t height, int16x8_t *ds, int32x4_t *deltas) { int32_t y = height; do { ds[8] = vld1q_s16(*d); ds[9] = vld1q_s16(*d + width); compute_delta_step3(&deltas[0], &deltas[4], ds[0], ds[1], ds[0], ds[1]); compute_delta_step3(&deltas[1], &deltas[5], ds[0], ds[1], ds[2], ds[3]); compute_delta_step3(&deltas[2], &deltas[6], ds[0], ds[1], ds[4], ds[5]); compute_delta_step3(&deltas[3], &deltas[7], ds[0], ds[1], ds[6], ds[7]); compute_delta_step3(&deltas[8], &deltas[12], ds[0], ds[1], ds[8], ds[9]); ds[0] = ds[2]; ds[1] = ds[3]; ds[2] = ds[4]; ds[3] = ds[5]; ds[4] = ds[6]; ds[5] = ds[7]; ds[6] = ds[8]; ds[7] = ds[9]; *d += d_stride; } while (--y); } static inline void derive_triangle_win5_neon(const int16x8_t *d_is, const int16x8_t *d_ie, int32x4_t *deltas) { msub_neon(&deltas[0], d_is[0], d_is[0]); msub_neon(&deltas[0], d_is[1], d_is[1]); msub_neon(&deltas[1], d_is[0], d_is[2]); msub_neon(&deltas[1], d_is[1], d_is[3]); msub_neon(&deltas[2], d_is[0], d_is[4]); msub_neon(&deltas[2], d_is[1], d_is[5]); msub_neon(&deltas[3], d_is[0], d_is[6]); msub_neon(&deltas[3], d_is[1], d_is[7]); msub_neon(&deltas[4], d_is[2], d_is[2]); msub_neon(&deltas[4], d_is[3], d_is[3]); msub_neon(&deltas[5], d_is[2], d_is[4]); msub_neon(&deltas[5], d_is[3], d_is[5]); msub_neon(&deltas[6], d_is[2], d_is[6]); msub_neon(&deltas[6], d_is[3], d_is[7]); msub_neon(&deltas[7], d_is[4], d_is[4]); msub_neon(&deltas[7], d_is[5], d_is[5]); msub_neon(&deltas[8], d_is[4], d_is[6]); msub_neon(&deltas[8], d_is[5], d_is[7]); msub_neon(&deltas[9], d_is[6], d_is[6]); msub_neon(&deltas[9], d_is[7], d_is[7]); madd_neon(&deltas[0], d_ie[0], d_ie[0]); madd_neon(&deltas[0], d_ie[1], d_ie[1]); madd_neon(&deltas[1], d_ie[0], d_ie[2]); madd_neon(&deltas[1], d_ie[1], d_ie[3]); madd_neon(&deltas[2], d_ie[0], d_ie[4]); madd_neon(&deltas[2], d_ie[1], d_ie[5]); madd_neon(&deltas[3], d_ie[0], d_ie[6]); madd_neon(&deltas[3], d_ie[1], d_ie[7]); madd_neon(&deltas[4], d_ie[2], d_ie[2]); madd_neon(&deltas[4], d_ie[3], d_ie[3]); madd_neon(&deltas[5], d_ie[2], d_ie[4]); madd_neon(&deltas[5], d_ie[3], d_ie[5]); madd_neon(&deltas[6], d_ie[2], d_ie[6]); madd_neon(&deltas[6], d_ie[3], d_ie[7]); madd_neon(&deltas[7], d_ie[4], d_ie[4]); madd_neon(&deltas[7], d_ie[5], d_ie[5]); madd_neon(&deltas[8], d_ie[4], d_ie[6]); madd_neon(&deltas[8], d_ie[5], d_ie[7]); madd_neon(&deltas[9], d_ie[6], d_ie[6]); madd_neon(&deltas[9], d_ie[7], d_ie[7]); } static inline void load_triangle_win5_neon(const int16_t *const di, const int32_t d_stride, const int32_t height, int16x8_t *d_is, int16x8_t *d_ie) { load_s16_8x4(di + 0, d_stride, &d_is[0], &d_is[2], &d_is[4], &d_is[6]); load_s16_8x4(di + 8, d_stride, &d_is[1], &d_is[3], &d_is[5], &d_is[7]); load_s16_8x4(di + height * d_stride + 0, d_stride, &d_ie[0], &d_ie[2], &d_ie[4], &d_ie[6]); load_s16_8x4(di + height * d_stride + 8, d_stride, &d_ie[1], &d_ie[3], &d_ie[5], &d_ie[7]); } static inline void sub_deltas_step4(int16x8_t *A, int16x8_t *B, int32x4_t *deltas) { deltas[0] = vmlsl_s16(deltas[0], vget_low_s16(A[0]), vget_low_s16(B[0])); deltas[0] = vmlsl_s16(deltas[0], vget_high_s16(A[0]), vget_high_s16(B[0])); deltas[1] = vmlsl_s16(deltas[1], vget_low_s16(A[0]), vget_low_s16(B[1])); deltas[1] = vmlsl_s16(deltas[1], vget_high_s16(A[0]), vget_high_s16(B[1])); deltas[2] = vmlsl_s16(deltas[2], vget_low_s16(A[0]), vget_low_s16(B[2])); deltas[2] = vmlsl_s16(deltas[2], vget_high_s16(A[0]), vget_high_s16(B[2])); deltas[3] = vmlsl_s16(deltas[3], vget_low_s16(A[0]), vget_low_s16(B[3])); deltas[3] = vmlsl_s16(deltas[3], vget_high_s16(A[0]), vget_high_s16(B[3])); deltas[4] = vmlsl_s16(deltas[4], vget_low_s16(A[0]), vget_low_s16(B[4])); deltas[4] = vmlsl_s16(deltas[4], vget_high_s16(A[0]), vget_high_s16(B[4])); deltas[5] = vmlsl_s16(deltas[5], vget_low_s16(A[1]), vget_low_s16(B[0])); deltas[5] = vmlsl_s16(deltas[5], vget_high_s16(A[1]), vget_high_s16(B[0])); deltas[6] = vmlsl_s16(deltas[6], vget_low_s16(A[2]), vget_low_s16(B[0])); deltas[6] = vmlsl_s16(deltas[6], vget_high_s16(A[2]), vget_high_s16(B[0])); deltas[7] = vmlsl_s16(deltas[7], vget_low_s16(A[3]), vget_low_s16(B[0])); deltas[7] = vmlsl_s16(deltas[7], vget_high_s16(A[3]), vget_high_s16(B[0])); deltas[8] = vmlsl_s16(deltas[8], vget_low_s16(A[4]), vget_low_s16(B[0])); deltas[8] = vmlsl_s16(deltas[8], vget_high_s16(A[4]), vget_high_s16(B[0])); } static inline void add_deltas_step4(int16x8_t *A, int16x8_t *B, int32x4_t *deltas) { deltas[0] = vmlal_s16(deltas[0], vget_low_s16(A[0]), vget_low_s16(B[0])); deltas[0] = vmlal_s16(deltas[0], vget_high_s16(A[0]), vget_high_s16(B[0])); deltas[1] = vmlal_s16(deltas[1], vget_low_s16(A[0]), vget_low_s16(B[1])); deltas[1] = vmlal_s16(deltas[1], vget_high_s16(A[0]), vget_high_s16(B[1])); deltas[2] = vmlal_s16(deltas[2], vget_low_s16(A[0]), vget_low_s16(B[2])); deltas[2] = vmlal_s16(deltas[2], vget_high_s16(A[0]), vget_high_s16(B[2])); deltas[3] = vmlal_s16(deltas[3], vget_low_s16(A[0]), vget_low_s16(B[3])); deltas[3] = vmlal_s16(deltas[3], vget_high_s16(A[0]), vget_high_s16(B[3])); deltas[4] = vmlal_s16(deltas[4], vget_low_s16(A[0]), vget_low_s16(B[4])); deltas[4] = vmlal_s16(deltas[4], vget_high_s16(A[0]), vget_high_s16(B[4])); deltas[5] = vmlal_s16(deltas[5], vget_low_s16(A[1]), vget_low_s16(B[0])); deltas[5] = vmlal_s16(deltas[5], vget_high_s16(A[1]), vget_high_s16(B[0])); deltas[6] = vmlal_s16(deltas[6], vget_low_s16(A[2]), vget_low_s16(B[0])); deltas[6] = vmlal_s16(deltas[6], vget_high_s16(A[2]), vget_high_s16(B[0])); deltas[7] = vmlal_s16(deltas[7], vget_low_s16(A[3]), vget_low_s16(B[0])); deltas[7] = vmlal_s16(deltas[7], vget_high_s16(A[3]), vget_high_s16(B[0])); deltas[8] = vmlal_s16(deltas[8], vget_low_s16(A[4]), vget_low_s16(B[0])); deltas[8] = vmlal_s16(deltas[8], vget_high_s16(A[4]), vget_high_s16(B[0])); } static inline void stats_top_win7_neon(const int16x8_t src[2], const int16x8_t dgd[2], const int16_t *const d, const int32_t d_stride, int32x4_t *sum_m, int32x4_t *sum_h) { int16x8_t dgds[WIENER_WIN * 2]; load_s16_8x7(d + 0, d_stride, &dgds[0], &dgds[2], &dgds[4], &dgds[6], &dgds[8], &dgds[10], &dgds[12]); load_s16_8x7(d + 8, d_stride, &dgds[1], &dgds[3], &dgds[5], &dgds[7], &dgds[9], &dgds[11], &dgds[13]); madd_neon(&sum_m[0], src[0], dgds[0]); madd_neon(&sum_m[0], src[1], dgds[1]); madd_neon(&sum_m[1], src[0], dgds[2]); madd_neon(&sum_m[1], src[1], dgds[3]); madd_neon(&sum_m[2], src[0], dgds[4]); madd_neon(&sum_m[2], src[1], dgds[5]); madd_neon(&sum_m[3], src[0], dgds[6]); madd_neon(&sum_m[3], src[1], dgds[7]); madd_neon(&sum_m[4], src[0], dgds[8]); madd_neon(&sum_m[4], src[1], dgds[9]); madd_neon(&sum_m[5], src[0], dgds[10]); madd_neon(&sum_m[5], src[1], dgds[11]); madd_neon(&sum_m[6], src[0], dgds[12]); madd_neon(&sum_m[6], src[1], dgds[13]); madd_neon(&sum_h[0], dgd[0], dgds[0]); madd_neon(&sum_h[0], dgd[1], dgds[1]); madd_neon(&sum_h[1], dgd[0], dgds[2]); madd_neon(&sum_h[1], dgd[1], dgds[3]); madd_neon(&sum_h[2], dgd[0], dgds[4]); madd_neon(&sum_h[2], dgd[1], dgds[5]); madd_neon(&sum_h[3], dgd[0], dgds[6]); madd_neon(&sum_h[3], dgd[1], dgds[7]); madd_neon(&sum_h[4], dgd[0], dgds[8]); madd_neon(&sum_h[4], dgd[1], dgds[9]); madd_neon(&sum_h[5], dgd[0], dgds[10]); madd_neon(&sum_h[5], dgd[1], dgds[11]); madd_neon(&sum_h[6], dgd[0], dgds[12]); madd_neon(&sum_h[6], dgd[1], dgds[13]); } static inline void derive_square_win7_neon(const int16x8_t *d_is, const int16x8_t *d_ie, const int16x8_t *d_js, const int16x8_t *d_je, int32x4_t deltas[][WIN_7]) { msub_neon(&deltas[0][0], d_is[0], d_js[0]); msub_neon(&deltas[0][0], d_is[1], d_js[1]); msub_neon(&deltas[0][1], d_is[0], d_js[2]); msub_neon(&deltas[0][1], d_is[1], d_js[3]); msub_neon(&deltas[0][2], d_is[0], d_js[4]); msub_neon(&deltas[0][2], d_is[1], d_js[5]); msub_neon(&deltas[0][3], d_is[0], d_js[6]); msub_neon(&deltas[0][3], d_is[1], d_js[7]); msub_neon(&deltas[0][4], d_is[0], d_js[8]); msub_neon(&deltas[0][4], d_is[1], d_js[9]); msub_neon(&deltas[0][5], d_is[0], d_js[10]); msub_neon(&deltas[0][5], d_is[1], d_js[11]); msub_neon(&deltas[1][0], d_is[2], d_js[0]); msub_neon(&deltas[1][0], d_is[3], d_js[1]); msub_neon(&deltas[1][1], d_is[2], d_js[2]); msub_neon(&deltas[1][1], d_is[3], d_js[3]); msub_neon(&deltas[1][2], d_is[2], d_js[4]); msub_neon(&deltas[1][2], d_is[3], d_js[5]); msub_neon(&deltas[1][3], d_is[2], d_js[6]); msub_neon(&deltas[1][3], d_is[3], d_js[7]); msub_neon(&deltas[1][4], d_is[2], d_js[8]); msub_neon(&deltas[1][4], d_is[3], d_js[9]); msub_neon(&deltas[1][5], d_is[2], d_js[10]); msub_neon(&deltas[1][5], d_is[3], d_js[11]); msub_neon(&deltas[2][0], d_is[4], d_js[0]); msub_neon(&deltas[2][0], d_is[5], d_js[1]); msub_neon(&deltas[2][1], d_is[4], d_js[2]); msub_neon(&deltas[2][1], d_is[5], d_js[3]); msub_neon(&deltas[2][2], d_is[4], d_js[4]); msub_neon(&deltas[2][2], d_is[5], d_js[5]); msub_neon(&deltas[2][3], d_is[4], d_js[6]); msub_neon(&deltas[2][3], d_is[5], d_js[7]); msub_neon(&deltas[2][4], d_is[4], d_js[8]); msub_neon(&deltas[2][4], d_is[5], d_js[9]); msub_neon(&deltas[2][5], d_is[4], d_js[10]); msub_neon(&deltas[2][5], d_is[5], d_js[11]); msub_neon(&deltas[3][0], d_is[6], d_js[0]); msub_neon(&deltas[3][0], d_is[7], d_js[1]); msub_neon(&deltas[3][1], d_is[6], d_js[2]); msub_neon(&deltas[3][1], d_is[7], d_js[3]); msub_neon(&deltas[3][2], d_is[6], d_js[4]); msub_neon(&deltas[3][2], d_is[7], d_js[5]); msub_neon(&deltas[3][3], d_is[6], d_js[6]); msub_neon(&deltas[3][3], d_is[7], d_js[7]); msub_neon(&deltas[3][4], d_is[6], d_js[8]); msub_neon(&deltas[3][4], d_is[7], d_js[9]); msub_neon(&deltas[3][5], d_is[6], d_js[10]); msub_neon(&deltas[3][5], d_is[7], d_js[11]); msub_neon(&deltas[4][0], d_is[8], d_js[0]); msub_neon(&deltas[4][0], d_is[9], d_js[1]); msub_neon(&deltas[4][1], d_is[8], d_js[2]); msub_neon(&deltas[4][1], d_is[9], d_js[3]); msub_neon(&deltas[4][2], d_is[8], d_js[4]); msub_neon(&deltas[4][2], d_is[9], d_js[5]); msub_neon(&deltas[4][3], d_is[8], d_js[6]); msub_neon(&deltas[4][3], d_is[9], d_js[7]); msub_neon(&deltas[4][4], d_is[8], d_js[8]); msub_neon(&deltas[4][4], d_is[9], d_js[9]); msub_neon(&deltas[4][5], d_is[8], d_js[10]); msub_neon(&deltas[4][5], d_is[9], d_js[11]); msub_neon(&deltas[5][0], d_is[10], d_js[0]); msub_neon(&deltas[5][0], d_is[11], d_js[1]); msub_neon(&deltas[5][1], d_is[10], d_js[2]); msub_neon(&deltas[5][1], d_is[11], d_js[3]); msub_neon(&deltas[5][2], d_is[10], d_js[4]); msub_neon(&deltas[5][2], d_is[11], d_js[5]); msub_neon(&deltas[5][3], d_is[10], d_js[6]); msub_neon(&deltas[5][3], d_is[11], d_js[7]); msub_neon(&deltas[5][4], d_is[10], d_js[8]); msub_neon(&deltas[5][4], d_is[11], d_js[9]); msub_neon(&deltas[5][5], d_is[10], d_js[10]); msub_neon(&deltas[5][5], d_is[11], d_js[11]); madd_neon(&deltas[0][0], d_ie[0], d_je[0]); madd_neon(&deltas[0][0], d_ie[1], d_je[1]); madd_neon(&deltas[0][1], d_ie[0], d_je[2]); madd_neon(&deltas[0][1], d_ie[1], d_je[3]); madd_neon(&deltas[0][2], d_ie[0], d_je[4]); madd_neon(&deltas[0][2], d_ie[1], d_je[5]); madd_neon(&deltas[0][3], d_ie[0], d_je[6]); madd_neon(&deltas[0][3], d_ie[1], d_je[7]); madd_neon(&deltas[0][4], d_ie[0], d_je[8]); madd_neon(&deltas[0][4], d_ie[1], d_je[9]); madd_neon(&deltas[0][5], d_ie[0], d_je[10]); madd_neon(&deltas[0][5], d_ie[1], d_je[11]); madd_neon(&deltas[1][0], d_ie[2], d_je[0]); madd_neon(&deltas[1][0], d_ie[3], d_je[1]); madd_neon(&deltas[1][1], d_ie[2], d_je[2]); madd_neon(&deltas[1][1], d_ie[3], d_je[3]); madd_neon(&deltas[1][2], d_ie[2], d_je[4]); madd_neon(&deltas[1][2], d_ie[3], d_je[5]); madd_neon(&deltas[1][3], d_ie[2], d_je[6]); madd_neon(&deltas[1][3], d_ie[3], d_je[7]); madd_neon(&deltas[1][4], d_ie[2], d_je[8]); madd_neon(&deltas[1][4], d_ie[3], d_je[9]); madd_neon(&deltas[1][5], d_ie[2], d_je[10]); madd_neon(&deltas[1][5], d_ie[3], d_je[11]); madd_neon(&deltas[2][0], d_ie[4], d_je[0]); madd_neon(&deltas[2][0], d_ie[5], d_je[1]); madd_neon(&deltas[2][1], d_ie[4], d_je[2]); madd_neon(&deltas[2][1], d_ie[5], d_je[3]); madd_neon(&deltas[2][2], d_ie[4], d_je[4]); madd_neon(&deltas[2][2], d_ie[5], d_je[5]); madd_neon(&deltas[2][3], d_ie[4], d_je[6]); madd_neon(&deltas[2][3], d_ie[5], d_je[7]); madd_neon(&deltas[2][4], d_ie[4], d_je[8]); madd_neon(&deltas[2][4], d_ie[5], d_je[9]); madd_neon(&deltas[2][5], d_ie[4], d_je[10]); madd_neon(&deltas[2][5], d_ie[5], d_je[11]); madd_neon(&deltas[3][0], d_ie[6], d_je[0]); madd_neon(&deltas[3][0], d_ie[7], d_je[1]); madd_neon(&deltas[3][1], d_ie[6], d_je[2]); madd_neon(&deltas[3][1], d_ie[7], d_je[3]); madd_neon(&deltas[3][2], d_ie[6], d_je[4]); madd_neon(&deltas[3][2], d_ie[7], d_je[5]); madd_neon(&deltas[3][3], d_ie[6], d_je[6]); madd_neon(&deltas[3][3], d_ie[7], d_je[7]); madd_neon(&deltas[3][4], d_ie[6], d_je[8]); madd_neon(&deltas[3][4], d_ie[7], d_je[9]); madd_neon(&deltas[3][5], d_ie[6], d_je[10]); madd_neon(&deltas[3][5], d_ie[7], d_je[11]); madd_neon(&deltas[4][0], d_ie[8], d_je[0]); madd_neon(&deltas[4][0], d_ie[9], d_je[1]); madd_neon(&deltas[4][1], d_ie[8], d_je[2]); madd_neon(&deltas[4][1], d_ie[9], d_je[3]); madd_neon(&deltas[4][2], d_ie[8], d_je[4]); madd_neon(&deltas[4][2], d_ie[9], d_je[5]); madd_neon(&deltas[4][3], d_ie[8], d_je[6]); madd_neon(&deltas[4][3], d_ie[9], d_je[7]); madd_neon(&deltas[4][4], d_ie[8], d_je[8]); madd_neon(&deltas[4][4], d_ie[9], d_je[9]); madd_neon(&deltas[4][5], d_ie[8], d_je[10]); madd_neon(&deltas[4][5], d_ie[9], d_je[11]); madd_neon(&deltas[5][0], d_ie[10], d_je[0]); madd_neon(&deltas[5][0], d_ie[11], d_je[1]); madd_neon(&deltas[5][1], d_ie[10], d_je[2]); madd_neon(&deltas[5][1], d_ie[11], d_je[3]); madd_neon(&deltas[5][2], d_ie[10], d_je[4]); madd_neon(&deltas[5][2], d_ie[11], d_je[5]); madd_neon(&deltas[5][3], d_ie[10], d_je[6]); madd_neon(&deltas[5][3], d_ie[11], d_je[7]); madd_neon(&deltas[5][4], d_ie[10], d_je[8]); madd_neon(&deltas[5][4], d_ie[11], d_je[9]); madd_neon(&deltas[5][5], d_ie[10], d_je[10]); madd_neon(&deltas[5][5], d_ie[11], d_je[11]); } static inline void update_8_stats_neon(const int64_t *const src, const int32x4_t delta0, const int32x4_t delta1, int64_t *const dst) { update_4_stats_neon(src + 0, delta0, dst + 0); update_4_stats_neon(src + 4, delta1, dst + 4); } static inline void load_square_win7_neon(const int16_t *const di, const int16_t *const dj, const int32_t d_stride, const int32_t height, int16x8_t *d_is, int16x8_t *d_ie, int16x8_t *d_js, int16x8_t *d_je) { load_s16_8x6(di + 0, d_stride, &d_is[0], &d_is[2], &d_is[4], &d_is[6], &d_is[8], &d_is[10]); load_s16_8x6(di + 8, d_stride, &d_is[1], &d_is[3], &d_is[5], &d_is[7], &d_is[9], &d_is[11]); load_s16_8x6(dj + 0, d_stride, &d_js[0], &d_js[2], &d_js[4], &d_js[6], &d_js[8], &d_js[10]); load_s16_8x6(dj + 8, d_stride, &d_js[1], &d_js[3], &d_js[5], &d_js[7], &d_js[9], &d_js[11]); load_s16_8x6(di + height * d_stride + 0, d_stride, &d_ie[0], &d_ie[2], &d_ie[4], &d_ie[6], &d_ie[8], &d_ie[10]); load_s16_8x6(di + height * d_stride + 8, d_stride, &d_ie[1], &d_ie[3], &d_ie[5], &d_ie[7], &d_ie[9], &d_ie[11]); load_s16_8x6(dj + height * d_stride + 0, d_stride, &d_je[0], &d_je[2], &d_je[4], &d_je[6], &d_je[8], &d_je[10]); load_s16_8x6(dj + height * d_stride + 8, d_stride, &d_je[1], &d_je[3], &d_je[5], &d_je[7], &d_je[9], &d_je[11]); } static inline void load_triangle_win7_neon(const int16_t *const di, const int32_t d_stride, const int32_t height, int16x8_t *d_is, int16x8_t *d_ie) { load_s16_8x6(di, d_stride, &d_is[0], &d_is[2], &d_is[4], &d_is[6], &d_is[8], &d_is[10]); load_s16_8x6(di + 8, d_stride, &d_is[1], &d_is[3], &d_is[5], &d_is[7], &d_is[9], &d_is[11]); load_s16_8x6(di + height * d_stride, d_stride, &d_ie[0], &d_ie[2], &d_ie[4], &d_ie[6], &d_ie[8], &d_ie[10]); load_s16_8x6(di + height * d_stride + 8, d_stride, &d_ie[1], &d_ie[3], &d_ie[5], &d_ie[7], &d_ie[9], &d_ie[11]); } static inline void stats_left_win7_neon(const int16x8_t src[2], const int16_t *d, const int32_t d_stride, int32x4_t *sum) { int16x8_t dgds[WIN_7]; load_s16_8x6(d + d_stride + 0, d_stride, &dgds[0], &dgds[2], &dgds[4], &dgds[6], &dgds[8], &dgds[10]); load_s16_8x6(d + d_stride + 8, d_stride, &dgds[1], &dgds[3], &dgds[5], &dgds[7], &dgds[9], &dgds[11]); madd_neon(&sum[0], src[0], dgds[0]); madd_neon(&sum[0], src[1], dgds[1]); madd_neon(&sum[1], src[0], dgds[2]); madd_neon(&sum[1], src[1], dgds[3]); madd_neon(&sum[2], src[0], dgds[4]); madd_neon(&sum[2], src[1], dgds[5]); madd_neon(&sum[3], src[0], dgds[6]); madd_neon(&sum[3], src[1], dgds[7]); madd_neon(&sum[4], src[0], dgds[8]); madd_neon(&sum[4], src[1], dgds[9]); madd_neon(&sum[5], src[0], dgds[10]); madd_neon(&sum[5], src[1], dgds[11]); } static inline void step3_win7_neon(const int16_t *d, const int32_t d_stride, const int32_t width, const int32_t height, int16x8_t *ds, int32x4_t *deltas) { int32_t y = height; do { ds[12] = vld1q_s16(d); ds[13] = vld1q_s16(d + width); compute_delta_step3(&deltas[0], &deltas[4], ds[0], ds[1], ds[0], ds[1]); compute_delta_step3(&deltas[1], &deltas[5], ds[0], ds[1], ds[2], ds[3]); compute_delta_step3(&deltas[2], &deltas[6], ds[0], ds[1], ds[4], ds[5]); compute_delta_step3(&deltas[3], &deltas[7], ds[0], ds[1], ds[6], ds[7]); compute_delta_step3(&deltas[8], &deltas[12], ds[0], ds[1], ds[8], ds[9]); compute_delta_step3(&deltas[9], &deltas[13], ds[0], ds[1], ds[10], ds[11]); compute_delta_step3(&deltas[10], &deltas[14], ds[0], ds[1], ds[12], ds[13]); ds[0] = ds[2]; ds[1] = ds[3]; ds[2] = ds[4]; ds[3] = ds[5]; ds[4] = ds[6]; ds[5] = ds[7]; ds[6] = ds[8]; ds[7] = ds[9]; ds[8] = ds[10]; ds[9] = ds[11]; ds[10] = ds[12]; ds[11] = ds[13]; d += d_stride; } while (--y); } static inline void derive_triangle_win7_neon(const int16x8_t *d_is, const int16x8_t *d_ie, int32x4_t *deltas) { msub_neon(&deltas[0], d_is[0], d_is[0]); msub_neon(&deltas[0], d_is[1], d_is[1]); msub_neon(&deltas[1], d_is[0], d_is[2]); msub_neon(&deltas[1], d_is[1], d_is[3]); msub_neon(&deltas[2], d_is[0], d_is[4]); msub_neon(&deltas[2], d_is[1], d_is[5]); msub_neon(&deltas[3], d_is[0], d_is[6]); msub_neon(&deltas[3], d_is[1], d_is[7]); msub_neon(&deltas[4], d_is[0], d_is[8]); msub_neon(&deltas[4], d_is[1], d_is[9]); msub_neon(&deltas[5], d_is[0], d_is[10]); msub_neon(&deltas[5], d_is[1], d_is[11]); msub_neon(&deltas[6], d_is[2], d_is[2]); msub_neon(&deltas[6], d_is[3], d_is[3]); msub_neon(&deltas[7], d_is[2], d_is[4]); msub_neon(&deltas[7], d_is[3], d_is[5]); msub_neon(&deltas[8], d_is[2], d_is[6]); msub_neon(&deltas[8], d_is[3], d_is[7]); msub_neon(&deltas[9], d_is[2], d_is[8]); msub_neon(&deltas[9], d_is[3], d_is[9]); msub_neon(&deltas[10], d_is[2], d_is[10]); msub_neon(&deltas[10], d_is[3], d_is[11]); msub_neon(&deltas[11], d_is[4], d_is[4]); msub_neon(&deltas[11], d_is[5], d_is[5]); msub_neon(&deltas[12], d_is[4], d_is[6]); msub_neon(&deltas[12], d_is[5], d_is[7]); msub_neon(&deltas[13], d_is[4], d_is[8]); msub_neon(&deltas[13], d_is[5], d_is[9]); msub_neon(&deltas[14], d_is[4], d_is[10]); msub_neon(&deltas[14], d_is[5], d_is[11]); msub_neon(&deltas[15], d_is[6], d_is[6]); msub_neon(&deltas[15], d_is[7], d_is[7]); msub_neon(&deltas[16], d_is[6], d_is[8]); msub_neon(&deltas[16], d_is[7], d_is[9]); msub_neon(&deltas[17], d_is[6], d_is[10]); msub_neon(&deltas[17], d_is[7], d_is[11]); msub_neon(&deltas[18], d_is[8], d_is[8]); msub_neon(&deltas[18], d_is[9], d_is[9]); msub_neon(&deltas[19], d_is[8], d_is[10]); msub_neon(&deltas[19], d_is[9], d_is[11]); msub_neon(&deltas[20], d_is[10], d_is[10]); msub_neon(&deltas[20], d_is[11], d_is[11]); madd_neon(&deltas[0], d_ie[0], d_ie[0]); madd_neon(&deltas[0], d_ie[1], d_ie[1]); madd_neon(&deltas[1], d_ie[0], d_ie[2]); madd_neon(&deltas[1], d_ie[1], d_ie[3]); madd_neon(&deltas[2], d_ie[0], d_ie[4]); madd_neon(&deltas[2], d_ie[1], d_ie[5]); madd_neon(&deltas[3], d_ie[0], d_ie[6]); madd_neon(&deltas[3], d_ie[1], d_ie[7]); madd_neon(&deltas[4], d_ie[0], d_ie[8]); madd_neon(&deltas[4], d_ie[1], d_ie[9]); madd_neon(&deltas[5], d_ie[0], d_ie[10]); madd_neon(&deltas[5], d_ie[1], d_ie[11]); madd_neon(&deltas[6], d_ie[2], d_ie[2]); madd_neon(&deltas[6], d_ie[3], d_ie[3]); madd_neon(&deltas[7], d_ie[2], d_ie[4]); madd_neon(&deltas[7], d_ie[3], d_ie[5]); madd_neon(&deltas[8], d_ie[2], d_ie[6]); madd_neon(&deltas[8], d_ie[3], d_ie[7]); madd_neon(&deltas[9], d_ie[2], d_ie[8]); madd_neon(&deltas[9], d_ie[3], d_ie[9]); madd_neon(&deltas[10], d_ie[2], d_ie[10]); madd_neon(&deltas[10], d_ie[3], d_ie[11]); madd_neon(&deltas[11], d_ie[4], d_ie[4]); madd_neon(&deltas[11], d_ie[5], d_ie[5]); madd_neon(&deltas[12], d_ie[4], d_ie[6]); madd_neon(&deltas[12], d_ie[5], d_ie[7]); madd_neon(&deltas[13], d_ie[4], d_ie[8]); madd_neon(&deltas[13], d_ie[5], d_ie[9]); madd_neon(&deltas[14], d_ie[4], d_ie[10]); madd_neon(&deltas[14], d_ie[5], d_ie[11]); madd_neon(&deltas[15], d_ie[6], d_ie[6]); madd_neon(&deltas[15], d_ie[7], d_ie[7]); madd_neon(&deltas[16], d_ie[6], d_ie[8]); madd_neon(&deltas[16], d_ie[7], d_ie[9]); madd_neon(&deltas[17], d_ie[6], d_ie[10]); madd_neon(&deltas[17], d_ie[7], d_ie[11]); madd_neon(&deltas[18], d_ie[8], d_ie[8]); madd_neon(&deltas[18], d_ie[9], d_ie[9]); madd_neon(&deltas[19], d_ie[8], d_ie[10]); madd_neon(&deltas[19], d_ie[9], d_ie[11]); madd_neon(&deltas[20], d_ie[10], d_ie[10]); madd_neon(&deltas[20], d_ie[11], d_ie[11]); } static inline void diagonal_copy_stats_neon(const int32_t wiener_win2, int64_t *const H) { for (int32_t i = 0; i < wiener_win2 - 1; i += 4) { int64x2_t in[8], out[8]; in[0] = vld1q_s64(H + (i + 0) * wiener_win2 + i + 1); in[1] = vld1q_s64(H + (i + 0) * wiener_win2 + i + 3); in[2] = vld1q_s64(H + (i + 1) * wiener_win2 + i + 1); in[3] = vld1q_s64(H + (i + 1) * wiener_win2 + i + 3); in[4] = vld1q_s64(H + (i + 2) * wiener_win2 + i + 1); in[5] = vld1q_s64(H + (i + 2) * wiener_win2 + i + 3); in[6] = vld1q_s64(H + (i + 3) * wiener_win2 + i + 1); in[7] = vld1q_s64(H + (i + 3) * wiener_win2 + i + 3); transpose_arrays_s64_4x4(in, out); vst1_s64(H + (i + 1) * wiener_win2 + i, vget_low_s64(out[0])); vst1q_s64(H + (i + 2) * wiener_win2 + i, out[2]); vst1q_s64(H + (i + 3) * wiener_win2 + i, out[4]); vst1q_s64(H + (i + 3) * wiener_win2 + i + 2, out[5]); vst1q_s64(H + (i + 4) * wiener_win2 + i, out[6]); vst1q_s64(H + (i + 4) * wiener_win2 + i + 2, out[7]); for (int32_t j = i + 5; j < wiener_win2; j += 4) { in[0] = vld1q_s64(H + (i + 0) * wiener_win2 + j); in[1] = vld1q_s64(H + (i + 0) * wiener_win2 + j + 2); in[2] = vld1q_s64(H + (i + 1) * wiener_win2 + j); in[3] = vld1q_s64(H + (i + 1) * wiener_win2 + j + 2); in[4] = vld1q_s64(H + (i + 2) * wiener_win2 + j); in[5] = vld1q_s64(H + (i + 2) * wiener_win2 + j + 2); in[6] = vld1q_s64(H + (i + 3) * wiener_win2 + j); in[7] = vld1q_s64(H + (i + 3) * wiener_win2 + j + 2); transpose_arrays_s64_4x4(in, out); vst1q_s64(H + (j + 0) * wiener_win2 + i, out[0]); vst1q_s64(H + (j + 0) * wiener_win2 + i + 2, out[1]); vst1q_s64(H + (j + 1) * wiener_win2 + i, out[2]); vst1q_s64(H + (j + 1) * wiener_win2 + i + 2, out[3]); vst1q_s64(H + (j + 2) * wiener_win2 + i, out[4]); vst1q_s64(H + (j + 2) * wiener_win2 + i + 2, out[5]); vst1q_s64(H + (j + 3) * wiener_win2 + i, out[6]); vst1q_s64(H + (j + 3) * wiener_win2 + i + 2, out[7]); } } } static inline int64x2_t div4_neon(const int64x2_t src) { #if AOM_ARCH_AARCH64 uint64x2_t sign = vcltzq_s64(src); int64x2_t abs = vabsq_s64(src); // divide by 4 abs = vshrq_n_s64(abs, 2); // re-apply sign return vbslq_s64(sign, vnegq_s64(abs), abs); #else int64x2_t sign = vshrq_n_s64(src, 63); int64x2_t abs = vsubq_s64(veorq_s64(src, sign), sign); // divide by 4 abs = vshrq_n_s64(abs, 2); // re-apply sign return vsubq_s64(veorq_s64(abs, sign), sign); #endif // AOM_ARCH_AARCH64 } static inline void div4_4x4_neon(const int32_t wiener_win2, int64_t *const H, int64x2_t out[8]) { out[0] = vld1q_s64(H + 0 * wiener_win2 + 0); out[1] = vld1q_s64(H + 0 * wiener_win2 + 2); out[2] = vld1q_s64(H + 1 * wiener_win2 + 0); out[3] = vld1q_s64(H + 1 * wiener_win2 + 2); out[4] = vld1q_s64(H + 2 * wiener_win2 + 0); out[5] = vld1q_s64(H + 2 * wiener_win2 + 2); out[6] = vld1q_s64(H + 3 * wiener_win2 + 0); out[7] = vld1q_s64(H + 3 * wiener_win2 + 2); out[0] = div4_neon(out[0]); out[1] = div4_neon(out[1]); out[2] = div4_neon(out[2]); out[3] = div4_neon(out[3]); out[4] = div4_neon(out[4]); out[5] = div4_neon(out[5]); out[6] = div4_neon(out[6]); out[7] = div4_neon(out[7]); vst1q_s64(H + 0 * wiener_win2 + 0, out[0]); vst1q_s64(H + 0 * wiener_win2 + 2, out[1]); vst1q_s64(H + 1 * wiener_win2 + 0, out[2]); vst1q_s64(H + 1 * wiener_win2 + 2, out[3]); vst1q_s64(H + 2 * wiener_win2 + 0, out[4]); vst1q_s64(H + 2 * wiener_win2 + 2, out[5]); vst1q_s64(H + 3 * wiener_win2 + 0, out[6]); vst1q_s64(H + 3 * wiener_win2 + 2, out[7]); } static inline int64x2_t div16_neon(const int64x2_t src) { #if AOM_ARCH_AARCH64 uint64x2_t sign = vcltzq_s64(src); int64x2_t abs = vabsq_s64(src); // divide by 16 abs = vshrq_n_s64(abs, 4); // re-apply sign return vbslq_s64(sign, vnegq_s64(abs), abs); #else int64x2_t sign = vshrq_n_s64(src, 63); int64x2_t abs = vsubq_s64(veorq_s64(src, sign), sign); // divide by 16 abs = vshrq_n_s64(abs, 4); // re-apply sign return vsubq_s64(veorq_s64(abs, sign), sign); #endif // AOM_ARCH_AARCH64 } static inline void div16_4x4_neon(const int32_t wiener_win2, int64_t *const H, int64x2_t out[8]) { out[0] = vld1q_s64(H + 0 * wiener_win2 + 0); out[1] = vld1q_s64(H + 0 * wiener_win2 + 2); out[2] = vld1q_s64(H + 1 * wiener_win2 + 0); out[3] = vld1q_s64(H + 1 * wiener_win2 + 2); out[4] = vld1q_s64(H + 2 * wiener_win2 + 0); out[5] = vld1q_s64(H + 2 * wiener_win2 + 2); out[6] = vld1q_s64(H + 3 * wiener_win2 + 0); out[7] = vld1q_s64(H + 3 * wiener_win2 + 2); out[0] = div16_neon(out[0]); out[1] = div16_neon(out[1]); out[2] = div16_neon(out[2]); out[3] = div16_neon(out[3]); out[4] = div16_neon(out[4]); out[5] = div16_neon(out[5]); out[6] = div16_neon(out[6]); out[7] = div16_neon(out[7]); vst1q_s64(H + 0 * wiener_win2 + 0, out[0]); vst1q_s64(H + 0 * wiener_win2 + 2, out[1]); vst1q_s64(H + 1 * wiener_win2 + 0, out[2]); vst1q_s64(H + 1 * wiener_win2 + 2, out[3]); vst1q_s64(H + 2 * wiener_win2 + 0, out[4]); vst1q_s64(H + 2 * wiener_win2 + 2, out[5]); vst1q_s64(H + 3 * wiener_win2 + 0, out[6]); vst1q_s64(H + 3 * wiener_win2 + 2, out[7]); } static inline void div4_diagonal_copy_stats_neon(const int32_t wiener_win2, int64_t *const H) { for (int32_t i = 0; i < wiener_win2 - 1; i += 4) { int64x2_t in[8], out[8]; div4_4x4_neon(wiener_win2, H + i * wiener_win2 + i + 1, in); transpose_arrays_s64_4x4(in, out); vst1_s64(H + (i + 1) * wiener_win2 + i + 0, vget_low_s64(out[0])); vst1q_s64(H + (i + 2) * wiener_win2 + i + 0, out[2]); vst1q_s64(H + (i + 3) * wiener_win2 + i + 0, out[4]); vst1q_s64(H + (i + 3) * wiener_win2 + i + 2, out[5]); vst1q_s64(H + (i + 4) * wiener_win2 + i + 0, out[6]); vst1q_s64(H + (i + 4) * wiener_win2 + i + 2, out[7]); for (int32_t j = i + 5; j < wiener_win2; j += 4) { div4_4x4_neon(wiener_win2, H + i * wiener_win2 + j, in); transpose_arrays_s64_4x4(in, out); vst1q_s64(H + (j + 0) * wiener_win2 + i + 0, out[0]); vst1q_s64(H + (j + 0) * wiener_win2 + i + 2, out[1]); vst1q_s64(H + (j + 1) * wiener_win2 + i + 0, out[2]); vst1q_s64(H + (j + 1) * wiener_win2 + i + 2, out[3]); vst1q_s64(H + (j + 2) * wiener_win2 + i + 0, out[4]); vst1q_s64(H + (j + 2) * wiener_win2 + i + 2, out[5]); vst1q_s64(H + (j + 3) * wiener_win2 + i + 0, out[6]); vst1q_s64(H + (j + 3) * wiener_win2 + i + 2, out[7]); } } } static inline void div16_diagonal_copy_stats_neon(const int32_t wiener_win2, int64_t *const H) { for (int32_t i = 0; i < wiener_win2 - 1; i += 4) { int64x2_t in[8], out[8]; div16_4x4_neon(wiener_win2, H + i * wiener_win2 + i + 1, in); transpose_arrays_s64_4x4(in, out); vst1_s64(H + (i + 1) * wiener_win2 + i + 0, vget_low_s64(out[0])); vst1q_s64(H + (i + 2) * wiener_win2 + i + 0, out[2]); vst1q_s64(H + (i + 3) * wiener_win2 + i + 0, out[4]); vst1q_s64(H + (i + 3) * wiener_win2 + i + 2, out[5]); vst1q_s64(H + (i + 4) * wiener_win2 + i + 0, out[6]); vst1q_s64(H + (i + 4) * wiener_win2 + i + 2, out[7]); for (int32_t j = i + 5; j < wiener_win2; j += 4) { div16_4x4_neon(wiener_win2, H + i * wiener_win2 + j, in); transpose_arrays_s64_4x4(in, out); vst1q_s64(H + (j + 0) * wiener_win2 + i + 0, out[0]); vst1q_s64(H + (j + 0) * wiener_win2 + i + 2, out[1]); vst1q_s64(H + (j + 1) * wiener_win2 + i + 0, out[2]); vst1q_s64(H + (j + 1) * wiener_win2 + i + 2, out[3]); vst1q_s64(H + (j + 2) * wiener_win2 + i + 0, out[4]); vst1q_s64(H + (j + 2) * wiener_win2 + i + 2, out[5]); vst1q_s64(H + (j + 3) * wiener_win2 + i + 0, out[6]); vst1q_s64(H + (j + 3) * wiener_win2 + i + 2, out[7]); } } } #endif // AOM_AV1_ENCODER_ARM_PICKRST_NEON_H_