Add 6-tap spec. for av1_resize_and_extend_frame_neon

The functions scale_plane_2_to_1_8tap, scale_plane_4_to_1_8tap are
called when 2/1 or 4/1 scaling is applied with filter types
EIGHTTAP_SMOOTH and EIGHTTAP_REGULAR. These filters are 0-padded so
rewrite this functions to avoid multiplying by, and adding, 0.

Change-Id: I55b879e7358ca0fa569be80033bdfa31a0e7c094
diff --git a/av1/common/arm/resize_neon.c b/av1/common/arm/resize_neon.c
index 548bda6..d29dc0a 100644
--- a/av1/common/arm/resize_neon.c
+++ b/av1/common/arm/resize_neon.c
@@ -169,27 +169,26 @@
   } while (--h != 0);
 }
 
-static inline uint8x8_t scale_filter8_8(const int16x8_t s0, const int16x8_t s1,
+static inline uint8x8_t scale_filter6_8(const int16x8_t s0, const int16x8_t s1,
                                         const int16x8_t s2, const int16x8_t s3,
                                         const int16x8_t s4, const int16x8_t s5,
-                                        const int16x8_t s6, const int16x8_t s7,
                                         const int16x8_t filter) {
   const int16x4_t filter_lo = vget_low_s16(filter);
   const int16x4_t filter_hi = vget_high_s16(filter);
 
-  int16x8_t sum = vmulq_lane_s16(s0, filter_lo, 0);
-  sum = vmlaq_lane_s16(sum, s1, filter_lo, 1);
-  sum = vmlaq_lane_s16(sum, s2, filter_lo, 2);
-  sum = vmlaq_lane_s16(sum, s5, filter_hi, 1);
-  sum = vmlaq_lane_s16(sum, s6, filter_hi, 2);
-  sum = vmlaq_lane_s16(sum, s7, filter_hi, 3);
-  sum = vqaddq_s16(sum, vmulq_lane_s16(s3, filter_lo, 3));
-  sum = vqaddq_s16(sum, vmulq_lane_s16(s4, filter_hi, 0));
+  // Filter values at indices 0 and 7 are 0.
+  int16x8_t sum = vmulq_lane_s16(s0, filter_lo, 1);
+  sum = vmlaq_lane_s16(sum, s1, filter_lo, 2);
+  sum = vmlaq_lane_s16(sum, s2, filter_lo, 3);
+  sum = vmlaq_lane_s16(sum, s3, filter_hi, 0);
+  sum = vmlaq_lane_s16(sum, s4, filter_hi, 1);
+  sum = vmlaq_lane_s16(sum, s5, filter_hi, 2);
 
-  return vqrshrun_n_s16(sum, FILTER_BITS);
+  // We halved the convolution filter values so -1 from the right shift.
+  return vqrshrun_n_s16(sum, FILTER_BITS - 1);
 }
 
-static inline void scale_2_to_1_horiz_8tap(const uint8_t *src,
+static inline void scale_2_to_1_horiz_6tap(const uint8_t *src,
                                            const int src_stride, int w, int h,
                                            uint8_t *dst, const int dst_stride,
                                            const int16x8_t filters) {
@@ -226,11 +225,10 @@
       int16x8_t s12 = vreinterpretq_s16_u16(vmovl_u8(t12));
       int16x8_t s13 = vreinterpretq_s16_u16(vmovl_u8(t13));
 
-      uint8x8_t d0 = scale_filter8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters);
-      uint8x8_t d1 = scale_filter8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters);
-      uint8x8_t d2 = scale_filter8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters);
-      uint8x8_t d3 =
-          scale_filter8_8(s6, s7, s8, s9, s10, s11, s12, s13, filters);
+      uint8x8_t d0 = scale_filter6_8(s0, s1, s2, s3, s4, s5, filters);
+      uint8x8_t d1 = scale_filter6_8(s2, s3, s4, s5, s6, s7, filters);
+      uint8x8_t d2 = scale_filter6_8(s4, s5, s6, s7, s8, s9, filters);
+      uint8x8_t d3 = scale_filter6_8(s6, s7, s8, s9, s10, s11, filters);
 
       transpose_elems_inplace_u8_8x4(&d0, &d1, &d2, &d3);
 
