From: Johann Koenig Date: Fri, 16 Sep 2016 06:12:49 +0000 (+0000) Subject: Revert "Restore vp8_sixtap_predict4x4_neon" X-Git-Tag: v1.6.1~261^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7795e992962a7e6b6f2960c77106dec7b3abcf37;p=libvpx Revert "Restore vp8_sixtap_predict4x4_neon" This reverts commit d9dce2f48eed1368a44c368fa87a506bd89ffec5. Appears to be failing the SixtapPredict tests in some configurations and possibly test vectors as well. Change-Id: Ica6aa83ebac47d0a76e451846e7da67b1c17a7d7 --- diff --git a/test/sixtap_predict_test.cc b/test/sixtap_predict_test.cc index 110c09aa8..31a604417 100644 --- a/test/sixtap_predict_test.cc +++ b/test/sixtap_predict_test.cc @@ -195,8 +195,7 @@ INSTANTIATE_TEST_CASE_P( NEON, SixtapPredictTest, ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_neon), make_tuple(8, 8, &vp8_sixtap_predict8x8_neon), - make_tuple(8, 4, &vp8_sixtap_predict8x4_neon), - make_tuple(4, 4, &vp8_sixtap_predict4x4_neon))); + make_tuple(8, 4, &vp8_sixtap_predict8x4_neon))); #endif #if HAVE_MMX INSTANTIATE_TEST_CASE_P( diff --git a/vp8/common/arm/neon/sixtappredict_neon.c b/vp8/common/arm/neon/sixtappredict_neon.c index 623ab0241..622baa3c5 100644 --- a/vp8/common/arm/neon/sixtappredict_neon.c +++ b/vp8/common/arm/neon/sixtappredict_neon.c @@ -9,8 +9,6 @@ */ #include -#include -#include "./vpx_config.h" #include "vpx_ports/mem.h" static const int8_t vp8_sub_pel_filters[8][8] = { @@ -24,398 +22,6 @@ static const int8_t vp8_sub_pel_filters[8][8] = { { 0, -1, 12, 123, -6, 0, 0, 0 }, }; -// This table is derived from vp8/common/filter.c:vp8_sub_pel_filters. -// Apply abs() to all the values. Elements 0, 2, 3, and 5 are always positive. -// Elements 1 and 4 are either 0 or negative. The code accounts for this with -// multiply/accumulates which either add or subtract as needed. The other -// functions will be updated to use this table later. -// It is also expanded to 8 elements to allow loading into 64 bit neon -// registers. -static const uint8_t abs_filters[8][8] = { - { 0, 0, 128, 0, 0, 0, 0, 0 }, { 0, 6, 123, 12, 1, 0, 0, 0 }, - { 2, 11, 108, 36, 8, 1, 0, 0 }, { 0, 9, 93, 50, 6, 0, 0, 0 }, - { 3, 16, 77, 77, 16, 3, 0, 0 }, { 0, 6, 50, 93, 9, 0, 0, 0 }, - { 1, 8, 36, 108, 11, 2, 0, 0 }, { 0, 1, 12, 123, 6, 0, 0, 0 }, -}; - -static INLINE uint8x8_t load_and_shift(const unsigned char *a) { - return vreinterpret_u8_u64(vshl_n_u64(vreinterpret_u64_u8(vld1_u8(a)), 32)); -} - -static INLINE void store4x4(unsigned char *dst, int dst_stride, - const uint8x8_t a0, const uint8x8_t a1) { - if (!((uintptr_t)dst & 0x3) && !(dst_stride & 0x3)) { - vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(a0), 0); - dst += dst_stride; - vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(a0), 1); - dst += dst_stride; - vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(a1), 0); - dst += dst_stride; - vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(a1), 1); - } else { - // Store to the aligned local buffer and memcpy instead of vget_lane_u8 - // which is really really slow. - uint32_t output_buffer[4]; - vst1_lane_u32(output_buffer, vreinterpret_u32_u8(a0), 0); - vst1_lane_u32(output_buffer + 1, vreinterpret_u32_u8(a0), 1); - vst1_lane_u32(output_buffer + 2, vreinterpret_u32_u8(a1), 0); - vst1_lane_u32(output_buffer + 3, vreinterpret_u32_u8(a1), 1); - - memcpy(dst, output_buffer, 4); - dst += dst_stride; - memcpy(dst, output_buffer + 1, 4); - dst += dst_stride; - memcpy(dst, output_buffer + 2, 4); - dst += dst_stride; - memcpy(dst, output_buffer + 3, 4); - } -} - -static INLINE void filter_add_accumulate(const uint8x16_t a, const uint8x16_t b, - const uint8x8_t filter, uint16x8_t *c, - uint16x8_t *d) { - const uint32x2x2_t a_shuf = vzip_u32(vreinterpret_u32_u8(vget_low_u8(a)), - vreinterpret_u32_u8(vget_high_u8(a))); - const uint32x2x2_t b_shuf = vzip_u32(vreinterpret_u32_u8(vget_low_u8(b)), - vreinterpret_u32_u8(vget_high_u8(b))); - *c = vmlal_u8(*c, vreinterpret_u8_u32(a_shuf.val[0]), filter); - *d = vmlal_u8(*d, vreinterpret_u8_u32(b_shuf.val[0]), filter); -} - -static INLINE void filter_sub_accumulate(const uint8x16_t a, const uint8x16_t b, - const uint8x8_t filter, uint16x8_t *c, - uint16x8_t *d) { - const uint32x2x2_t a_shuf = vzip_u32(vreinterpret_u32_u8(vget_low_u8(a)), - vreinterpret_u32_u8(vget_high_u8(a))); - const uint32x2x2_t b_shuf = vzip_u32(vreinterpret_u32_u8(vget_low_u8(b)), - vreinterpret_u32_u8(vget_high_u8(b))); - *c = vmlsl_u8(*c, vreinterpret_u8_u32(a_shuf.val[0]), filter); - *d = vmlsl_u8(*d, vreinterpret_u8_u32(b_shuf.val[0]), filter); -} - -static INLINE void yonly4x4(const unsigned char *src, int src_stride, - int filter_offset, unsigned char *dst, - int dst_stride) { - uint8x8_t a0, a1, a2, a3, a4, a5, a6, a7, a8; - uint8x8_t b0, b1, b2, b3, b4, b5, b6, b7, b8; - uint16x8_t c0, c1, c2, c3; - uint8x8_t d0, d1; - - const uint8x8_t filter = vld1_u8(abs_filters[filter_offset]); - const uint8x8_t filter0 = vdup_lane_u8(filter, 0); - const uint8x8_t filter1 = vdup_lane_u8(filter, 1); - const uint8x8_t filter2 = vdup_lane_u8(filter, 2); - const uint8x8_t filter3 = vdup_lane_u8(filter, 3); - const uint8x8_t filter4 = vdup_lane_u8(filter, 4); - const uint8x8_t filter5 = vdup_lane_u8(filter, 5); - - src -= src_stride * 2; - // Shift the even rows to allow using 'vext' to combine the vectors. armv8 - // has vcopy_lane which would be interesting. This started as just a - // horrible workaround for clang adding alignment hints to 32bit loads: - // https://llvm.org/bugs/show_bug.cgi?id=24421 - // But it turns out it almost identical to casting the loads. - a0 = load_and_shift(src); - src += src_stride; - a1 = vld1_u8(src); - src += src_stride; - a2 = load_and_shift(src); - src += src_stride; - a3 = vld1_u8(src); - src += src_stride; - a4 = load_and_shift(src); - src += src_stride; - a5 = vld1_u8(src); - src += src_stride; - a6 = load_and_shift(src); - src += src_stride; - a7 = vld1_u8(src); - src += src_stride; - a8 = vld1_u8(src); - - // Combine the rows so we can operate on 8 at a time. - b0 = vext_u8(a0, a1, 4); - b2 = vext_u8(a2, a3, 4); - b4 = vext_u8(a4, a5, 4); - b6 = vext_u8(a6, a7, 4); - b8 = a8; - - // To keep with the 8-at-a-time theme, combine *alternate* rows. This - // allows combining the odd rows with the even. - b1 = vext_u8(b0, b2, 4); - b3 = vext_u8(b2, b4, 4); - b5 = vext_u8(b4, b6, 4); - b7 = vext_u8(b6, b8, 4); - - // Multiply and expand to 16 bits. - c0 = vmull_u8(b0, filter0); - c1 = vmull_u8(b2, filter0); - c2 = vmull_u8(b5, filter5); - c3 = vmull_u8(b7, filter5); - - // Multiply, subtract and accumulate for filters 1 and 4 (the negative - // ones). - c0 = vmlsl_u8(c0, b4, filter4); - c1 = vmlsl_u8(c1, b6, filter4); - c2 = vmlsl_u8(c2, b1, filter1); - c3 = vmlsl_u8(c3, b3, filter1); - - // Add more positive ones. vmlal should really return a signed type. - // It's doing signed math internally, as evidenced by the fact we can do - // subtractions followed by more additions. Ideally we could use - // vqmlal/sl but that instruction doesn't exist. Might be able to - // shoehorn vqdmlal/vqdmlsl in here but it would take some effort. - c0 = vmlal_u8(c0, b2, filter2); - c1 = vmlal_u8(c1, b4, filter2); - c2 = vmlal_u8(c2, b3, filter3); - c3 = vmlal_u8(c3, b5, filter3); - - // Use signed saturation math because vmlsl may have left some negative - // numbers in there. - c0 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(c2), vreinterpretq_s16_u16(c0))); - c1 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(c3), vreinterpretq_s16_u16(c1))); - - // Shift and narrow. - d0 = vqrshrn_n_u16(c0, 7); - d1 = vqrshrn_n_u16(c1, 7); - - store4x4(dst, dst_stride, d0, d1); -} - -void vp8_sixtap_predict4x4_neon(unsigned char *src_ptr, int src_pixels_per_line, - int xoffset, int yoffset, - unsigned char *dst_ptr, int dst_pitch) { - uint8x16_t s0, s1, s2, s3, s4; - uint64x2_t s01, s23; - // Variables to hold src[] elements for the given filter[] - uint8x8_t s0_f5, s1_f5, s2_f5, s3_f5, s4_f5; - uint8x8_t s4_f1, s4_f2, s4_f3, s4_f4; - uint8x16_t s01_f0, s23_f0; - uint64x2_t s01_f3, s23_f3; - uint32x2x2_t s01_f3_q, s23_f3_q, s01_f5_q, s23_f5_q; - // Accumulator variables. - uint16x8_t d0123, d4567, d89; - uint16x8_t d0123_a, d4567_a, d89_a; - // Second pass intermediates. - uint8x8_t b0, b1, b2, b3, b4, b5, b6, b7, b8; - uint16x8_t c0, c1, c2, c3; - uint8x8_t d0, d1; - uint8x8_t filter, filter0, filter1, filter2, filter3, filter4, filter5; - - if (xoffset == 0) { // Second pass only. - yonly4x4(src_ptr, src_pixels_per_line, yoffset, dst_ptr, dst_pitch); - return; - } - - if (yoffset == 0) { // First pass only. - src_ptr -= 2; - } else { // Add context for the second pass. 2 extra lines on top. - src_ptr -= 2 + (src_pixels_per_line * 2); - } - - filter = vld1_u8(abs_filters[xoffset]); - filter0 = vdup_lane_u8(filter, 0); - filter1 = vdup_lane_u8(filter, 1); - filter2 = vdup_lane_u8(filter, 2); - filter3 = vdup_lane_u8(filter, 3); - filter4 = vdup_lane_u8(filter, 4); - filter5 = vdup_lane_u8(filter, 5); - - // 2 bytes of context, 4 bytes of src values, 3 bytes of context, 7 bytes of - // garbage. So much effort for that last single bit. - // The low values of each pair are for filter0. - s0 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s1 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s2 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s3 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - - // Shift to extract values for filter[5] - // If src[] is 0, this puts: - // 3 4 5 6 7 8 9 10 in s0_f5 - // Can't use vshr.u64 because it crosses the double word boundary. - s0_f5 = vext_u8(vget_low_u8(s0), vget_high_u8(s0), 5); - s1_f5 = vext_u8(vget_low_u8(s1), vget_high_u8(s1), 5); - s2_f5 = vext_u8(vget_low_u8(s2), vget_high_u8(s2), 5); - s3_f5 = vext_u8(vget_low_u8(s3), vget_high_u8(s3), 5); - - s01_f0 = vcombine_u8(vget_low_u8(s0), vget_low_u8(s1)); - s23_f0 = vcombine_u8(vget_low_u8(s2), vget_low_u8(s3)); - - s01_f5_q = vzip_u32(vreinterpret_u32_u8(s0_f5), vreinterpret_u32_u8(s1_f5)); - s23_f5_q = vzip_u32(vreinterpret_u32_u8(s2_f5), vreinterpret_u32_u8(s3_f5)); - d0123 = vmull_u8(vreinterpret_u8_u32(s01_f5_q.val[0]), filter5); - d4567 = vmull_u8(vreinterpret_u8_u32(s23_f5_q.val[0]), filter5); - - // Keep original src data as 64 bits to simplify shifting and extracting. - s01 = vreinterpretq_u64_u8(s01_f0); - s23 = vreinterpretq_u64_u8(s23_f0); - - // 3 4 5 6 * filter0 - filter_add_accumulate(s01_f0, s23_f0, filter0, &d0123, &d4567); - - // Shift over one to use -1, 0, 1, 2 for filter1 - // -1 0 1 2 * filter1 - filter_sub_accumulate(vreinterpretq_u8_u64(vshrq_n_u64(s01, 8)), - vreinterpretq_u8_u64(vshrq_n_u64(s23, 8)), filter1, - &d0123, &d4567); - - // 2 3 4 5 * filter4 - filter_sub_accumulate(vreinterpretq_u8_u64(vshrq_n_u64(s01, 32)), - vreinterpretq_u8_u64(vshrq_n_u64(s23, 32)), filter4, - &d0123, &d4567); - - // 0 1 2 3 * filter2 - filter_add_accumulate(vreinterpretq_u8_u64(vshrq_n_u64(s01, 16)), - vreinterpretq_u8_u64(vshrq_n_u64(s23, 16)), filter2, - &d0123, &d4567); - - // 1 2 3 4 * filter3 - s01_f3 = vshrq_n_u64(s01, 24); - s23_f3 = vshrq_n_u64(s23, 24); - s01_f3_q = vzip_u32(vreinterpret_u32_u64(vget_low_u64(s01_f3)), - vreinterpret_u32_u64(vget_high_u64(s01_f3))); - s23_f3_q = vzip_u32(vreinterpret_u32_u64(vget_low_u64(s23_f3)), - vreinterpret_u32_u64(vget_high_u64(s23_f3))); - // Accumulate into different registers so it can use saturated addition. - d0123_a = vmull_u8(vreinterpret_u8_u32(s01_f3_q.val[0]), filter3); - d4567_a = vmull_u8(vreinterpret_u8_u32(s23_f3_q.val[0]), filter3); - - d0123 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(d0123), vreinterpretq_s16_u16(d0123_a))); - d4567 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(d4567), vreinterpretq_s16_u16(d4567_a))); - - // Shift and narrow. - b0 = vqrshrn_n_u16(d0123, 7); - b2 = vqrshrn_n_u16(d4567, 7); - - if (yoffset == 0) { // firstpass_filter4x4_only - store4x4(dst_ptr, dst_pitch, b0, b2); - return; - } - - // Load additional context when doing both filters. - s0 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s1 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s2 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s3 = vld1q_u8(src_ptr); - src_ptr += src_pixels_per_line; - s4 = vld1q_u8(src_ptr); - - s0_f5 = vext_u8(vget_low_u8(s0), vget_high_u8(s0), 5); - s1_f5 = vext_u8(vget_low_u8(s1), vget_high_u8(s1), 5); - s2_f5 = vext_u8(vget_low_u8(s2), vget_high_u8(s2), 5); - s3_f5 = vext_u8(vget_low_u8(s3), vget_high_u8(s3), 5); - s4_f5 = vext_u8(vget_low_u8(s4), vget_high_u8(s4), 5); - - // 3 4 5 6 * filter0 - s01_f0 = vcombine_u8(vget_low_u8(s0), vget_low_u8(s1)); - s23_f0 = vcombine_u8(vget_low_u8(s2), vget_low_u8(s3)); - - s01_f5_q = vzip_u32(vreinterpret_u32_u8(s0_f5), vreinterpret_u32_u8(s1_f5)); - s23_f5_q = vzip_u32(vreinterpret_u32_u8(s2_f5), vreinterpret_u32_u8(s3_f5)); - // But this time instead of 16 pixels to filter, there are 20. So an extra - // run with a doubleword register. - d0123 = vmull_u8(vreinterpret_u8_u32(s01_f5_q.val[0]), filter5); - d4567 = vmull_u8(vreinterpret_u8_u32(s23_f5_q.val[0]), filter5); - d89 = vmull_u8(s4_f5, filter5); - - // Save a copy as u64 for shifting. - s01 = vreinterpretq_u64_u8(s01_f0); - s23 = vreinterpretq_u64_u8(s23_f0); - - filter_add_accumulate(s01_f0, s23_f0, filter0, &d0123, &d4567); - d89 = vmlal_u8(d89, vget_low_u8(s4), filter0); - - filter_sub_accumulate(vreinterpretq_u8_u64(vshrq_n_u64(s01, 8)), - vreinterpretq_u8_u64(vshrq_n_u64(s23, 8)), filter1, - &d0123, &d4567); - s4_f1 = vext_u8(vget_low_u8(s4), vget_high_u8(s4), 1); - d89 = vmlsl_u8(d89, s4_f1, filter1); - - filter_sub_accumulate(vreinterpretq_u8_u64(vshrq_n_u64(s01, 32)), - vreinterpretq_u8_u64(vshrq_n_u64(s23, 32)), filter4, - &d0123, &d4567); - s4_f4 = vext_u8(vget_low_u8(s4), vget_high_u8(s4), 4); - d89 = vmlsl_u8(d89, s4_f4, filter4); - - filter_add_accumulate(vreinterpretq_u8_u64(vshrq_n_u64(s01, 16)), - vreinterpretq_u8_u64(vshrq_n_u64(s23, 16)), filter2, - &d0123, &d4567); - s4_f2 = vext_u8(vget_low_u8(s4), vget_high_u8(s4), 2); - d89 = vmlal_u8(d89, s4_f2, filter2); - - s01_f3 = vshrq_n_u64(s01, 24); - s23_f3 = vshrq_n_u64(s23, 24); - s01_f3_q = vzip_u32(vreinterpret_u32_u64(vget_low_u64(s01_f3)), - vreinterpret_u32_u64(vget_high_u64(s01_f3))); - s23_f3_q = vzip_u32(vreinterpret_u32_u64(vget_low_u64(s23_f3)), - vreinterpret_u32_u64(vget_high_u64(s23_f3))); - s4_f3 = vext_u8(vget_low_u8(s4), vget_high_u8(s4), 3); - d0123_a = vmull_u8(vreinterpret_u8_u32(s01_f3_q.val[0]), filter3); - d4567_a = vmull_u8(vreinterpret_u8_u32(s23_f3_q.val[0]), filter3); - d89_a = vmull_u8(s4_f3, filter3); - - d0123 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(d0123), vreinterpretq_s16_u16(d0123_a))); - d4567 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(d4567), vreinterpretq_s16_u16(d4567_a))); - d89 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(d89), vreinterpretq_s16_u16(d89_a))); - - b4 = vqrshrn_n_u16(d0123, 7); - b6 = vqrshrn_n_u16(d4567, 7); - b8 = vqrshrn_n_u16(d89, 7); - - // Second pass: 4x4 - filter = vld1_u8(abs_filters[yoffset]); - filter0 = vdup_lane_u8(filter, 0); - filter1 = vdup_lane_u8(filter, 1); - filter2 = vdup_lane_u8(filter, 2); - filter3 = vdup_lane_u8(filter, 3); - filter4 = vdup_lane_u8(filter, 4); - filter5 = vdup_lane_u8(filter, 5); - - b1 = vext_u8(b0, b2, 4); - b3 = vext_u8(b2, b4, 4); - b5 = vext_u8(b4, b6, 4); - b7 = vext_u8(b6, b8, 4); - - c0 = vmull_u8(b0, filter0); - c1 = vmull_u8(b2, filter0); - c2 = vmull_u8(b5, filter5); - c3 = vmull_u8(b7, filter5); - - c0 = vmlsl_u8(c0, b4, filter4); - c1 = vmlsl_u8(c1, b6, filter4); - c2 = vmlsl_u8(c2, b1, filter1); - c3 = vmlsl_u8(c3, b3, filter1); - - c0 = vmlal_u8(c0, b2, filter2); - c1 = vmlal_u8(c1, b4, filter2); - c2 = vmlal_u8(c2, b3, filter3); - c3 = vmlal_u8(c3, b5, filter3); - - c0 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(c2), vreinterpretq_s16_u16(c0))); - c1 = vreinterpretq_u16_s16( - vqaddq_s16(vreinterpretq_s16_u16(c3), vreinterpretq_s16_u16(c1))); - - d0 = vqrshrn_n_u16(c0, 7); - d1 = vqrshrn_n_u16(c1, 7); - - store4x4(dst_ptr, dst_pitch, d0, d1); -} - void vp8_sixtap_predict8x4_neon(unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch) { diff --git a/vp8/common/rtcd_defs.pl b/vp8/common/rtcd_defs.pl index 063b9d5f5..b58f8e7af 100644 --- a/vp8/common/rtcd_defs.pl +++ b/vp8/common/rtcd_defs.pl @@ -163,15 +163,21 @@ if (vpx_config("CONFIG_POSTPROC") eq "yes") { # add_proto qw/void vp8_sixtap_predict16x16/, "unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch"; specialize qw/vp8_sixtap_predict16x16 mmx sse2 ssse3 neon dspr2 msa/; +$vp8_sixtap_predict16x16_dspr2=vp8_sixtap_predict16x16_dspr2; add_proto qw/void vp8_sixtap_predict8x8/, "unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch"; specialize qw/vp8_sixtap_predict8x8 mmx sse2 ssse3 neon dspr2 msa/; +$vp8_sixtap_predict8x8_dspr2=vp8_sixtap_predict8x8_dspr2; add_proto qw/void vp8_sixtap_predict8x4/, "unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch"; specialize qw/vp8_sixtap_predict8x4 mmx sse2 ssse3 neon dspr2 msa/; +$vp8_sixtap_predict8x4_dspr2=vp8_sixtap_predict8x4_dspr2; +# TODO(johannkoenig): Add neon implementation +# https://bugs.chromium.org/p/webm/issues/detail?id=1273 add_proto qw/void vp8_sixtap_predict4x4/, "unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch"; -specialize qw/vp8_sixtap_predict4x4 mmx ssse3 neon dspr2 msa/; +specialize qw/vp8_sixtap_predict4x4 mmx ssse3 dspr2 msa/; +$vp8_sixtap_predict4x4_dspr2=vp8_sixtap_predict4x4_dspr2; add_proto qw/void vp8_bilinear_predict16x16/, "unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch"; specialize qw/vp8_bilinear_predict16x16 mmx sse2 ssse3 neon msa/;