Source code

Revision control

Copy as Markdown

Other Tools

/*
* 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 <arm_neon.h>
#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_