@@ -257,43 +255,40 @@
   } while (h > 0);
 }
 
-static inline void scale_2_to_1_vert_8tap(const uint8_t *src,
+static inline void scale_2_to_1_vert_6tap(const uint8_t *src,
                                           const int src_stride, int w, int h,
                                           uint8_t *dst, const int dst_stride,
                                           const int16x8_t filters) {
   do {
-    uint8x8_t t0, t1, t2, t3, t4, t5;
-    load_u8_8x6(src, src_stride, &t0, &t1, &t2, &t3, &t4, &t5);
+    uint8x8_t t0, t1, t2, t3;
+    load_u8_8x4(src, src_stride, &t0, &t1, &t2, &t3);
 
     int16x8_t s0 = vreinterpretq_s16_u16(vmovl_u8(t0));
     int16x8_t s1 = vreinterpretq_s16_u16(vmovl_u8(t1));
     int16x8_t s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
     int16x8_t s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
-    int16x8_t s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
-    int16x8_t s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
 
-    const uint8_t *s = src + 6 * src_stride;
+    const uint8_t *s = src + 4 * src_stride;
     uint8_t *d = dst;
     int height = h;
 
     do {
-      uint8x8_t t6, t7, t8, t9, t10, t11, t12, t13;
-      load_u8_8x8(s, src_stride, &t6, &t7, &t8, &t9, &t10, &t11, &t12, &t13);
+      uint8x8_t t4, t5, t6, t7, t8, t9, t10, t11;
+      load_u8_8x8(s, src_stride, &t4, &t5, &t6, &t7, &t8, &t9, &t10, &t11);
 
+      int16x8_t s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
+      int16x8_t s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
       int16x8_t s6 = vreinterpretq_s16_u16(vmovl_u8(t6));
       int16x8_t s7 = vreinterpretq_s16_u16(vmovl_u8(t7));
       int16x8_t s8 = vreinterpretq_s16_u16(vmovl_u8(t8));
       int16x8_t s9 = vreinterpretq_s16_u16(vmovl_u8(t9));
       int16x8_t s10 = vreinterpretq_s16_u16(vmovl_u8(t10));
       int16x8_t s11 = vreinterpretq_s16_u16(vmovl_u8(t11));
-      int16x8_t s12 = vreinterpretq_s16_u16(vmovl_u8(t12));
-      int16x8_t s13 = vreinterpretq_s16_u16(vmovl_u8(t13));
 
-      uint8x8_t d0 = scale_filter8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters);
-      uint8x8_t d1 = scale_filter8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters);
-      uint8x8_t d2 = scale_filter8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters);
-      uint8x8_t d3 =
-          scale_filter8_8(s6, s7, s8, s9, s10, s11, s12, s13, filters);
+      uint8x8_t d0 = scale_filter6_8(s0, s1, s2, s3, s4, s5, filters);
+      uint8x8_t d1 = scale_filter6_8(s2, s3, s4, s5, s6, s7, filters);
+      uint8x8_t d2 = scale_filter6_8(s4, s5, s6, s7, s8, s9, filters);
+      uint8x8_t d3 = scale_filter6_8(s6, s7, s8, s9, s10, s11, filters);
 
       store_u8_8x4(d, dst_stride, d0, d1, d2, d3);
 
@@ -301,8 +296,6 @@
       s1 = s9;
       s2 = s10;
       s3 = s11;
-      s4 = s12;
-      s5 = s13;
 
       d += 4 * dst_stride;
       s += 8 * src_stride;
@@ -315,27 +308,30 @@
   } while (w > 0);
 }
 
-static inline void scale_plane_2_to_1_8tap(const uint8_t *src,
+static inline void scale_plane_2_to_1_6tap(const uint8_t *src,
                                            const int src_stride, uint8_t *dst,
                                            const int dst_stride, const int w,
                                            const int h,
                                            const int16_t *const filter_ptr,
                                            uint8_t *const im_block) {
   assert(w > 0 && h > 0);
-  const int im_h = 2 * h + SUBPEL_TAPS - 2;
+  const int im_h = 2 * h + SUBPEL_TAPS - 3;
   const int im_stride = (w + 3) & ~3;
-  const int16x8_t filters = vld1q_s16(filter_ptr);
 
-  const ptrdiff_t horiz_offset = SUBPEL_TAPS / 2 - 1;
-  const ptrdiff_t vert_offset = (SUBPEL_TAPS / 2 - 1) * src_stride;
+  // All filter values are even, halve them to stay in 16-bit elements when
+  // applying filter.
+  const int16x8_t filters = vshrq_n_s16(vld1q_s16(filter_ptr), 1);
 
-  scale_2_to_1_horiz_8tap(src - horiz_offset - vert_offset, src_stride, w, im_h,
+  const ptrdiff_t horiz_offset = SUBPEL_TAPS / 2 - 2;
+  const ptrdiff_t vert_offset = (SUBPEL_TAPS / 2 - 2) * src_stride;
+
+  scale_2_to_1_horiz_6tap(src - horiz_offset - vert_offset, src_stride, w, im_h,
                           im_block, im_stride, filters);
 
-  scale_2_to_1_vert_8tap(im_block, im_stride, w, h, dst, dst_stride, filters);
+  scale_2_to_1_vert_6tap(im_block, im_stride, w, h, dst, dst_stride, filters);
 }
 
-static inline void scale_4_to_1_horiz_8tap(const uint8_t *src,
+static inline void scale_4_to_1_horiz_6tap(const uint8_t *src,
                                            const int src_stride, int w, int h,
                                            uint8_t *dst, const int dst_stride,
                                            const int16x8_t filters) {
@@ -369,8 +365,8 @@
       int16x8_t s10 = vreinterpretq_s16_u16(vmovl_u8(t10));
       int16x8_t s11 = vreinterpretq_s16_u16(vmovl_u8(t11));
 
-      uint8x8_t d0 = scale_filter8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters);
-      uint8x8_t d1 = scale_filter8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters);
+      uint8x8_t d0 = scale_filter6_8(s0, s1, s2, s3, s4, s5, filters);
+      uint8x8_t d1 = scale_filter6_8(s4, s5, s6, s7, s8, s9, filters);
 
       uint8x8x2_t d01 = vtrn_u8(d0, d1);
 
@@ -393,45 +389,41 @@
   } while (h > 0);
 }
 
-static inline void scale_4_to_1_vert_8tap(const uint8_t *src,
+static inline void scale_4_to_1_vert_6tap(const uint8_t *src,
                                           const int src_stride, int w, int h,
                                           uint8_t *dst, const int dst_stride,
                                           const int16x8_t filters) {
   do {
-    uint8x8_t t0, t1, t2, t3;
-    load_u8_8x4(src, src_stride, &t0, &t1, &t2, &t3);
+    uint8x8_t t0 = vld1_u8(src + 0 * src_stride);
+    uint8x8_t t1 = vld1_u8(src + 1 * src_stride);
 
     int16x8_t s0 = vreinterpretq_s16_u16(vmovl_u8(t0));
     int16x8_t s1 = vreinterpretq_s16_u16(vmovl_u8(t1));
-    int16x8_t s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
-    int16x8_t s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
 
-    const uint8_t *s = src + 4 * src_stride;
+    const uint8_t *s = src + 2 * src_stride;
     uint8_t *d = dst;
     int height = h;
 
     do {
-      uint8x8_t t4, t5, t6, t7, t8, t9, t10, t11;
-      load_u8_8x8(s, src_stride, &t4, &t5, &t6, &t7, &t8, &t9, &t10, &t11);
+      uint8x8_t t2, t3, t4, t5, t6, t7, t8, t9;
+      load_u8_8x8(s, src_stride, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
 
+      int16x8_t s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
+      int16x8_t s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
       int16x8_t s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
       int16x8_t s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
       int16x8_t s6 = vreinterpretq_s16_u16(vmovl_u8(t6));
       int16x8_t s7 = vreinterpretq_s16_u16(vmovl_u8(t7));
       int16x8_t s8 = vreinterpretq_s16_u16(vmovl_u8(t8));
       int16x8_t s9 = vreinterpretq_s16_u16(vmovl_u8(t9));
-      int16x8_t s10 = vreinterpretq_s16_u16(vmovl_u8(t10));
-      int16x8_t s11 = vreinterpretq_s16_u16(vmovl_u8(t11));
 
-      uint8x8_t d0 = scale_filter8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters);
-      uint8x8_t d1 = scale_filter8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters);
+      uint8x8_t d0 = scale_filter6_8(s0, s1, s2, s3, s4, s5, filters);
+      uint8x8_t d1 = scale_filter6_8(s4, s5, s6, s7, s8, s9, filters);
 
       store_u8_8x2(d, dst_stride, d0, d1);
 
       s0 = s8;
       s1 = s9;
-      s2 = s10;
-      s3 = s11;
 
       s += 8 * src_stride;
       d += 2 * dst_stride;
@@ -444,24 +436,26 @@
   } while (w > 0);
 }
 
-static inline void scale_plane_4_to_1_8tap(const uint8_t *src,
+static inline void scale_plane_4_to_1_6tap(const uint8_t *src,
                                            const int src_stride, uint8_t *dst,
                                            const int dst_stride, const int w,
                                            const int h,
                                            const int16_t *const filter_ptr,
                                            uint8_t *const im_block) {
   assert(w > 0 && h > 0);
-  const int im_h = 4 * h + SUBPEL_TAPS - 2;
+  const int im_h = 4 * h + SUBPEL_TAPS - 3;
   const int im_stride = (w + 1) & ~1;
-  const int16x8_t filters = vld1q_s16(filter_ptr);
+  // All filter values are even, halve them to stay in 16-bit elements when
+  // applying filter.
+  const int16x8_t filters = vshrq_n_s16(vld1q_s16(filter_ptr), 1);
 
-  const ptrdiff_t horiz_offset = SUBPEL_TAPS / 2 - 1;
-  const ptrdiff_t vert_offset = (SUBPEL_TAPS / 2 - 1) * src_stride;
+  const ptrdiff_t horiz_offset = SUBPEL_TAPS / 2 - 2;
+  const ptrdiff_t vert_offset = (SUBPEL_TAPS / 2 - 2) * src_stride;
 
-  scale_4_to_1_horiz_8tap(src - horiz_offset - vert_offset, src_stride, w, im_h,
+  scale_4_to_1_horiz_6tap(src - horiz_offset - vert_offset, src_stride, w, im_h,
                           im_block, im_stride, filters);
 
-  scale_4_to_1_vert_8tap(im_block, im_stride, w, h, dst, dst_stride, filters);
+  scale_4_to_1_vert_6tap(im_block, im_stride, w, h, dst, dst_stride, filters);
 }
 
 static inline uint8x8_t scale_filter_bilinear(const uint8x8_t *const s,
@@ -818,6 +812,9 @@
                                       YV12_BUFFER_CONFIG *dst,
                                       const InterpFilter filter,
                                       const int phase, const int num_planes) {
+  assert(filter == BILINEAR || filter == EIGHTTAP_SMOOTH ||
+         filter == EIGHTTAP_REGULAR);
+
   bool has_normative_scaler =
       has_normative_scaler_neon(src->y_crop_width, src->y_crop_height,
                                 dst->y_crop_width, dst->y_crop_height);
@@ -869,7 +866,7 @@
         const InterpKernel *interp_kernel =
             (const InterpKernel *)av1_interp_filter_params_list[filter]
                 .filter_ptr;
-        scale_plane_2_to_1_8tap(src->buffers[i], src->strides[is_uv],
+        scale_plane_2_to_1_6tap(src->buffers[i], src->strides[is_uv],
                                 dst->buffers[i], dst->strides[is_uv], dst_w,
                                 dst_h, interp_kernel[phase], temp_buffer);
         free(temp_buffer);
@@ -897,7 +894,7 @@
         const InterpKernel *interp_kernel =
             (const InterpKernel *)av1_interp_filter_params_list[filter]
                 .filter_ptr;
-        scale_plane_4_to_1_8tap(src->buffers[i], src->strides[is_uv],
+        scale_plane_4_to_1_6tap(src->buffers[i], src->strides[is_uv],
                                 dst->buffers[i], dst->strides[is_uv], dst_w,
                                 dst_h, interp_kernel[phase], temp_buffer);
         free(temp_buffer);