|  | /* | 
|  | *  Copyright 2011 The LibYuv Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS. All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "libyuv/row.h" | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | namespace libyuv { | 
|  | extern "C" { | 
|  | #endif | 
|  |  | 
|  | // This module is for GCC x86 and x64. | 
|  | #if !defined(LIBYUV_DISABLE_X86) && \ | 
|  | (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) | 
|  |  | 
|  | #if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3) | 
|  |  | 
|  | // Constants for ARGB | 
|  | static const uvec8 kARGBToY = {25u, 129u, 66u, 0u, 25u, 129u, 66u, 0u, | 
|  | 25u, 129u, 66u, 0u, 25u, 129u, 66u, 0u}; | 
|  |  | 
|  | // JPeg full range. | 
|  | static const uvec8 kARGBToYJ = {29u, 150u, 77u, 0u, 29u, 150u, 77u, 0u, | 
|  | 29u, 150u, 77u, 0u, 29u, 150u, 77u, 0u}; | 
|  |  | 
|  | static const uvec8 kRGBAToYJ = {0u, 29u, 150u, 77u, 0u, 29u, 150u, 77u, | 
|  | 0u, 29u, 150u, 77u, 0u, 29u, 150u, 77u}; | 
|  | #endif  // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3) | 
|  |  | 
|  | #if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3) | 
|  |  | 
|  | static const vec8 kARGBToU = {112, -74, -38, 0, 112, -74, -38, 0, | 
|  | 112, -74, -38, 0, 112, -74, -38, 0}; | 
|  |  | 
|  | static const vec8 kARGBToUJ = {127, -84, -43, 0, 127, -84, -43, 0, | 
|  | 127, -84, -43, 0, 127, -84, -43, 0}; | 
|  |  | 
|  | static const vec8 kARGBToV = {-18, -94, 112, 0, -18, -94, 112, 0, | 
|  | -18, -94, 112, 0, -18, -94, 112, 0}; | 
|  |  | 
|  | static const vec8 kARGBToVJ = {-20, -107, 127, 0, -20, -107, 127, 0, | 
|  | -20, -107, 127, 0, -20, -107, 127, 0}; | 
|  |  | 
|  | // Constants for BGRA | 
|  | static const uvec8 kBGRAToY = {0u, 66u, 129u, 25u, 0u, 66u, 129u, 25u, | 
|  | 0u, 66u, 129u, 25u, 0u, 66u, 129u, 25u}; | 
|  |  | 
|  | static const vec8 kBGRAToU = {0, -38, -74, 112, 0, -38, -74, 112, | 
|  | 0, -38, -74, 112, 0, -38, -74, 112}; | 
|  |  | 
|  | static const vec8 kBGRAToV = {0, 112, -94, -18, 0, 112, -94, -18, | 
|  | 0, 112, -94, -18, 0, 112, -94, -18}; | 
|  |  | 
|  | // Constants for ABGR | 
|  | static const uvec8 kABGRToY = {66u, 129u, 25u, 0u, 66u, 129u, 25u, 0u, | 
|  | 66u, 129u, 25u, 0u, 66u, 129u, 25u, 0u}; | 
|  |  | 
|  | static const vec8 kABGRToU = {-38, -74, 112, 0, -38, -74, 112, 0, | 
|  | -38, -74, 112, 0, -38, -74, 112, 0}; | 
|  |  | 
|  | static const vec8 kABGRToV = {112, -94, -18, 0, 112, -94, -18, 0, | 
|  | 112, -94, -18, 0, 112, -94, -18, 0}; | 
|  |  | 
|  | // Constants for RGBA. | 
|  | static const uvec8 kRGBAToY = {0u, 25u, 129u, 66u, 0u, 25u, 129u, 66u, | 
|  | 0u, 25u, 129u, 66u, 0u, 25u, 129u, 66u}; | 
|  |  | 
|  | static const vec8 kRGBAToU = {0, 112, -74, -38, 0, 112, -74, -38, | 
|  | 0, 112, -74, -38, 0, 112, -74, -38}; | 
|  |  | 
|  | static const vec8 kRGBAToV = {0, -18, -94, 112, 0, -18, -94, 112, | 
|  | 0, -18, -94, 112, 0, -18, -94, 112}; | 
|  |  | 
|  | static const uvec16 kAddY16 = {0x7e80u, 0x7e80u, 0x7e80u, 0x7e80u, | 
|  | 0x7e80u, 0x7e80u, 0x7e80u, 0x7e80u}; | 
|  |  | 
|  | static const uvec8 kAddUV128 = {128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; | 
|  |  | 
|  | static const uvec16 kSub128 = {0x8080u, 0x8080u, 0x8080u, 0x8080u, | 
|  | 0x8080u, 0x8080u, 0x8080u, 0x8080u}; | 
|  |  | 
|  | #endif  // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3) | 
|  |  | 
|  | #ifdef HAS_RGB24TOARGBROW_SSSE3 | 
|  |  | 
|  | // Shuffle table for converting RGB24 to ARGB. | 
|  | static const uvec8 kShuffleMaskRGB24ToARGB = { | 
|  | 0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u}; | 
|  |  | 
|  | // Shuffle table for converting RAW to ARGB. | 
|  | static const uvec8 kShuffleMaskRAWToARGB = {2u, 1u, 0u, 12u, 5u,  4u,  3u, 13u, | 
|  | 8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u}; | 
|  |  | 
|  | // Shuffle table for converting RAW to RGBA. | 
|  | static const uvec8 kShuffleMaskRAWToRGBA = {12u, 2u, 1u, 0u, 13u, 5u,  4u,  3u, | 
|  | 14u, 8u, 7u, 6u, 15u, 11u, 10u, 9u}; | 
|  |  | 
|  | // Shuffle table for converting RAW to RGB24.  First 8. | 
|  | static const uvec8 kShuffleMaskRAWToRGB24_0 = { | 
|  | 2u,   1u,   0u,   5u,   4u,   3u,   8u,   7u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; | 
|  |  | 
|  | // Shuffle table for converting RAW to RGB24.  Middle 8. | 
|  | static const uvec8 kShuffleMaskRAWToRGB24_1 = { | 
|  | 2u,   7u,   6u,   5u,   10u,  9u,   8u,   13u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; | 
|  |  | 
|  | // Shuffle table for converting RAW to RGB24.  Last 8. | 
|  | static const uvec8 kShuffleMaskRAWToRGB24_2 = { | 
|  | 8u,   7u,   12u,  11u,  10u,  15u,  14u,  13u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; | 
|  |  | 
|  | // Shuffle table for converting ARGB to RGB24. | 
|  | static const uvec8 kShuffleMaskARGBToRGB24 = { | 
|  | 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 10u, 12u, 13u, 14u, 128u, 128u, 128u, 128u}; | 
|  |  | 
|  | // Shuffle table for converting ARGB to RAW. | 
|  | static const uvec8 kShuffleMaskARGBToRAW = { | 
|  | 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 8u, 14u, 13u, 12u, 128u, 128u, 128u, 128u}; | 
|  |  | 
|  | // Shuffle table for converting ARGBToRGB24 for I422ToRGB24.  First 8 + next 4 | 
|  | static const uvec8 kShuffleMaskARGBToRGB24_0 = { | 
|  | 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u}; | 
|  |  | 
|  | // YUY2 shuf 16 Y to 32 Y. | 
|  | static const lvec8 kShuffleYUY2Y = {0,  0,  2,  2,  4,  4,  6,  6,  8,  8, 10, | 
|  | 10, 12, 12, 14, 14, 0,  0,  2,  2,  4, 4, | 
|  | 6,  6,  8,  8,  10, 10, 12, 12, 14, 14}; | 
|  |  | 
|  | // YUY2 shuf 8 UV to 16 UV. | 
|  | static const lvec8 kShuffleYUY2UV = {1,  3,  1,  3,  5,  7,  5,  7,  9,  11, 9, | 
|  | 11, 13, 15, 13, 15, 1,  3,  1,  3,  5,  7, | 
|  | 5,  7,  9,  11, 9,  11, 13, 15, 13, 15}; | 
|  |  | 
|  | // UYVY shuf 16 Y to 32 Y. | 
|  | static const lvec8 kShuffleUYVYY = {1,  1,  3,  3,  5,  5,  7,  7,  9,  9, 11, | 
|  | 11, 13, 13, 15, 15, 1,  1,  3,  3,  5, 5, | 
|  | 7,  7,  9,  9,  11, 11, 13, 13, 15, 15}; | 
|  |  | 
|  | // UYVY shuf 8 UV to 16 UV. | 
|  | static const lvec8 kShuffleUYVYUV = {0,  2,  0,  2,  4,  6,  4,  6,  8,  10, 8, | 
|  | 10, 12, 14, 12, 14, 0,  2,  0,  2,  4,  6, | 
|  | 4,  6,  8,  10, 8,  10, 12, 14, 12, 14}; | 
|  |  | 
|  | // NV21 shuf 8 VU to 16 UV. | 
|  | static const lvec8 kShuffleNV21 = { | 
|  | 1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6, | 
|  | 1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6, | 
|  | }; | 
|  | #endif  // HAS_RGB24TOARGBROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_J400TOARGBROW_SSE2 | 
|  | void J400ToARGBRow_SSE2(const uint8_t* src_y, uint8_t* dst_argb, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "pslld       $0x18,%%xmm5                  \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%0),%%xmm0                   \n" | 
|  | "lea         0x8(%0),%0                    \n" | 
|  | "punpcklbw   %%xmm0,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklwd   %%xmm0,%%xmm0                 \n" | 
|  | "punpckhwd   %%xmm1,%%xmm1                 \n" | 
|  | "por         %%xmm5,%%xmm0                 \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y),     // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | ::"memory", | 
|  | "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_J400TOARGBROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_RGB24TOARGBROW_SSSE3 | 
|  | void RGB24ToARGBRow_SSSE3(const uint8_t* src_rgb24, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n"  // 0xff000000 | 
|  | "pslld       $0x18,%%xmm5                  \n" | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm3               \n" | 
|  | "lea         0x30(%0),%0                   \n" | 
|  | "movdqa      %%xmm3,%%xmm2                 \n" | 
|  | "palignr     $0x8,%%xmm1,%%xmm2            \n" | 
|  | "pshufb      %%xmm4,%%xmm2                 \n" | 
|  | "por         %%xmm5,%%xmm2                 \n" | 
|  | "palignr     $0xc,%%xmm0,%%xmm1            \n" | 
|  | "pshufb      %%xmm4,%%xmm0                 \n" | 
|  | "movdqu      %%xmm2,0x20(%1)               \n" | 
|  | "por         %%xmm5,%%xmm0                 \n" | 
|  | "pshufb      %%xmm4,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "palignr     $0x4,%%xmm3,%%xmm3            \n" | 
|  | "pshufb      %%xmm4,%%xmm3                 \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "por         %%xmm5,%%xmm3                 \n" | 
|  | "movdqu      %%xmm3,0x30(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_rgb24),              // %0 | 
|  | "+r"(dst_argb),               // %1 | 
|  | "+r"(width)                   // %2 | 
|  | : "m"(kShuffleMaskRGB24ToARGB)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void RAWToARGBRow_SSSE3(const uint8_t* src_raw, uint8_t* dst_argb, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n"  // 0xff000000 | 
|  | "pslld       $0x18,%%xmm5                  \n" | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm3               \n" | 
|  | "lea         0x30(%0),%0                   \n" | 
|  | "movdqa      %%xmm3,%%xmm2                 \n" | 
|  | "palignr     $0x8,%%xmm1,%%xmm2            \n" | 
|  | "pshufb      %%xmm4,%%xmm2                 \n" | 
|  | "por         %%xmm5,%%xmm2                 \n" | 
|  | "palignr     $0xc,%%xmm0,%%xmm1            \n" | 
|  | "pshufb      %%xmm4,%%xmm0                 \n" | 
|  | "movdqu      %%xmm2,0x20(%1)               \n" | 
|  | "por         %%xmm5,%%xmm0                 \n" | 
|  | "pshufb      %%xmm4,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "palignr     $0x4,%%xmm3,%%xmm3            \n" | 
|  | "pshufb      %%xmm4,%%xmm3                 \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "por         %%xmm5,%%xmm3                 \n" | 
|  | "movdqu      %%xmm3,0x30(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_raw),              // %0 | 
|  | "+r"(dst_argb),             // %1 | 
|  | "+r"(width)                 // %2 | 
|  | : "m"(kShuffleMaskRAWToARGB)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | // Same code as RAWToARGB with different shuffler and A in low bits | 
|  | void RAWToRGBARow_SSSE3(const uint8_t* src_raw, uint8_t* dst_rgba, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n"  // 0x000000ff | 
|  | "psrld       $0x18,%%xmm5                  \n" | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm3               \n" | 
|  | "lea         0x30(%0),%0                   \n" | 
|  | "movdqa      %%xmm3,%%xmm2                 \n" | 
|  | "palignr     $0x8,%%xmm1,%%xmm2            \n" | 
|  | "pshufb      %%xmm4,%%xmm2                 \n" | 
|  | "por         %%xmm5,%%xmm2                 \n" | 
|  | "palignr     $0xc,%%xmm0,%%xmm1            \n" | 
|  | "pshufb      %%xmm4,%%xmm0                 \n" | 
|  | "movdqu      %%xmm2,0x20(%1)               \n" | 
|  | "por         %%xmm5,%%xmm0                 \n" | 
|  | "pshufb      %%xmm4,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "palignr     $0x4,%%xmm3,%%xmm3            \n" | 
|  | "pshufb      %%xmm4,%%xmm3                 \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "por         %%xmm5,%%xmm3                 \n" | 
|  | "movdqu      %%xmm3,0x30(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_raw),              // %0 | 
|  | "+r"(dst_rgba),             // %1 | 
|  | "+r"(width)                 // %2 | 
|  | : "m"(kShuffleMaskRAWToRGBA)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void RAWToRGB24Row_SSSE3(const uint8_t* src_raw, | 
|  | uint8_t* dst_rgb24, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm3                     \n" | 
|  | "movdqa      %4,%%xmm4                     \n" | 
|  | "movdqa      %5,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x4(%0),%%xmm1                \n" | 
|  | "movdqu      0x8(%0),%%xmm2                \n" | 
|  | "lea         0x18(%0),%0                   \n" | 
|  | "pshufb      %%xmm3,%%xmm0                 \n" | 
|  | "pshufb      %%xmm4,%%xmm1                 \n" | 
|  | "pshufb      %%xmm5,%%xmm2                 \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "movq        %%xmm1,0x8(%1)                \n" | 
|  | "movq        %%xmm2,0x10(%1)               \n" | 
|  | "lea         0x18(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_raw),                  // %0 | 
|  | "+r"(dst_rgb24),                // %1 | 
|  | "+r"(width)                     // %2 | 
|  | : "m"(kShuffleMaskRAWToRGB24_0),  // %3 | 
|  | "m"(kShuffleMaskRAWToRGB24_1),  // %4 | 
|  | "m"(kShuffleMaskRAWToRGB24_2)   // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void RGB565ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "mov         $0x1080108,%%eax              \n" | 
|  | "movd        %%eax,%%xmm5                  \n" | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "mov         $0x20802080,%%eax             \n" | 
|  | "movd        %%eax,%%xmm6                  \n" | 
|  | "pshufd      $0x0,%%xmm6,%%xmm6            \n" | 
|  | "pcmpeqb     %%xmm3,%%xmm3                 \n" | 
|  | "psllw       $0xb,%%xmm3                   \n" | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psllw       $0xa,%%xmm4                   \n" | 
|  | "psrlw       $0x5,%%xmm4                   \n" | 
|  | "pcmpeqb     %%xmm7,%%xmm7                 \n" | 
|  | "psllw       $0x8,%%xmm7                   \n" | 
|  | "sub         %0,%1                         \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "pand        %%xmm3,%%xmm1                 \n" | 
|  | "psllw       $0xb,%%xmm2                   \n" | 
|  | "pmulhuw     %%xmm5,%%xmm1                 \n" | 
|  | "pmulhuw     %%xmm5,%%xmm2                 \n" | 
|  | "psllw       $0x8,%%xmm1                   \n" | 
|  | "por         %%xmm2,%%xmm1                 \n" | 
|  | "pand        %%xmm4,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm6,%%xmm0                 \n" | 
|  | "por         %%xmm7,%%xmm0                 \n" | 
|  | "movdqa      %%xmm1,%%xmm2                 \n" | 
|  | "punpcklbw   %%xmm0,%%xmm1                 \n" | 
|  | "punpckhbw   %%xmm0,%%xmm2                 \n" | 
|  | "movdqu      %%xmm1,0x00(%1,%0,2)          \n" | 
|  | "movdqu      %%xmm2,0x10(%1,%0,2)          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", | 
|  | "xmm6", "xmm7"); | 
|  | } | 
|  |  | 
|  | void ARGB1555ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "mov         $0x1080108,%%eax              \n" | 
|  | "movd        %%eax,%%xmm5                  \n" | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "mov         $0x42004200,%%eax             \n" | 
|  | "movd        %%eax,%%xmm6                  \n" | 
|  | "pshufd      $0x0,%%xmm6,%%xmm6            \n" | 
|  | "pcmpeqb     %%xmm3,%%xmm3                 \n" | 
|  | "psllw       $0xb,%%xmm3                   \n" | 
|  | "movdqa      %%xmm3,%%xmm4                 \n" | 
|  | "psrlw       $0x6,%%xmm4                   \n" | 
|  | "pcmpeqb     %%xmm7,%%xmm7                 \n" | 
|  | "psllw       $0x8,%%xmm7                   \n" | 
|  | "sub         %0,%1                         \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "psllw       $0x1,%%xmm1                   \n" | 
|  | "psllw       $0xb,%%xmm2                   \n" | 
|  | "pand        %%xmm3,%%xmm1                 \n" | 
|  | "pmulhuw     %%xmm5,%%xmm2                 \n" | 
|  | "pmulhuw     %%xmm5,%%xmm1                 \n" | 
|  | "psllw       $0x8,%%xmm1                   \n" | 
|  | "por         %%xmm2,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "pand        %%xmm4,%%xmm0                 \n" | 
|  | "psraw       $0x8,%%xmm2                   \n" | 
|  | "pmulhuw     %%xmm6,%%xmm0                 \n" | 
|  | "pand        %%xmm7,%%xmm2                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqa      %%xmm1,%%xmm2                 \n" | 
|  | "punpcklbw   %%xmm0,%%xmm1                 \n" | 
|  | "punpckhbw   %%xmm0,%%xmm2                 \n" | 
|  | "movdqu      %%xmm1,0x00(%1,%0,2)          \n" | 
|  | "movdqu      %%xmm2,0x10(%1,%0,2)          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", | 
|  | "xmm6", "xmm7"); | 
|  | } | 
|  |  | 
|  | void ARGB4444ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "mov         $0xf0f0f0f,%%eax              \n" | 
|  | "movd        %%eax,%%xmm4                  \n" | 
|  | "pshufd      $0x0,%%xmm4,%%xmm4            \n" | 
|  | "movdqa      %%xmm4,%%xmm5                 \n" | 
|  | "pslld       $0x4,%%xmm5                   \n" | 
|  | "sub         %0,%1                         \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "pand        %%xmm4,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm2,%%xmm3                 \n" | 
|  | "psllw       $0x4,%%xmm1                   \n" | 
|  | "psrlw       $0x4,%%xmm3                   \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm3,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm2,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm2,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,0x00(%1,%0,2)          \n" | 
|  | "movdqu      %%xmm1,0x10(%1,%0,2)          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void ARGBToRGB24Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "movdqa      %3,%%xmm6                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x30(%0),%%xmm3               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "pshufb      %%xmm6,%%xmm0                 \n" | 
|  | "pshufb      %%xmm6,%%xmm1                 \n" | 
|  | "pshufb      %%xmm6,%%xmm2                 \n" | 
|  | "pshufb      %%xmm6,%%xmm3                 \n" | 
|  | "movdqa      %%xmm1,%%xmm4                 \n" | 
|  | "psrldq      $0x4,%%xmm1                   \n" | 
|  | "pslldq      $0xc,%%xmm4                   \n" | 
|  | "movdqa      %%xmm2,%%xmm5                 \n" | 
|  | "por         %%xmm4,%%xmm0                 \n" | 
|  | "pslldq      $0x8,%%xmm5                   \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "psrldq      $0x8,%%xmm2                   \n" | 
|  | "pslldq      $0x4,%%xmm3                   \n" | 
|  | "por         %%xmm3,%%xmm2                 \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "movdqu      %%xmm2,0x20(%1)               \n" | 
|  | "lea         0x30(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),                    // %0 | 
|  | "+r"(dst),                    // %1 | 
|  | "+r"(width)                   // %2 | 
|  | : "m"(kShuffleMaskARGBToRGB24)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  |  | 
|  | void ARGBToRAWRow_SSSE3(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "movdqa      %3,%%xmm6                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x30(%0),%%xmm3               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "pshufb      %%xmm6,%%xmm0                 \n" | 
|  | "pshufb      %%xmm6,%%xmm1                 \n" | 
|  | "pshufb      %%xmm6,%%xmm2                 \n" | 
|  | "pshufb      %%xmm6,%%xmm3                 \n" | 
|  | "movdqa      %%xmm1,%%xmm4                 \n" | 
|  | "psrldq      $0x4,%%xmm1                   \n" | 
|  | "pslldq      $0xc,%%xmm4                   \n" | 
|  | "movdqa      %%xmm2,%%xmm5                 \n" | 
|  | "por         %%xmm4,%%xmm0                 \n" | 
|  | "pslldq      $0x8,%%xmm5                   \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "psrldq      $0x8,%%xmm2                   \n" | 
|  | "pslldq      $0x4,%%xmm3                   \n" | 
|  | "por         %%xmm3,%%xmm2                 \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "movdqu      %%xmm2,0x20(%1)               \n" | 
|  | "lea         0x30(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),                  // %0 | 
|  | "+r"(dst),                  // %1 | 
|  | "+r"(width)                 // %2 | 
|  | : "m"(kShuffleMaskARGBToRAW)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  |  | 
|  | #ifdef HAS_ARGBTORGB24ROW_AVX2 | 
|  | // vpermd for 12+12 to 24 | 
|  | static const lvec32 kPermdRGB24_AVX = {0, 1, 2, 4, 5, 6, 3, 7}; | 
|  |  | 
|  | void ARGBToRGB24Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm6                  \n" | 
|  | "vmovdqa     %4,%%ymm7                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vmovdqu     0x40(%0),%%ymm2               \n" | 
|  | "vmovdqu     0x60(%0),%%ymm3               \n" | 
|  | "lea         0x80(%0),%0                   \n" | 
|  | "vpshufb     %%ymm6,%%ymm0,%%ymm0          \n"  // xxx0yyy0 | 
|  | "vpshufb     %%ymm6,%%ymm1,%%ymm1          \n" | 
|  | "vpshufb     %%ymm6,%%ymm2,%%ymm2          \n" | 
|  | "vpshufb     %%ymm6,%%ymm3,%%ymm3          \n" | 
|  | "vpermd      %%ymm0,%%ymm7,%%ymm0          \n"  // pack to 24 bytes | 
|  | "vpermd      %%ymm1,%%ymm7,%%ymm1          \n" | 
|  | "vpermd      %%ymm2,%%ymm7,%%ymm2          \n" | 
|  | "vpermd      %%ymm3,%%ymm7,%%ymm3          \n" | 
|  | "vpermq      $0x3f,%%ymm1,%%ymm4           \n"  // combine 24 + 8 | 
|  | "vpor        %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vpermq      $0xf9,%%ymm1,%%ymm1           \n"  // combine 16 + 16 | 
|  | "vpermq      $0x4f,%%ymm2,%%ymm4           \n" | 
|  | "vpor        %%ymm4,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "vpermq      $0xfe,%%ymm2,%%ymm2           \n"  // combine 8 + 24 | 
|  | "vpermq      $0x93,%%ymm3,%%ymm3           \n" | 
|  | "vpor        %%ymm3,%%ymm2,%%ymm2          \n" | 
|  | "vmovdqu     %%ymm2,0x40(%1)               \n" | 
|  | "lea         0x60(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),                     // %0 | 
|  | "+r"(dst),                     // %1 | 
|  | "+r"(width)                    // %2 | 
|  | : "m"(kShuffleMaskARGBToRGB24),  // %3 | 
|  | "m"(kPermdRGB24_AVX)           // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef HAS_ARGBTORGB24ROW_AVX512VBMI | 
|  | // Shuffle table for converting ARGBToRGB24 | 
|  | static const ulvec8 kPermARGBToRGB24_0 = { | 
|  | 0u,  1u,  2u,  4u,  5u,  6u,  8u,  9u,  10u, 12u, 13u, | 
|  | 14u, 16u, 17u, 18u, 20u, 21u, 22u, 24u, 25u, 26u, 28u, | 
|  | 29u, 30u, 32u, 33u, 34u, 36u, 37u, 38u, 40u, 41u}; | 
|  | static const ulvec8 kPermARGBToRGB24_1 = { | 
|  | 10u, 12u, 13u, 14u, 16u, 17u, 18u, 20u, 21u, 22u, 24u, | 
|  | 25u, 26u, 28u, 29u, 30u, 32u, 33u, 34u, 36u, 37u, 38u, | 
|  | 40u, 41u, 42u, 44u, 45u, 46u, 48u, 49u, 50u, 52u}; | 
|  | static const ulvec8 kPermARGBToRGB24_2 = { | 
|  | 21u, 22u, 24u, 25u, 26u, 28u, 29u, 30u, 32u, 33u, 34u, | 
|  | 36u, 37u, 38u, 40u, 41u, 42u, 44u, 45u, 46u, 48u, 49u, | 
|  | 50u, 52u, 53u, 54u, 56u, 57u, 58u, 60u, 61u, 62u}; | 
|  |  | 
|  | void ARGBToRGB24Row_AVX512VBMI(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vmovdqa     %3,%%ymm5                     \n" | 
|  | "vmovdqa     %4,%%ymm6                     \n" | 
|  | "vmovdqa     %5,%%ymm7                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vmovdqu     0x40(%0),%%ymm2               \n" | 
|  | "vmovdqu     0x60(%0),%%ymm3               \n" | 
|  | "lea         0x80(%0),%0                   \n" | 
|  | "vpermt2b    %%ymm1,%%ymm5,%%ymm0          \n" | 
|  | "vpermt2b    %%ymm2,%%ymm6,%%ymm1          \n" | 
|  | "vpermt2b    %%ymm3,%%ymm7,%%ymm2          \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "vmovdqu     %%ymm2,0x40(%1)               \n" | 
|  | "lea         0x60(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),                // %0 | 
|  | "+r"(dst),                // %1 | 
|  | "+r"(width)               // %2 | 
|  | : "m"(kPermARGBToRGB24_0),  // %3 | 
|  | "m"(kPermARGBToRGB24_1),  // %4 | 
|  | "m"(kPermARGBToRGB24_2)   // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5", "xmm6", "xmm7"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef HAS_ARGBTORAWROW_AVX2 | 
|  | void ARGBToRAWRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm6                  \n" | 
|  | "vmovdqa     %4,%%ymm7                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vmovdqu     0x40(%0),%%ymm2               \n" | 
|  | "vmovdqu     0x60(%0),%%ymm3               \n" | 
|  | "lea         0x80(%0),%0                   \n" | 
|  | "vpshufb     %%ymm6,%%ymm0,%%ymm0          \n"  // xxx0yyy0 | 
|  | "vpshufb     %%ymm6,%%ymm1,%%ymm1          \n" | 
|  | "vpshufb     %%ymm6,%%ymm2,%%ymm2          \n" | 
|  | "vpshufb     %%ymm6,%%ymm3,%%ymm3          \n" | 
|  | "vpermd      %%ymm0,%%ymm7,%%ymm0          \n"  // pack to 24 bytes | 
|  | "vpermd      %%ymm1,%%ymm7,%%ymm1          \n" | 
|  | "vpermd      %%ymm2,%%ymm7,%%ymm2          \n" | 
|  | "vpermd      %%ymm3,%%ymm7,%%ymm3          \n" | 
|  | "vpermq      $0x3f,%%ymm1,%%ymm4           \n"  // combine 24 + 8 | 
|  | "vpor        %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vpermq      $0xf9,%%ymm1,%%ymm1           \n"  // combine 16 + 16 | 
|  | "vpermq      $0x4f,%%ymm2,%%ymm4           \n" | 
|  | "vpor        %%ymm4,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "vpermq      $0xfe,%%ymm2,%%ymm2           \n"  // combine 8 + 24 | 
|  | "vpermq      $0x93,%%ymm3,%%ymm3           \n" | 
|  | "vpor        %%ymm3,%%ymm2,%%ymm2          \n" | 
|  | "vmovdqu     %%ymm2,0x40(%1)               \n" | 
|  | "lea         0x60(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),                   // %0 | 
|  | "+r"(dst),                   // %1 | 
|  | "+r"(width)                  // %2 | 
|  | : "m"(kShuffleMaskARGBToRAW),  // %3 | 
|  | "m"(kPermdRGB24_AVX)         // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | void ARGBToRGB565Row_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm3,%%xmm3                 \n" | 
|  | "psrld       $0x1b,%%xmm3                  \n" | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psrld       $0x1a,%%xmm4                  \n" | 
|  | "pslld       $0x5,%%xmm4                   \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "pslld       $0xb,%%xmm5                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "pslld       $0x8,%%xmm0                   \n" | 
|  | "psrld       $0x3,%%xmm1                   \n" | 
|  | "psrld       $0x5,%%xmm2                   \n" | 
|  | "psrad       $0x10,%%xmm0                  \n" | 
|  | "pand        %%xmm3,%%xmm1                 \n" | 
|  | "pand        %%xmm4,%%xmm2                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm1                 \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "packssdw    %%xmm0,%%xmm0                 \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | ::"memory", | 
|  | "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void ARGBToRGB565DitherRow_SSE2(const uint8_t* src, | 
|  | uint8_t* dst, | 
|  | const uint32_t dither4, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movd        %3,%%xmm6                     \n" | 
|  | "punpcklbw   %%xmm6,%%xmm6                 \n" | 
|  | "movdqa      %%xmm6,%%xmm7                 \n" | 
|  | "punpcklwd   %%xmm6,%%xmm6                 \n" | 
|  | "punpckhwd   %%xmm7,%%xmm7                 \n" | 
|  | "pcmpeqb     %%xmm3,%%xmm3                 \n" | 
|  | "psrld       $0x1b,%%xmm3                  \n" | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psrld       $0x1a,%%xmm4                  \n" | 
|  | "pslld       $0x5,%%xmm4                   \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "pslld       $0xb,%%xmm5                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "paddusb     %%xmm6,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "pslld       $0x8,%%xmm0                   \n" | 
|  | "psrld       $0x3,%%xmm1                   \n" | 
|  | "psrld       $0x5,%%xmm2                   \n" | 
|  | "psrad       $0x10,%%xmm0                  \n" | 
|  | "pand        %%xmm3,%%xmm1                 \n" | 
|  | "pand        %%xmm4,%%xmm2                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm1                 \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "packssdw    %%xmm0,%%xmm0                 \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),    // %0 | 
|  | "+r"(dst),    // %1 | 
|  | "+r"(width)   // %2 | 
|  | : "m"(dither4)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  |  | 
|  | #ifdef HAS_ARGBTORGB565DITHERROW_AVX2 | 
|  | void ARGBToRGB565DitherRow_AVX2(const uint8_t* src, | 
|  | uint8_t* dst, | 
|  | const uint32_t dither4, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastss %3,%%xmm6                    \n" | 
|  | "vpunpcklbw  %%xmm6,%%xmm6,%%xmm6          \n" | 
|  | "vpermq      $0xd8,%%ymm6,%%ymm6           \n" | 
|  | "vpunpcklwd  %%ymm6,%%ymm6,%%ymm6          \n" | 
|  | "vpcmpeqb    %%ymm3,%%ymm3,%%ymm3          \n" | 
|  | "vpsrld      $0x1b,%%ymm3,%%ymm3           \n" | 
|  | "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n" | 
|  | "vpsrld      $0x1a,%%ymm4,%%ymm4           \n" | 
|  | "vpslld      $0x5,%%ymm4,%%ymm4            \n" | 
|  | "vpslld      $0xb,%%ymm3,%%ymm5            \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vpaddusb    %%ymm6,%%ymm0,%%ymm0          \n" | 
|  | "vpsrld      $0x5,%%ymm0,%%ymm2            \n" | 
|  | "vpsrld      $0x3,%%ymm0,%%ymm1            \n" | 
|  | "vpsrld      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpand       %%ymm4,%%ymm2,%%ymm2          \n" | 
|  | "vpand       %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpor        %%ymm2,%%ymm1,%%ymm1          \n" | 
|  | "vpor        %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpackusdw   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "vmovdqu     %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),    // %0 | 
|  | "+r"(dst),    // %1 | 
|  | "+r"(width)   // %2 | 
|  | : "m"(dither4)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTORGB565DITHERROW_AVX2 | 
|  |  | 
|  | void ARGBToARGB1555Row_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psrld       $0x1b,%%xmm4                  \n" | 
|  | "movdqa      %%xmm4,%%xmm5                 \n" | 
|  | "pslld       $0x5,%%xmm5                   \n" | 
|  | "movdqa      %%xmm4,%%xmm6                 \n" | 
|  | "pslld       $0xa,%%xmm6                   \n" | 
|  | "pcmpeqb     %%xmm7,%%xmm7                 \n" | 
|  | "pslld       $0xf,%%xmm7                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm3                 \n" | 
|  | "psrad       $0x10,%%xmm0                  \n" | 
|  | "psrld       $0x3,%%xmm1                   \n" | 
|  | "psrld       $0x6,%%xmm2                   \n" | 
|  | "psrld       $0x9,%%xmm3                   \n" | 
|  | "pand        %%xmm7,%%xmm0                 \n" | 
|  | "pand        %%xmm4,%%xmm1                 \n" | 
|  | "pand        %%xmm5,%%xmm2                 \n" | 
|  | "pand        %%xmm6,%%xmm3                 \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm3,%%xmm2                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "packssdw    %%xmm0,%%xmm0                 \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | ::"memory", | 
|  | "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"); | 
|  | } | 
|  |  | 
|  | void ARGBToARGB4444Row_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psllw       $0xc,%%xmm4                   \n" | 
|  | "movdqa      %%xmm4,%%xmm3                 \n" | 
|  | "psrlw       $0x8,%%xmm3                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pand        %%xmm3,%%xmm0                 \n" | 
|  | "pand        %%xmm4,%%xmm1                 \n" | 
|  | "psrlq       $0x4,%%xmm0                   \n" | 
|  | "psrlq       $0x8,%%xmm1                   \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | ::"memory", | 
|  | "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); | 
|  | } | 
|  | #endif  // HAS_RGB24TOARGBROW_SSSE3 | 
|  |  | 
|  | /* | 
|  |  | 
|  | ARGBToAR30Row: | 
|  |  | 
|  | Red Blue | 
|  | With the 8 bit value in the upper bits of a short, vpmulhuw by (1024+4) will | 
|  | produce a 10 bit value in the low 10 bits of each 16 bit value. This is whats | 
|  | wanted for the blue channel. The red needs to be shifted 4 left, so multiply by | 
|  | (1024+4)*16 for red. | 
|  |  | 
|  | Alpha Green | 
|  | Alpha and Green are already in the high bits so vpand can zero out the other | 
|  | bits, keeping just 2 upper bits of alpha and 8 bit green. The same multiplier | 
|  | could be used for Green - (1024+4) putting the 10 bit green in the lsb.  Alpha | 
|  | would be a simple multiplier to shift it into position.  It wants a gap of 10 | 
|  | above the green.  Green is 10 bits, so there are 6 bits in the low short.  4 | 
|  | more are needed, so a multiplier of 4 gets the 2 bits into the upper 16 bits, | 
|  | and then a shift of 4 is a multiply of 16, so (4*16) = 64.  Then shift the | 
|  | result left 10 to position the A and G channels. | 
|  | */ | 
|  |  | 
|  | // Shuffle table for converting RAW to RGB24.  Last 8. | 
|  | static const uvec8 kShuffleRB30 = {128u, 0u, 128u, 2u,  128u, 4u,  128u, 6u, | 
|  | 128u, 8u, 128u, 10u, 128u, 12u, 128u, 14u}; | 
|  |  | 
|  | static const uvec8 kShuffleBR30 = {128u, 2u,  128u, 0u, 128u, 6u,  128u, 4u, | 
|  | 128u, 10u, 128u, 8u, 128u, 14u, 128u, 12u}; | 
|  |  | 
|  | static const uint32_t kMulRB10 = 1028 * 16 * 65536 + 1028; | 
|  | static const uint32_t kMaskRB10 = 0x3ff003ff; | 
|  | static const uint32_t kMaskAG10 = 0xc000ff00; | 
|  | static const uint32_t kMulAG10 = 64 * 65536 + 1028; | 
|  |  | 
|  | void ARGBToAR30Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm2                     \n"  // shuffler for RB | 
|  | "movd        %4,%%xmm3                     \n"  // multipler for RB | 
|  | "movd        %5,%%xmm4                     \n"  // mask for R10 B10 | 
|  | "movd        %6,%%xmm5                     \n"  // mask for AG | 
|  | "movd        %7,%%xmm6                     \n"  // multipler for AG | 
|  | "pshufd      $0x0,%%xmm3,%%xmm3            \n" | 
|  | "pshufd      $0x0,%%xmm4,%%xmm4            \n" | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "pshufd      $0x0,%%xmm6,%%xmm6            \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n"  // fetch 4 ARGB pixels | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pshufb      %%xmm2,%%xmm1                 \n"  // R0B0 | 
|  | "pand        %%xmm5,%%xmm0                 \n"  // A0G0 | 
|  | "pmulhuw     %%xmm3,%%xmm1                 \n"  // X2 R16 X4  B10 | 
|  | "pmulhuw     %%xmm6,%%xmm0                 \n"  // X10 A2 X10 G10 | 
|  | "pand        %%xmm4,%%xmm1                 \n"  // X2 R10 X10 B10 | 
|  | "pslld       $10,%%xmm0                    \n"  // A2 x10 G10 x10 | 
|  | "por         %%xmm1,%%xmm0                 \n"  // A2 R10 G10 B10 | 
|  | "movdqu      %%xmm0,(%1,%0)                \n"  // store 4 AR30 pixels | 
|  | "add         $0x10,%0                      \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | : "+r"(src),          // %0 | 
|  | "+r"(dst),          // %1 | 
|  | "+r"(width)         // %2 | 
|  | : "m"(kShuffleRB30),  // %3 | 
|  | "m"(kMulRB10),      // %4 | 
|  | "m"(kMaskRB10),     // %5 | 
|  | "m"(kMaskAG10),     // %6 | 
|  | "m"(kMulAG10)       // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  |  | 
|  | void ABGRToAR30Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm2                     \n"  // shuffler for RB | 
|  | "movd        %4,%%xmm3                     \n"  // multipler for RB | 
|  | "movd        %5,%%xmm4                     \n"  // mask for R10 B10 | 
|  | "movd        %6,%%xmm5                     \n"  // mask for AG | 
|  | "movd        %7,%%xmm6                     \n"  // multipler for AG | 
|  | "pshufd      $0x0,%%xmm3,%%xmm3            \n" | 
|  | "pshufd      $0x0,%%xmm4,%%xmm4            \n" | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "pshufd      $0x0,%%xmm6,%%xmm6            \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n"  // fetch 4 ABGR pixels | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pshufb      %%xmm2,%%xmm1                 \n"  // R0B0 | 
|  | "pand        %%xmm5,%%xmm0                 \n"  // A0G0 | 
|  | "pmulhuw     %%xmm3,%%xmm1                 \n"  // X2 R16 X4  B10 | 
|  | "pmulhuw     %%xmm6,%%xmm0                 \n"  // X10 A2 X10 G10 | 
|  | "pand        %%xmm4,%%xmm1                 \n"  // X2 R10 X10 B10 | 
|  | "pslld       $10,%%xmm0                    \n"  // A2 x10 G10 x10 | 
|  | "por         %%xmm1,%%xmm0                 \n"  // A2 R10 G10 B10 | 
|  | "movdqu      %%xmm0,(%1,%0)                \n"  // store 4 AR30 pixels | 
|  | "add         $0x10,%0                      \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | : "+r"(src),          // %0 | 
|  | "+r"(dst),          // %1 | 
|  | "+r"(width)         // %2 | 
|  | : "m"(kShuffleBR30),  // %3  reversed shuffler | 
|  | "m"(kMulRB10),      // %4 | 
|  | "m"(kMaskRB10),     // %5 | 
|  | "m"(kMaskAG10),     // %6 | 
|  | "m"(kMulAG10)       // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  |  | 
|  | #ifdef HAS_ARGBTOAR30ROW_AVX2 | 
|  | void ARGBToAR30Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm2                  \n"  // shuffler for RB | 
|  | "vbroadcastss %4,%%ymm3                    \n"  // multipler for RB | 
|  | "vbroadcastss %5,%%ymm4                    \n"  // mask for R10 B10 | 
|  | "vbroadcastss %6,%%ymm5                    \n"  // mask for AG | 
|  | "vbroadcastss %7,%%ymm6                    \n"  // multipler for AG | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n"  // fetch 8 ARGB pixels | 
|  | "vpshufb     %%ymm2,%%ymm0,%%ymm1          \n"  // R0B0 | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n"  // A0G0 | 
|  | "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n"  // X2 R16 X4  B10 | 
|  | "vpmulhuw    %%ymm6,%%ymm0,%%ymm0          \n"  // X10 A2 X10 G10 | 
|  | "vpand       %%ymm4,%%ymm1,%%ymm1          \n"  // X2 R10 X10 B10 | 
|  | "vpslld      $10,%%ymm0,%%ymm0             \n"  // A2 x10 G10 x10 | 
|  | "vpor        %%ymm1,%%ymm0,%%ymm0          \n"  // A2 R10 G10 B10 | 
|  | "vmovdqu     %%ymm0,(%1,%0)                \n"  // store 8 AR30 pixels | 
|  | "add         $0x20,%0                      \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  |  | 
|  | : "+r"(src),          // %0 | 
|  | "+r"(dst),          // %1 | 
|  | "+r"(width)         // %2 | 
|  | : "m"(kShuffleRB30),  // %3 | 
|  | "m"(kMulRB10),      // %4 | 
|  | "m"(kMaskRB10),     // %5 | 
|  | "m"(kMaskAG10),     // %6 | 
|  | "m"(kMulAG10)       // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef HAS_ABGRTOAR30ROW_AVX2 | 
|  | void ABGRToAR30Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm2                  \n"  // shuffler for RB | 
|  | "vbroadcastss %4,%%ymm3                    \n"  // multipler for RB | 
|  | "vbroadcastss %5,%%ymm4                    \n"  // mask for R10 B10 | 
|  | "vbroadcastss %6,%%ymm5                    \n"  // mask for AG | 
|  | "vbroadcastss %7,%%ymm6                    \n"  // multipler for AG | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n"  // fetch 8 ABGR pixels | 
|  | "vpshufb     %%ymm2,%%ymm0,%%ymm1          \n"  // R0B0 | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n"  // A0G0 | 
|  | "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n"  // X2 R16 X4  B10 | 
|  | "vpmulhuw    %%ymm6,%%ymm0,%%ymm0          \n"  // X10 A2 X10 G10 | 
|  | "vpand       %%ymm4,%%ymm1,%%ymm1          \n"  // X2 R10 X10 B10 | 
|  | "vpslld      $10,%%ymm0,%%ymm0             \n"  // A2 x10 G10 x10 | 
|  | "vpor        %%ymm1,%%ymm0,%%ymm0          \n"  // A2 R10 G10 B10 | 
|  | "vmovdqu     %%ymm0,(%1,%0)                \n"  // store 8 AR30 pixels | 
|  | "add         $0x20,%0                      \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  |  | 
|  | : "+r"(src),          // %0 | 
|  | "+r"(dst),          // %1 | 
|  | "+r"(width)         // %2 | 
|  | : "m"(kShuffleBR30),  // %3  reversed shuffler | 
|  | "m"(kMulRB10),      // %4 | 
|  | "m"(kMaskRB10),     // %5 | 
|  | "m"(kMaskAG10),     // %6 | 
|  | "m"(kMulAG10)       // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // clang-format off | 
|  |  | 
|  | // TODO(mraptis): Consider passing R, G, B multipliers as parameter. | 
|  | // round parameter is register containing value to add before shift. | 
|  | #define RGBTOY(round)                            \ | 
|  | "1:                                        \n" \ | 
|  | "movdqu    (%0),%%xmm0                     \n" \ | 
|  | "movdqu    0x10(%0),%%xmm1                 \n" \ | 
|  | "movdqu    0x20(%0),%%xmm2                 \n" \ | 
|  | "movdqu    0x30(%0),%%xmm3                 \n" \ | 
|  | "psubb     %%xmm5,%%xmm0                   \n" \ | 
|  | "psubb     %%xmm5,%%xmm1                   \n" \ | 
|  | "psubb     %%xmm5,%%xmm2                   \n" \ | 
|  | "psubb     %%xmm5,%%xmm3                   \n" \ | 
|  | "movdqu    %%xmm4,%%xmm6                   \n" \ | 
|  | "pmaddubsw %%xmm0,%%xmm6                   \n" \ | 
|  | "movdqu    %%xmm4,%%xmm0                   \n" \ | 
|  | "pmaddubsw %%xmm1,%%xmm0                   \n" \ | 
|  | "movdqu    %%xmm4,%%xmm1                   \n" \ | 
|  | "pmaddubsw %%xmm2,%%xmm1                   \n" \ | 
|  | "movdqu    %%xmm4,%%xmm2                   \n" \ | 
|  | "pmaddubsw %%xmm3,%%xmm2                   \n" \ | 
|  | "lea       0x40(%0),%0                     \n" \ | 
|  | "phaddw    %%xmm0,%%xmm6                   \n" \ | 
|  | "phaddw    %%xmm2,%%xmm1                   \n" \ | 
|  | "prefetcht0 1280(%0)                       \n" \ | 
|  | "paddw     %%" #round ",%%xmm6             \n" \ | 
|  | "paddw     %%" #round ",%%xmm1             \n" \ | 
|  | "psrlw     $0x8,%%xmm6                     \n" \ | 
|  | "psrlw     $0x8,%%xmm1                     \n" \ | 
|  | "packuswb  %%xmm1,%%xmm6                   \n" \ | 
|  | "movdqu    %%xmm6,(%1)                     \n" \ | 
|  | "lea       0x10(%1),%1                     \n" \ | 
|  | "sub       $0x10,%2                        \n" \ | 
|  | "jg        1b                              \n" | 
|  |  | 
|  | #define RGBTOY_AVX2(round)                                       \ | 
|  | "1:                                        \n"                 \ | 
|  | "vmovdqu    (%0),%%ymm0                    \n"                 \ | 
|  | "vmovdqu    0x20(%0),%%ymm1                \n"                 \ | 
|  | "vmovdqu    0x40(%0),%%ymm2                \n"                 \ | 
|  | "vmovdqu    0x60(%0),%%ymm3                \n"                 \ | 
|  | "vpsubb     %%ymm5, %%ymm0, %%ymm0         \n"                 \ | 
|  | "vpsubb     %%ymm5, %%ymm1, %%ymm1         \n"                 \ | 
|  | "vpsubb     %%ymm5, %%ymm2, %%ymm2         \n"                 \ | 
|  | "vpsubb     %%ymm5, %%ymm3, %%ymm3         \n"                 \ | 
|  | "vpmaddubsw %%ymm0,%%ymm4,%%ymm0           \n"                 \ | 
|  | "vpmaddubsw %%ymm1,%%ymm4,%%ymm1           \n"                 \ | 
|  | "vpmaddubsw %%ymm2,%%ymm4,%%ymm2           \n"                 \ | 
|  | "vpmaddubsw %%ymm3,%%ymm4,%%ymm3           \n"                 \ | 
|  | "lea       0x80(%0),%0                     \n"                 \ | 
|  | "vphaddw    %%ymm1,%%ymm0,%%ymm0           \n" /* mutates. */  \ | 
|  | "vphaddw    %%ymm3,%%ymm2,%%ymm2           \n"                 \ | 
|  | "prefetcht0 1280(%0)                       \n"                 \ | 
|  | "vpaddw     %%" #round ",%%ymm0,%%ymm0     \n" /* Add .5 for rounding. */             \ | 
|  | "vpaddw     %%" #round ",%%ymm2,%%ymm2     \n" \ | 
|  | "vpsrlw     $0x8,%%ymm0,%%ymm0             \n"                 \ | 
|  | "vpsrlw     $0x8,%%ymm2,%%ymm2             \n"                 \ | 
|  | "vpackuswb  %%ymm2,%%ymm0,%%ymm0           \n" /* mutates. */  \ | 
|  | "vpermd     %%ymm0,%%ymm6,%%ymm0           \n" /* unmutate. */ \ | 
|  | "vmovdqu    %%ymm0,(%1)                    \n"                 \ | 
|  | "lea       0x20(%1),%1                     \n"                 \ | 
|  | "sub       $0x20,%2                        \n"                 \ | 
|  | "jg        1b                              \n"                 \ | 
|  | "vzeroupper                                \n" | 
|  |  | 
|  | // clang-format on | 
|  |  | 
|  | #ifdef HAS_ARGBTOYROW_SSSE3 | 
|  | // Convert 16 ARGB pixels (64 bytes) to 16 Y values. | 
|  | void ARGBToYRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  | "movdqa      %5,%%xmm7                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY(xmm7) | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kARGBToY),   // %3 | 
|  | "m"(kSub128),    // %4 | 
|  | "m"(kAddY16)     // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOYROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBTOYJROW_SSSE3 | 
|  | // Convert 16 ARGB pixels (64 bytes) to 16 YJ values. | 
|  | // Same as ARGBToYRow but different coefficients, no add 16. | 
|  | void ARGBToYJRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY(xmm5) | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kARGBToYJ),  // %3 | 
|  | "m"(kSub128)     // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOYJROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_RGBATOYJROW_SSSE3 | 
|  | // Convert 16 ARGB pixels (64 bytes) to 16 YJ values. | 
|  | // Same as ARGBToYRow but different coefficients, no add 16. | 
|  | void RGBAToYJRow_SSSE3(const uint8_t* src_rgba, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY(xmm5) | 
|  | : "+r"(src_rgba),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kRGBAToYJ),  // %3 | 
|  | "m"(kSub128)     // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_RGBATOYJROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBTOYROW_AVX2 | 
|  | // vpermd for vphaddw + vpackuswb vpermd. | 
|  | static const lvec32 kPermdARGBToY_AVX = {0, 4, 1, 5, 2, 6, 3, 7}; | 
|  |  | 
|  | // Convert 32 ARGB pixels (128 bytes) to 32 Y values. | 
|  | void ARGBToYRow_AVX2(const uint8_t* src_argb, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm4                  \n" | 
|  | "vbroadcastf128 %4,%%ymm5                  \n" | 
|  | "vbroadcastf128 %5,%%ymm7                  \n" | 
|  | "vmovdqu     %6,%%ymm6                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY_AVX2(ymm7) | 
|  | : "+r"(src_argb),         // %0 | 
|  | "+r"(dst_y),            // %1 | 
|  | "+r"(width)             // %2 | 
|  | : "m"(kARGBToY),          // %3 | 
|  | "m"(kSub128),           // %4 | 
|  | "m"(kAddY16),           // %5 | 
|  | "m"(kPermdARGBToY_AVX)  // %6 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOYROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ABGRTOYROW_AVX2 | 
|  | // Convert 32 ABGR pixels (128 bytes) to 32 Y values. | 
|  | void ABGRToYRow_AVX2(const uint8_t* src_abgr, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm4                  \n" | 
|  | "vbroadcastf128 %4,%%ymm5                  \n" | 
|  | "vbroadcastf128 %5,%%ymm7                  \n" | 
|  | "vmovdqu     %6,%%ymm6                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY_AVX2(ymm7) | 
|  | : "+r"(src_abgr),         // %0 | 
|  | "+r"(dst_y),            // %1 | 
|  | "+r"(width)             // %2 | 
|  | : "m"(kABGRToY),          // %3 | 
|  | "m"(kSub128),           // %4 | 
|  | "m"(kAddY16),           // %5 | 
|  | "m"(kPermdARGBToY_AVX)  // %6 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ABGRTOYROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBTOYJROW_AVX2 | 
|  | // Convert 32 ARGB pixels (128 bytes) to 32 Y values. | 
|  | void ARGBToYJRow_AVX2(const uint8_t* src_argb, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm4                  \n" | 
|  | "vbroadcastf128 %4,%%ymm5                  \n" | 
|  | "vmovdqu     %5,%%ymm6                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY_AVX2(ymm5) | 
|  | : "+r"(src_argb),         // %0 | 
|  | "+r"(dst_y),            // %1 | 
|  | "+r"(width)             // %2 | 
|  | : "m"(kARGBToYJ),         // %3 | 
|  | "m"(kSub128),           // %4 | 
|  | "m"(kPermdARGBToY_AVX)  // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOYJROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_RGBATOYJROW_AVX2 | 
|  | // Convert 32 ARGB pixels (128 bytes) to 32 Y values. | 
|  | void RGBAToYJRow_AVX2(const uint8_t* src_rgba, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm4                  \n" | 
|  | "vbroadcastf128 %4,%%ymm5                  \n" | 
|  | "vmovdqu     %5,%%ymm6                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY_AVX2( | 
|  | ymm5) "vzeroupper                                \n" | 
|  | : "+r"(src_rgba),         // %0 | 
|  | "+r"(dst_y),            // %1 | 
|  | "+r"(width)             // %2 | 
|  | : "m"(kRGBAToYJ),         // %3 | 
|  | "m"(kSub128),           // %4 | 
|  | "m"(kPermdARGBToY_AVX)  // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_RGBATOYJROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBTOUVROW_SSSE3 | 
|  | void ARGBToUVRow_SSSE3(const uint8_t* src_argb0, | 
|  | int src_stride_argb, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %5,%%xmm3                     \n" | 
|  | "movdqa      %6,%%xmm4                     \n" | 
|  | "movdqa      %7,%%xmm5                     \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm1                 \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x20(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "movdqu      0x30(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm6                 \n" | 
|  |  | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm1,%%xmm0           \n" | 
|  | "shufps      $0xdd,%%xmm1,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqa      %%xmm2,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm6,%%xmm2           \n" | 
|  | "shufps      $0xdd,%%xmm6,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm2,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "phaddw      %%xmm2,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm1                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm1                   \n" | 
|  | "packsswb    %%xmm1,%%xmm0                 \n" | 
|  | "paddb       %%xmm5,%%xmm0                 \n" | 
|  | "movlps      %%xmm0,(%1)                   \n" | 
|  | "movhps      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_argb)),  // %4 | 
|  | "m"(kARGBToV),                     // %5 | 
|  | "m"(kARGBToU),                     // %6 | 
|  | "m"(kAddUV128)                     // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOUVROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBTOUVROW_AVX2 | 
|  | // vpshufb for vphaddw + vpackuswb packed to shorts. | 
|  | static const lvec8 kShufARGBToUV_AVX = { | 
|  | 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, | 
|  | 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15}; | 
|  | void ARGBToUVRow_AVX2(const uint8_t* src_argb0, | 
|  | int src_stride_argb, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %5,%%ymm5                  \n" | 
|  | "vbroadcastf128 %6,%%ymm6                  \n" | 
|  | "vbroadcastf128 %7,%%ymm7                  \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vmovdqu     0x40(%0),%%ymm2               \n" | 
|  | "vmovdqu     0x60(%0),%%ymm3               \n" | 
|  | "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n" | 
|  | "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n" | 
|  | "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n" | 
|  | "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n" | 
|  | "lea         0x80(%0),%0                   \n" | 
|  | "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n" | 
|  | "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n" | 
|  | "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n" | 
|  | "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n" | 
|  | "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n" | 
|  |  | 
|  | "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n" | 
|  | "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n" | 
|  | "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n" | 
|  | "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n" | 
|  | "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpsraw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpsraw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpshufb     %8,%%ymm0,%%ymm0              \n" | 
|  | "vpaddb      %%ymm5,%%ymm0,%%ymm0          \n" | 
|  |  | 
|  | "vextractf128 $0x0,%%ymm0,(%1)             \n" | 
|  | "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_argb)),  // %4 | 
|  | "m"(kAddUV128),                    // %5 | 
|  | "m"(kARGBToV),                     // %6 | 
|  | "m"(kARGBToU),                     // %7 | 
|  | "m"(kShufARGBToUV_AVX)             // %8 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOUVROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ABGRTOUVROW_AVX2 | 
|  | void ABGRToUVRow_AVX2(const uint8_t* src_abgr0, | 
|  | int src_stride_abgr, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %5,%%ymm5                  \n" | 
|  | "vbroadcastf128 %6,%%ymm6                  \n" | 
|  | "vbroadcastf128 %7,%%ymm7                  \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vmovdqu     0x40(%0),%%ymm2               \n" | 
|  | "vmovdqu     0x60(%0),%%ymm3               \n" | 
|  | "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n" | 
|  | "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n" | 
|  | "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n" | 
|  | "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n" | 
|  | "lea         0x80(%0),%0                   \n" | 
|  | "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n" | 
|  | "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n" | 
|  | "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n" | 
|  | "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n" | 
|  | "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n" | 
|  |  | 
|  | "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n" | 
|  | "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n" | 
|  | "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n" | 
|  | "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n" | 
|  | "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpsraw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpsraw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpshufb     %8,%%ymm0,%%ymm0              \n" | 
|  | "vpaddb      %%ymm5,%%ymm0,%%ymm0          \n" | 
|  |  | 
|  | "vextractf128 $0x0,%%ymm0,(%1)             \n" | 
|  | "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_abgr0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_abgr)),  // %4 | 
|  | "m"(kAddUV128),                    // %5 | 
|  | "m"(kABGRToV),                     // %6 | 
|  | "m"(kABGRToU),                     // %7 | 
|  | "m"(kShufARGBToUV_AVX)             // %8 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ABGRTOUVROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBTOUVJROW_AVX2 | 
|  | void ARGBToUVJRow_AVX2(const uint8_t* src_argb0, | 
|  | int src_stride_argb, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %5,%%ymm5                  \n" | 
|  | "vbroadcastf128 %6,%%ymm6                  \n" | 
|  | "vbroadcastf128 %7,%%ymm7                  \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vmovdqu     0x40(%0),%%ymm2               \n" | 
|  | "vmovdqu     0x60(%0),%%ymm3               \n" | 
|  | "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n" | 
|  | "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n" | 
|  | "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n" | 
|  | "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n" | 
|  | "lea         0x80(%0),%0                   \n" | 
|  | "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n" | 
|  | "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n" | 
|  | "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n" | 
|  | "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n" | 
|  | "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n" | 
|  |  | 
|  | "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n" | 
|  | "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n" | 
|  | "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n" | 
|  | "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n" | 
|  | "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpaddw      %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpaddw      %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vpsraw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpsraw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpshufb     %8,%%ymm0,%%ymm0              \n" | 
|  |  | 
|  | "vextractf128 $0x0,%%ymm0,(%1)             \n" | 
|  | "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_argb)),  // %4 | 
|  | "m"(kSub128),                      // %5 | 
|  | "m"(kARGBToVJ),                    // %6 | 
|  | "m"(kARGBToUJ),                    // %7 | 
|  | "m"(kShufARGBToUV_AVX)             // %8 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOUVJROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBTOUVJROW_SSSE3 | 
|  | void ARGBToUVJRow_SSSE3(const uint8_t* src_argb0, | 
|  | int src_stride_argb, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %5,%%xmm3                     \n" | 
|  | "movdqa      %6,%%xmm4                     \n" | 
|  | "movdqa      %7,%%xmm5                     \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm1                 \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x20(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "movdqu      0x30(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm6                 \n" | 
|  |  | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm1,%%xmm0           \n" | 
|  | "shufps      $0xdd,%%xmm1,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqa      %%xmm2,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm6,%%xmm2           \n" | 
|  | "shufps      $0xdd,%%xmm6,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm2,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "phaddw      %%xmm2,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm1                 \n" | 
|  | "paddw       %%xmm5,%%xmm0                 \n" | 
|  | "paddw       %%xmm5,%%xmm1                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm1                   \n" | 
|  | "packsswb    %%xmm1,%%xmm0                 \n" | 
|  | "movlps      %%xmm0,(%1)                   \n" | 
|  | "movhps      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_argb)),  // %4 | 
|  | "m"(kARGBToVJ),                    // %5 | 
|  | "m"(kARGBToUJ),                    // %6 | 
|  | "m"(kSub128)                       // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOUVJROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBTOUV444ROW_SSSE3 | 
|  | void ARGBToUV444Row_SSSE3(const uint8_t* src_argb, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %4,%%xmm3                     \n" | 
|  | "movdqa      %5,%%xmm4                     \n" | 
|  | "movdqa      %6,%%xmm5                     \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm6                 \n" | 
|  | "phaddw      %%xmm1,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm2                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm2                   \n" | 
|  | "packsswb    %%xmm2,%%xmm0                 \n" | 
|  | "paddb       %%xmm5,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "phaddw      %%xmm1,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm2                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm2                   \n" | 
|  | "packsswb    %%xmm2,%%xmm0                 \n" | 
|  | "paddb       %%xmm5,%%xmm0                 \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "movdqu      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_u),     // %1 | 
|  | "+r"(dst_v),     // %2 | 
|  | "+rm"(width)     // %3 | 
|  | : "m"(kARGBToV),   // %4 | 
|  | "m"(kARGBToU),   // %5 | 
|  | "m"(kAddUV128)   // %6 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_ARGBTOUV444ROW_SSSE3 | 
|  |  | 
|  | void BGRAToYRow_SSSE3(const uint8_t* src_bgra, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  | "movdqa      %5,%%xmm7                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY(xmm7) | 
|  | : "+r"(src_bgra),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kBGRAToY),   // %3 | 
|  | "m"(kSub128),    // %4 | 
|  | "m"(kAddY16)     // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  |  | 
|  | void BGRAToUVRow_SSSE3(const uint8_t* src_bgra0, | 
|  | int src_stride_bgra, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %5,%%xmm3                     \n" | 
|  | "movdqa      %6,%%xmm4                     \n" | 
|  | "movdqa      %7,%%xmm5                     \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm1                 \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x20(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "movdqu      0x30(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm6                 \n" | 
|  |  | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm1,%%xmm0           \n" | 
|  | "shufps      $0xdd,%%xmm1,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqa      %%xmm2,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm6,%%xmm2           \n" | 
|  | "shufps      $0xdd,%%xmm6,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm2,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "phaddw      %%xmm2,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm1                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm1                   \n" | 
|  | "packsswb    %%xmm1,%%xmm0                 \n" | 
|  | "paddb       %%xmm5,%%xmm0                 \n" | 
|  | "movlps      %%xmm0,(%1)                   \n" | 
|  | "movhps      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_bgra0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_bgra)),  // %4 | 
|  | "m"(kBGRAToV),                     // %5 | 
|  | "m"(kBGRAToU),                     // %6 | 
|  | "m"(kAddUV128)                     // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); | 
|  | } | 
|  |  | 
|  | void ABGRToYRow_SSSE3(const uint8_t* src_abgr, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  | "movdqa      %5,%%xmm7                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY(xmm7) | 
|  | : "+r"(src_abgr),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kABGRToY),   // %3 | 
|  | "m"(kSub128),    // %4 | 
|  | "m"(kAddY16)     // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  |  | 
|  | void RGBAToYRow_SSSE3(const uint8_t* src_rgba, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  | "movdqa      %5,%%xmm7                     \n" | 
|  |  | 
|  | LABELALIGN RGBTOY(xmm7) | 
|  | : "+r"(src_rgba),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kRGBAToY),   // %3 | 
|  | "m"(kSub128),    // %4 | 
|  | "m"(kAddY16)     // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  |  | 
|  | void ABGRToUVRow_SSSE3(const uint8_t* src_abgr0, | 
|  | int src_stride_abgr, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %5,%%xmm3                     \n" | 
|  | "movdqa      %6,%%xmm4                     \n" | 
|  | "movdqa      %7,%%xmm5                     \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm1                 \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x20(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "movdqu      0x30(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm6                 \n" | 
|  |  | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm1,%%xmm0           \n" | 
|  | "shufps      $0xdd,%%xmm1,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqa      %%xmm2,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm6,%%xmm2           \n" | 
|  | "shufps      $0xdd,%%xmm6,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm2,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "phaddw      %%xmm2,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm1                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm1                   \n" | 
|  | "packsswb    %%xmm1,%%xmm0                 \n" | 
|  | "paddb       %%xmm5,%%xmm0                 \n" | 
|  | "movlps      %%xmm0,(%1)                   \n" | 
|  | "movhps      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_abgr0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_abgr)),  // %4 | 
|  | "m"(kABGRToV),                     // %5 | 
|  | "m"(kABGRToU),                     // %6 | 
|  | "m"(kAddUV128)                     // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); | 
|  | } | 
|  |  | 
|  | void RGBAToUVRow_SSSE3(const uint8_t* src_rgba0, | 
|  | int src_stride_rgba, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      %5,%%xmm3                     \n" | 
|  | "movdqa      %6,%%xmm4                     \n" | 
|  | "movdqa      %7,%%xmm5                     \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm1                 \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x20(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqu      0x30(%0),%%xmm6               \n" | 
|  | "movdqu      0x30(%0,%4,1),%%xmm7          \n" | 
|  | "pavgb       %%xmm7,%%xmm6                 \n" | 
|  |  | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm1,%%xmm0           \n" | 
|  | "shufps      $0xdd,%%xmm1,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm0                 \n" | 
|  | "movdqa      %%xmm2,%%xmm7                 \n" | 
|  | "shufps      $0x88,%%xmm6,%%xmm2           \n" | 
|  | "shufps      $0xdd,%%xmm6,%%xmm7           \n" | 
|  | "pavgb       %%xmm7,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm2,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "phaddw      %%xmm2,%%xmm0                 \n" | 
|  | "phaddw      %%xmm6,%%xmm1                 \n" | 
|  | "psraw       $0x8,%%xmm0                   \n" | 
|  | "psraw       $0x8,%%xmm1                   \n" | 
|  | "packsswb    %%xmm1,%%xmm0                 \n" | 
|  | "paddb       %%xmm5,%%xmm0                 \n" | 
|  | "movlps      %%xmm0,(%1)                   \n" | 
|  | "movhps      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_rgba0),                   // %0 | 
|  | "+r"(dst_u),                       // %1 | 
|  | "+r"(dst_v),                       // %2 | 
|  | "+rm"(width)                       // %3 | 
|  | : "r"((intptr_t)(src_stride_rgba)),  // %4 | 
|  | "m"(kRGBAToV),                     // %5 | 
|  | "m"(kRGBAToU),                     // %6 | 
|  | "m"(kAddUV128)                     // %7 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); | 
|  | } | 
|  |  | 
|  | #if defined(HAS_I422TOARGBROW_SSSE3) || defined(HAS_I422TOARGBROW_AVX2) | 
|  |  | 
|  | // Read 8 UV from 444 | 
|  | #define READYUV444                                                \ | 
|  | "movq       (%[u_buf]),%%xmm0                               \n" \ | 
|  | "movq       0x00(%[u_buf],%[v_buf],1),%%xmm1                \n" \ | 
|  | "lea        0x8(%[u_buf]),%[u_buf]                          \n" \ | 
|  | "punpcklbw  %%xmm1,%%xmm0                                   \n" \ | 
|  | "movq       (%[y_buf]),%%xmm4                               \n" \ | 
|  | "punpcklbw  %%xmm4,%%xmm4                                   \n" \ | 
|  | "lea        0x8(%[y_buf]),%[y_buf]                          \n" | 
|  |  | 
|  | // Read 4 UV from 422, upsample to 8 UV | 
|  | #define READYUV422                                                \ | 
|  | "movd       (%[u_buf]),%%xmm0                               \n" \ | 
|  | "movd       0x00(%[u_buf],%[v_buf],1),%%xmm1                \n" \ | 
|  | "lea        0x4(%[u_buf]),%[u_buf]                          \n" \ | 
|  | "punpcklbw  %%xmm1,%%xmm0                                   \n" \ | 
|  | "punpcklwd  %%xmm0,%%xmm0                                   \n" \ | 
|  | "movq       (%[y_buf]),%%xmm4                               \n" \ | 
|  | "punpcklbw  %%xmm4,%%xmm4                                   \n" \ | 
|  | "lea        0x8(%[y_buf]),%[y_buf]                          \n" | 
|  |  | 
|  | // Read 4 UV from 422 10 bit, upsample to 8 UV | 
|  | // TODO(fbarchard): Consider shufb to replace pack/unpack | 
|  | // TODO(fbarchard): Consider pmulhuw to replace psraw | 
|  | // TODO(fbarchard): Consider pmullw to replace psllw and allow different bits. | 
|  | #define READYUV210                                                \ | 
|  | "movq       (%[u_buf]),%%xmm0                               \n" \ | 
|  | "movq       0x00(%[u_buf],%[v_buf],1),%%xmm1                \n" \ | 
|  | "lea        0x8(%[u_buf]),%[u_buf]                          \n" \ | 
|  | "punpcklwd  %%xmm1,%%xmm0                                   \n" \ | 
|  | "psraw      $0x2,%%xmm0                                     \n" \ | 
|  | "packuswb   %%xmm0,%%xmm0                                   \n" \ | 
|  | "punpcklwd  %%xmm0,%%xmm0                                   \n" \ | 
|  | "movdqu     (%[y_buf]),%%xmm4                               \n" \ | 
|  | "psllw      $0x6,%%xmm4                                     \n" \ | 
|  | "lea        0x10(%[y_buf]),%[y_buf]                         \n" | 
|  |  | 
|  | // Read 4 UV from 422, upsample to 8 UV.  With 8 Alpha. | 
|  | #define READYUVA422                                               \ | 
|  | "movd       (%[u_buf]),%%xmm0                               \n" \ | 
|  | "movd       0x00(%[u_buf],%[v_buf],1),%%xmm1                \n" \ | 
|  | "lea        0x4(%[u_buf]),%[u_buf]                          \n" \ | 
|  | "punpcklbw  %%xmm1,%%xmm0                                   \n" \ | 
|  | "punpcklwd  %%xmm0,%%xmm0                                   \n" \ | 
|  | "movq       (%[y_buf]),%%xmm4                               \n" \ | 
|  | "punpcklbw  %%xmm4,%%xmm4                                   \n" \ | 
|  | "lea        0x8(%[y_buf]),%[y_buf]                          \n" \ | 
|  | "movq       (%[a_buf]),%%xmm5                               \n" \ | 
|  | "lea        0x8(%[a_buf]),%[a_buf]                          \n" | 
|  |  | 
|  | // Read 4 UV from NV12, upsample to 8 UV | 
|  | #define READNV12                                                  \ | 
|  | "movq       (%[uv_buf]),%%xmm0                              \n" \ | 
|  | "lea        0x8(%[uv_buf]),%[uv_buf]                        \n" \ | 
|  | "punpcklwd  %%xmm0,%%xmm0                                   \n" \ | 
|  | "movq       (%[y_buf]),%%xmm4                               \n" \ | 
|  | "punpcklbw  %%xmm4,%%xmm4                                   \n" \ | 
|  | "lea        0x8(%[y_buf]),%[y_buf]                          \n" | 
|  |  | 
|  | // Read 4 VU from NV21, upsample to 8 UV | 
|  | #define READNV21                                                  \ | 
|  | "movq       (%[vu_buf]),%%xmm0                              \n" \ | 
|  | "lea        0x8(%[vu_buf]),%[vu_buf]                        \n" \ | 
|  | "pshufb     %[kShuffleNV21], %%xmm0                         \n" \ | 
|  | "movq       (%[y_buf]),%%xmm4                               \n" \ | 
|  | "punpcklbw  %%xmm4,%%xmm4                                   \n" \ | 
|  | "lea        0x8(%[y_buf]),%[y_buf]                          \n" | 
|  |  | 
|  | // Read 4 YUY2 with 8 Y and update 4 UV to 8 UV. | 
|  | #define READYUY2                                                  \ | 
|  | "movdqu     (%[yuy2_buf]),%%xmm4                            \n" \ | 
|  | "pshufb     %[kShuffleYUY2Y], %%xmm4                        \n" \ | 
|  | "movdqu     (%[yuy2_buf]),%%xmm0                            \n" \ | 
|  | "pshufb     %[kShuffleYUY2UV], %%xmm0                       \n" \ | 
|  | "lea        0x10(%[yuy2_buf]),%[yuy2_buf]                   \n" | 
|  |  | 
|  | // Read 4 UYVY with 8 Y and update 4 UV to 8 UV. | 
|  | #define READUYVY                                                  \ | 
|  | "movdqu     (%[uyvy_buf]),%%xmm4                            \n" \ | 
|  | "pshufb     %[kShuffleUYVYY], %%xmm4                        \n" \ | 
|  | "movdqu     (%[uyvy_buf]),%%xmm0                            \n" \ | 
|  | "pshufb     %[kShuffleUYVYUV], %%xmm0                       \n" \ | 
|  | "lea        0x10(%[uyvy_buf]),%[uyvy_buf]                   \n" | 
|  |  | 
|  | #if defined(__x86_64__) | 
|  | #define YUVTORGB_SETUP(yuvconstants)                              \ | 
|  | "movdqa     (%[yuvconstants]),%%xmm8                        \n" \ | 
|  | "movdqa     32(%[yuvconstants]),%%xmm9                      \n" \ | 
|  | "movdqa     64(%[yuvconstants]),%%xmm10                     \n" \ | 
|  | "movdqa     96(%[yuvconstants]),%%xmm11                     \n" \ | 
|  | "movdqa     128(%[yuvconstants]),%%xmm12                    \n" \ | 
|  | "movdqa     160(%[yuvconstants]),%%xmm13                    \n" \ | 
|  | "movdqa     192(%[yuvconstants]),%%xmm14                    \n" | 
|  | // Convert 8 pixels: 8 UV and 8 Y | 
|  | #define YUVTORGB16(yuvconstants)                                  \ | 
|  | "movdqa     %%xmm0,%%xmm1                                   \n" \ | 
|  | "movdqa     %%xmm0,%%xmm2                                   \n" \ | 
|  | "movdqa     %%xmm0,%%xmm3                                   \n" \ | 
|  | "movdqa     %%xmm11,%%xmm0                                  \n" \ | 
|  | "pmaddubsw  %%xmm8,%%xmm1                                   \n" \ | 
|  | "psubw      %%xmm1,%%xmm0                                   \n" \ | 
|  | "movdqa     %%xmm12,%%xmm1                                  \n" \ | 
|  | "pmaddubsw  %%xmm9,%%xmm2                                   \n" \ | 
|  | "psubw      %%xmm2,%%xmm1                                   \n" \ | 
|  | "movdqa     %%xmm13,%%xmm2                                  \n" \ | 
|  | "pmaddubsw  %%xmm10,%%xmm3                                  \n" \ | 
|  | "psubw      %%xmm3,%%xmm2                                   \n" \ | 
|  | "pmulhuw    %%xmm14,%%xmm4                                  \n" \ | 
|  | "paddsw     %%xmm4,%%xmm0                                   \n" \ | 
|  | "paddsw     %%xmm4,%%xmm1                                   \n" \ | 
|  | "paddsw     %%xmm4,%%xmm2                                   \n" | 
|  | #define YUVTORGB_REGS \ | 
|  | "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", | 
|  |  | 
|  | #else | 
|  | #define YUVTORGB_SETUP(yuvconstants) | 
|  | // Convert 8 pixels: 8 UV and 8 Y | 
|  | #define YUVTORGB16(yuvconstants)                                  \ | 
|  | "movdqa     %%xmm0,%%xmm1                                   \n" \ | 
|  | "movdqa     %%xmm0,%%xmm2                                   \n" \ | 
|  | "movdqa     %%xmm0,%%xmm3                                   \n" \ | 
|  | "movdqa     96(%[yuvconstants]),%%xmm0                      \n" \ | 
|  | "pmaddubsw  (%[yuvconstants]),%%xmm1                        \n" \ | 
|  | "psubw      %%xmm1,%%xmm0                                   \n" \ | 
|  | "movdqa     128(%[yuvconstants]),%%xmm1                     \n" \ | 
|  | "pmaddubsw  32(%[yuvconstants]),%%xmm2                      \n" \ | 
|  | "psubw      %%xmm2,%%xmm1                                   \n" \ | 
|  | "movdqa     160(%[yuvconstants]),%%xmm2                     \n" \ | 
|  | "pmaddubsw  64(%[yuvconstants]),%%xmm3                      \n" \ | 
|  | "psubw      %%xmm3,%%xmm2                                   \n" \ | 
|  | "pmulhuw    192(%[yuvconstants]),%%xmm4                     \n" \ | 
|  | "paddsw     %%xmm4,%%xmm0                                   \n" \ | 
|  | "paddsw     %%xmm4,%%xmm1                                   \n" \ | 
|  | "paddsw     %%xmm4,%%xmm2                                   \n" | 
|  | #define YUVTORGB_REGS | 
|  | #endif | 
|  |  | 
|  | #define YUVTORGB(yuvconstants)                                    \ | 
|  | YUVTORGB16(yuvconstants)                                        \ | 
|  | "psraw      $0x6,%%xmm0                                     \n" \ | 
|  | "psraw      $0x6,%%xmm1                                     \n" \ | 
|  | "psraw      $0x6,%%xmm2                                     \n" \ | 
|  | "packuswb   %%xmm0,%%xmm0                                   \n" \ | 
|  | "packuswb   %%xmm1,%%xmm1                                   \n" \ | 
|  | "packuswb   %%xmm2,%%xmm2                                   \n" | 
|  |  | 
|  | // Store 8 ARGB values. | 
|  | #define STOREARGB                                                  \ | 
|  | "punpcklbw  %%xmm1,%%xmm0                                    \n" \ | 
|  | "punpcklbw  %%xmm5,%%xmm2                                    \n" \ | 
|  | "movdqa     %%xmm0,%%xmm1                                    \n" \ | 
|  | "punpcklwd  %%xmm2,%%xmm0                                    \n" \ | 
|  | "punpckhwd  %%xmm2,%%xmm1                                    \n" \ | 
|  | "movdqu     %%xmm0,(%[dst_argb])                             \n" \ | 
|  | "movdqu     %%xmm1,0x10(%[dst_argb])                         \n" \ | 
|  | "lea        0x20(%[dst_argb]), %[dst_argb]                   \n" | 
|  |  | 
|  | // Store 8 RGBA values. | 
|  | #define STORERGBA                                                  \ | 
|  | "pcmpeqb   %%xmm5,%%xmm5                                     \n" \ | 
|  | "punpcklbw %%xmm2,%%xmm1                                     \n" \ | 
|  | "punpcklbw %%xmm0,%%xmm5                                     \n" \ | 
|  | "movdqa    %%xmm5,%%xmm0                                     \n" \ | 
|  | "punpcklwd %%xmm1,%%xmm5                                     \n" \ | 
|  | "punpckhwd %%xmm1,%%xmm0                                     \n" \ | 
|  | "movdqu    %%xmm5,(%[dst_rgba])                              \n" \ | 
|  | "movdqu    %%xmm0,0x10(%[dst_rgba])                          \n" \ | 
|  | "lea       0x20(%[dst_rgba]),%[dst_rgba]                     \n" | 
|  |  | 
|  | // Store 8 AR30 values. | 
|  | #define STOREAR30                                                  \ | 
|  | "psraw      $0x4,%%xmm0                                      \n" \ | 
|  | "psraw      $0x4,%%xmm1                                      \n" \ | 
|  | "psraw      $0x4,%%xmm2                                      \n" \ | 
|  | "pminsw     %%xmm7,%%xmm0                                    \n" \ | 
|  | "pminsw     %%xmm7,%%xmm1                                    \n" \ | 
|  | "pminsw     %%xmm7,%%xmm2                                    \n" \ | 
|  | "pmaxsw     %%xmm6,%%xmm0                                    \n" \ | 
|  | "pmaxsw     %%xmm6,%%xmm1                                    \n" \ | 
|  | "pmaxsw     %%xmm6,%%xmm2                                    \n" \ | 
|  | "psllw      $0x4,%%xmm2                                      \n" \ | 
|  | "movdqa     %%xmm0,%%xmm3                                    \n" \ | 
|  | "punpcklwd  %%xmm2,%%xmm0                                    \n" \ | 
|  | "punpckhwd  %%xmm2,%%xmm3                                    \n" \ | 
|  | "movdqa     %%xmm1,%%xmm2                                    \n" \ | 
|  | "punpcklwd  %%xmm5,%%xmm1                                    \n" \ | 
|  | "punpckhwd  %%xmm5,%%xmm2                                    \n" \ | 
|  | "pslld      $0xa,%%xmm1                                      \n" \ | 
|  | "pslld      $0xa,%%xmm2                                      \n" \ | 
|  | "por        %%xmm1,%%xmm0                                    \n" \ | 
|  | "por        %%xmm2,%%xmm3                                    \n" \ | 
|  | "movdqu     %%xmm0,(%[dst_ar30])                             \n" \ | 
|  | "movdqu     %%xmm3,0x10(%[dst_ar30])                         \n" \ | 
|  | "lea        0x20(%[dst_ar30]), %[dst_ar30]                   \n" | 
|  |  | 
|  | void OMITFP I444ToARGBRow_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV444 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  |  | 
|  | void OMITFP I422ToRGB24Row_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_rgb24, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "movdqa      %[kShuffleMaskARGBToRGB24_0],%%xmm5 \n" | 
|  | "movdqa      %[kShuffleMaskARGBToRGB24],%%xmm6 \n" | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422 | 
|  | YUVTORGB(yuvconstants) | 
|  | "punpcklbw   %%xmm1,%%xmm0                 \n" | 
|  | "punpcklbw   %%xmm2,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklwd   %%xmm2,%%xmm0                 \n" | 
|  | "punpckhwd   %%xmm2,%%xmm1                 \n" | 
|  | "pshufb      %%xmm5,%%xmm0                 \n" | 
|  | "pshufb      %%xmm6,%%xmm1                 \n" | 
|  | "palignr     $0xc,%%xmm0,%%xmm1            \n" | 
|  | "movq        %%xmm0,(%[dst_rgb24])         \n" | 
|  | "movdqu      %%xmm1,0x8(%[dst_rgb24])      \n" | 
|  | "lea         0x18(%[dst_rgb24]),%[dst_rgb24] \n" | 
|  | "subl        $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_rgb24]"+r"(dst_rgb24),  // %[dst_rgb24] | 
|  | #if defined(__i386__) | 
|  | [width]"+m"(width)     // %[width] | 
|  | #else | 
|  | [width]"+rm"(width)    // %[width] | 
|  | #endif | 
|  | : [yuvconstants]"r"(yuvconstants),  // %[yuvconstants] | 
|  | [kShuffleMaskARGBToRGB24_0]"m"(kShuffleMaskARGBToRGB24_0), | 
|  | [kShuffleMaskARGBToRGB24]"m"(kShuffleMaskARGBToRGB24) | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" | 
|  | ); | 
|  | } | 
|  |  | 
|  | void OMITFP I422ToARGBRow_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  |  | 
|  | void OMITFP I422ToAR30Row_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_ar30, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n"  // AR30 constants | 
|  | "psrlw       $14,%%xmm5                    \n" | 
|  | "psllw       $4,%%xmm5                     \n"  // 2 alpha bits | 
|  | "pxor        %%xmm6,%%xmm6                 \n" | 
|  | "pcmpeqb     %%xmm7,%%xmm7                 \n"  // 0 for min | 
|  | "psrlw       $6,%%xmm7                     \n"  // 1023 for max | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422 | 
|  | YUVTORGB16(yuvconstants) | 
|  | STOREAR30 | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_ar30]"+r"(dst_ar30),  // %[dst_ar30] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" | 
|  | ); | 
|  | } | 
|  |  | 
|  | // 10 bit YUV to ARGB | 
|  | void OMITFP I210ToARGBRow_SSSE3(const uint16_t* y_buf, | 
|  | const uint16_t* u_buf, | 
|  | const uint16_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV210 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  |  | 
|  | // 10 bit YUV to AR30 | 
|  | void OMITFP I210ToAR30Row_SSSE3(const uint16_t* y_buf, | 
|  | const uint16_t* u_buf, | 
|  | const uint16_t* v_buf, | 
|  | uint8_t* dst_ar30, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $14,%%xmm5                    \n" | 
|  | "psllw       $4,%%xmm5                     \n"  // 2 alpha bits | 
|  | "pxor        %%xmm6,%%xmm6                 \n" | 
|  | "pcmpeqb     %%xmm7,%%xmm7                 \n"  // 0 for min | 
|  | "psrlw       $6,%%xmm7                     \n"  // 1023 for max | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV210 | 
|  | YUVTORGB16(yuvconstants) | 
|  | STOREAR30 | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_ar30]"+r"(dst_ar30),  // %[dst_ar30] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" | 
|  | ); | 
|  | } | 
|  |  | 
|  | #ifdef HAS_I422ALPHATOARGBROW_SSSE3 | 
|  | void OMITFP I422AlphaToARGBRow_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | const uint8_t* a_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUVA422 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "subl        $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [a_buf]"+r"(a_buf),    // %[a_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | #if defined(__i386__) | 
|  | [width]"+m"(width)     // %[width] | 
|  | #else | 
|  | [width]"+rm"(width)    // %[width] | 
|  | #endif | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_I422ALPHATOARGBROW_SSSE3 | 
|  |  | 
|  | void OMITFP NV12ToARGBRow_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* uv_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READNV12 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [uv_buf]"+r"(uv_buf),    // %[uv_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  |  | 
|  | void OMITFP NV21ToARGBRow_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* vu_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READNV21 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [vu_buf]"+r"(vu_buf),    // %[vu_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] | 
|  | [kShuffleNV21]"m"(kShuffleNV21) | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  |  | 
|  | void OMITFP YUY2ToARGBRow_SSSE3(const uint8_t* yuy2_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUY2 | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [yuy2_buf]"+r"(yuy2_buf),    // %[yuy2_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] | 
|  | [kShuffleYUY2Y]"m"(kShuffleYUY2Y), | 
|  | [kShuffleYUY2UV]"m"(kShuffleYUY2UV) | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  |  | 
|  | void OMITFP UYVYToARGBRow_SSSE3(const uint8_t* uyvy_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READUYVY | 
|  | YUVTORGB(yuvconstants) | 
|  | STOREARGB | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [uyvy_buf]"+r"(uyvy_buf),    // %[uyvy_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] | 
|  | [kShuffleUYVYY]"m"(kShuffleUYVYY), | 
|  | [kShuffleUYVYUV]"m"(kShuffleUYVYUV) | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  |  | 
|  | void OMITFP I422ToRGBARow_SSSE3(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_rgba, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422 | 
|  | YUVTORGB(yuvconstants) | 
|  | STORERGBA | 
|  | "sub         $0x8,%[width]                 \n" | 
|  | "jg          1b                            \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_rgba]"+r"(dst_rgba),  // %[dst_rgba] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  |  | 
|  | #endif  // HAS_I422TOARGBROW_SSSE3 | 
|  |  | 
|  | // Read 16 UV from 444 | 
|  | #define READYUV444_AVX2                                               \ | 
|  | "vmovdqu    (%[u_buf]),%%xmm0                                   \n" \ | 
|  | "vmovdqu    0x00(%[u_buf],%[v_buf],1),%%xmm1                    \n" \ | 
|  | "lea        0x10(%[u_buf]),%[u_buf]                             \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpermq     $0xd8,%%ymm1,%%ymm1                                 \n" \ | 
|  | "vpunpcklbw %%ymm1,%%ymm0,%%ymm0                                \n" \ | 
|  | "vmovdqu    (%[y_buf]),%%xmm4                                   \n" \ | 
|  | "vpermq     $0xd8,%%ymm4,%%ymm4                                 \n" \ | 
|  | "vpunpcklbw %%ymm4,%%ymm4,%%ymm4                                \n" \ | 
|  | "lea        0x10(%[y_buf]),%[y_buf]                             \n" | 
|  |  | 
|  | // Read 8 UV from 422, upsample to 16 UV. | 
|  | #define READYUV422_AVX2                                               \ | 
|  | "vmovq      (%[u_buf]),%%xmm0                                   \n" \ | 
|  | "vmovq      0x00(%[u_buf],%[v_buf],1),%%xmm1                    \n" \ | 
|  | "lea        0x8(%[u_buf]),%[u_buf]                              \n" \ | 
|  | "vpunpcklbw %%ymm1,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpunpcklwd %%ymm0,%%ymm0,%%ymm0                                \n" \ | 
|  | "vmovdqu    (%[y_buf]),%%xmm4                                   \n" \ | 
|  | "vpermq     $0xd8,%%ymm4,%%ymm4                                 \n" \ | 
|  | "vpunpcklbw %%ymm4,%%ymm4,%%ymm4                                \n" \ | 
|  | "lea        0x10(%[y_buf]),%[y_buf]                             \n" | 
|  |  | 
|  | // Read 8 UV from 210 10 bit, upsample to 16 UV | 
|  | // TODO(fbarchard): Consider vshufb to replace pack/unpack | 
|  | // TODO(fbarchard): Consider vunpcklpd to combine the 2 registers into 1. | 
|  | #define READYUV210_AVX2                                            \ | 
|  | "vmovdqu    (%[u_buf]),%%xmm0                                \n" \ | 
|  | "vmovdqu    0x00(%[u_buf],%[v_buf],1),%%xmm1                 \n" \ | 
|  | "lea        0x10(%[u_buf]),%[u_buf]                          \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                              \n" \ | 
|  | "vpermq     $0xd8,%%ymm1,%%ymm1                              \n" \ | 
|  | "vpunpcklwd %%ymm1,%%ymm0,%%ymm0                             \n" \ | 
|  | "vpsraw     $0x2,%%ymm0,%%ymm0                               \n" \ | 
|  | "vpackuswb  %%ymm0,%%ymm0,%%ymm0                             \n" \ | 
|  | "vpunpcklwd %%ymm0,%%ymm0,%%ymm0                             \n" \ | 
|  | "vmovdqu    (%[y_buf]),%%ymm4                                \n" \ | 
|  | "vpsllw     $0x6,%%ymm4,%%ymm4                               \n" \ | 
|  | "lea        0x20(%[y_buf]),%[y_buf]                          \n" | 
|  |  | 
|  | // Read 8 UV from 422, upsample to 16 UV.  With 16 Alpha. | 
|  | #define READYUVA422_AVX2                                              \ | 
|  | "vmovq      (%[u_buf]),%%xmm0                                   \n" \ | 
|  | "vmovq      0x00(%[u_buf],%[v_buf],1),%%xmm1                    \n" \ | 
|  | "lea        0x8(%[u_buf]),%[u_buf]                              \n" \ | 
|  | "vpunpcklbw %%ymm1,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpunpcklwd %%ymm0,%%ymm0,%%ymm0                                \n" \ | 
|  | "vmovdqu    (%[y_buf]),%%xmm4                                   \n" \ | 
|  | "vpermq     $0xd8,%%ymm4,%%ymm4                                 \n" \ | 
|  | "vpunpcklbw %%ymm4,%%ymm4,%%ymm4                                \n" \ | 
|  | "lea        0x10(%[y_buf]),%[y_buf]                             \n" \ | 
|  | "vmovdqu    (%[a_buf]),%%xmm5                                   \n" \ | 
|  | "vpermq     $0xd8,%%ymm5,%%ymm5                                 \n" \ | 
|  | "lea        0x10(%[a_buf]),%[a_buf]                             \n" | 
|  |  | 
|  | // Read 8 UV from NV12, upsample to 16 UV. | 
|  | #define READNV12_AVX2                                                 \ | 
|  | "vmovdqu    (%[uv_buf]),%%xmm0                                  \n" \ | 
|  | "lea        0x10(%[uv_buf]),%[uv_buf]                           \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpunpcklwd %%ymm0,%%ymm0,%%ymm0                                \n" \ | 
|  | "vmovdqu    (%[y_buf]),%%xmm4                                   \n" \ | 
|  | "vpermq     $0xd8,%%ymm4,%%ymm4                                 \n" \ | 
|  | "vpunpcklbw %%ymm4,%%ymm4,%%ymm4                                \n" \ | 
|  | "lea        0x10(%[y_buf]),%[y_buf]                             \n" | 
|  |  | 
|  | // Read 8 VU from NV21, upsample to 16 UV. | 
|  | #define READNV21_AVX2                                                 \ | 
|  | "vmovdqu    (%[vu_buf]),%%xmm0                                  \n" \ | 
|  | "lea        0x10(%[vu_buf]),%[vu_buf]                           \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpshufb     %[kShuffleNV21], %%ymm0, %%ymm0                    \n" \ | 
|  | "vmovdqu    (%[y_buf]),%%xmm4                                   \n" \ | 
|  | "vpermq     $0xd8,%%ymm4,%%ymm4                                 \n" \ | 
|  | "vpunpcklbw %%ymm4,%%ymm4,%%ymm4                                \n" \ | 
|  | "lea        0x10(%[y_buf]),%[y_buf]                             \n" | 
|  |  | 
|  | // Read 8 YUY2 with 16 Y and upsample 8 UV to 16 UV. | 
|  | #define READYUY2_AVX2                                                 \ | 
|  | "vmovdqu    (%[yuy2_buf]),%%ymm4                                \n" \ | 
|  | "vpshufb    %[kShuffleYUY2Y], %%ymm4, %%ymm4                    \n" \ | 
|  | "vmovdqu    (%[yuy2_buf]),%%ymm0                                \n" \ | 
|  | "vpshufb    %[kShuffleYUY2UV], %%ymm0, %%ymm0                   \n" \ | 
|  | "lea        0x20(%[yuy2_buf]),%[yuy2_buf]                       \n" | 
|  |  | 
|  | // Read 8 UYVY with 16 Y and upsample 8 UV to 16 UV. | 
|  | #define READUYVY_AVX2                                                 \ | 
|  | "vmovdqu    (%[uyvy_buf]),%%ymm4                                \n" \ | 
|  | "vpshufb    %[kShuffleUYVYY], %%ymm4, %%ymm4                    \n" \ | 
|  | "vmovdqu    (%[uyvy_buf]),%%ymm0                                \n" \ | 
|  | "vpshufb    %[kShuffleUYVYUV], %%ymm0, %%ymm0                   \n" \ | 
|  | "lea        0x20(%[uyvy_buf]),%[uyvy_buf]                       \n" | 
|  |  | 
|  | #if defined(__x86_64__) | 
|  | #define YUVTORGB_SETUP_AVX2(yuvconstants)                            \ | 
|  | "vmovdqa     (%[yuvconstants]),%%ymm8                          \n" \ | 
|  | "vmovdqa     32(%[yuvconstants]),%%ymm9                        \n" \ | 
|  | "vmovdqa     64(%[yuvconstants]),%%ymm10                       \n" \ | 
|  | "vmovdqa     96(%[yuvconstants]),%%ymm11                       \n" \ | 
|  | "vmovdqa     128(%[yuvconstants]),%%ymm12                      \n" \ | 
|  | "vmovdqa     160(%[yuvconstants]),%%ymm13                      \n" \ | 
|  | "vmovdqa     192(%[yuvconstants]),%%ymm14                      \n" | 
|  |  | 
|  | #define YUVTORGB16_AVX2(yuvconstants)                                 \ | 
|  | "vpmaddubsw  %%ymm10,%%ymm0,%%ymm2                              \n" \ | 
|  | "vpmaddubsw  %%ymm9,%%ymm0,%%ymm1                               \n" \ | 
|  | "vpmaddubsw  %%ymm8,%%ymm0,%%ymm0                               \n" \ | 
|  | "vpsubw      %%ymm2,%%ymm13,%%ymm2                              \n" \ | 
|  | "vpsubw      %%ymm1,%%ymm12,%%ymm1                              \n" \ | 
|  | "vpsubw      %%ymm0,%%ymm11,%%ymm0                              \n" \ | 
|  | "vpmulhuw    %%ymm14,%%ymm4,%%ymm4                              \n" \ | 
|  | "vpaddsw     %%ymm4,%%ymm0,%%ymm0                               \n" \ | 
|  | "vpaddsw     %%ymm4,%%ymm1,%%ymm1                               \n" \ | 
|  | "vpaddsw     %%ymm4,%%ymm2,%%ymm2                               \n" | 
|  |  | 
|  | #define YUVTORGB_REGS_AVX2 \ | 
|  | "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", | 
|  |  | 
|  | #else  // Convert 16 pixels: 16 UV and 16 Y. | 
|  |  | 
|  | #define YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | #define YUVTORGB16_AVX2(yuvconstants)                                 \ | 
|  | "vpmaddubsw  64(%[yuvconstants]),%%ymm0,%%ymm2                  \n" \ | 
|  | "vpmaddubsw  32(%[yuvconstants]),%%ymm0,%%ymm1                  \n" \ | 
|  | "vpmaddubsw  (%[yuvconstants]),%%ymm0,%%ymm0                    \n" \ | 
|  | "vmovdqu     160(%[yuvconstants]),%%ymm3                        \n" \ | 
|  | "vpsubw      %%ymm2,%%ymm3,%%ymm2                               \n" \ | 
|  | "vmovdqu     128(%[yuvconstants]),%%ymm3                        \n" \ | 
|  | "vpsubw      %%ymm1,%%ymm3,%%ymm1                               \n" \ | 
|  | "vmovdqu     96(%[yuvconstants]),%%ymm3                         \n" \ | 
|  | "vpsubw      %%ymm0,%%ymm3,%%ymm0                               \n" \ | 
|  | "vpmulhuw    192(%[yuvconstants]),%%ymm4,%%ymm4                 \n" \ | 
|  | "vpaddsw     %%ymm4,%%ymm0,%%ymm0                               \n" \ | 
|  | "vpaddsw     %%ymm4,%%ymm1,%%ymm1                               \n" \ | 
|  | "vpaddsw     %%ymm4,%%ymm2,%%ymm2                               \n" | 
|  | #define YUVTORGB_REGS_AVX2 | 
|  | #endif | 
|  |  | 
|  | #define YUVTORGB_AVX2(yuvconstants)                                   \ | 
|  | YUVTORGB16_AVX2(yuvconstants)                                       \ | 
|  | "vpsraw      $0x6,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpsraw      $0x6,%%ymm1,%%ymm1                                 \n" \ | 
|  | "vpsraw      $0x6,%%ymm2,%%ymm2                                 \n" \ | 
|  | "vpackuswb   %%ymm0,%%ymm0,%%ymm0                               \n" \ | 
|  | "vpackuswb   %%ymm1,%%ymm1,%%ymm1                               \n" \ | 
|  | "vpackuswb   %%ymm2,%%ymm2,%%ymm2                               \n" | 
|  |  | 
|  | // Store 16 ARGB values. | 
|  | #define STOREARGB_AVX2                                                \ | 
|  | "vpunpcklbw %%ymm1,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpunpcklbw %%ymm5,%%ymm2,%%ymm2                                \n" \ | 
|  | "vpermq     $0xd8,%%ymm2,%%ymm2                                 \n" \ | 
|  | "vpunpcklwd %%ymm2,%%ymm0,%%ymm1                                \n" \ | 
|  | "vpunpckhwd %%ymm2,%%ymm0,%%ymm0                                \n" \ | 
|  | "vmovdqu    %%ymm1,(%[dst_argb])                                \n" \ | 
|  | "vmovdqu    %%ymm0,0x20(%[dst_argb])                            \n" \ | 
|  | "lea       0x40(%[dst_argb]), %[dst_argb]                       \n" | 
|  |  | 
|  | // Store 16 AR30 values. | 
|  | #define STOREAR30_AVX2                                                \ | 
|  | "vpsraw     $0x4,%%ymm0,%%ymm0                                  \n" \ | 
|  | "vpsraw     $0x4,%%ymm1,%%ymm1                                  \n" \ | 
|  | "vpsraw     $0x4,%%ymm2,%%ymm2                                  \n" \ | 
|  | "vpminsw    %%ymm7,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpminsw    %%ymm7,%%ymm1,%%ymm1                                \n" \ | 
|  | "vpminsw    %%ymm7,%%ymm2,%%ymm2                                \n" \ | 
|  | "vpmaxsw    %%ymm6,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpmaxsw    %%ymm6,%%ymm1,%%ymm1                                \n" \ | 
|  | "vpmaxsw    %%ymm6,%%ymm2,%%ymm2                                \n" \ | 
|  | "vpsllw     $0x4,%%ymm2,%%ymm2                                  \n" \ | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0                                 \n" \ | 
|  | "vpermq     $0xd8,%%ymm1,%%ymm1                                 \n" \ | 
|  | "vpermq     $0xd8,%%ymm2,%%ymm2                                 \n" \ | 
|  | "vpunpckhwd %%ymm2,%%ymm0,%%ymm3                                \n" \ | 
|  | "vpunpcklwd %%ymm2,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpunpckhwd %%ymm5,%%ymm1,%%ymm2                                \n" \ | 
|  | "vpunpcklwd %%ymm5,%%ymm1,%%ymm1                                \n" \ | 
|  | "vpslld     $0xa,%%ymm1,%%ymm1                                  \n" \ | 
|  | "vpslld     $0xa,%%ymm2,%%ymm2                                  \n" \ | 
|  | "vpor       %%ymm1,%%ymm0,%%ymm0                                \n" \ | 
|  | "vpor       %%ymm2,%%ymm3,%%ymm3                                \n" \ | 
|  | "vmovdqu    %%ymm0,(%[dst_ar30])                                \n" \ | 
|  | "vmovdqu    %%ymm3,0x20(%[dst_ar30])                            \n" \ | 
|  | "lea        0x40(%[dst_ar30]), %[dst_ar30]                      \n" | 
|  |  | 
|  | #ifdef HAS_I444TOARGBROW_AVX2 | 
|  | // 16 pixels | 
|  | // 16 UV values with 16 Y producing 16 ARGB (64 bytes). | 
|  | void OMITFP I444ToARGBRow_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV444_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_I444TOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_I422TOARGBROW_AVX2) | 
|  | // 16 pixels | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). | 
|  | void OMITFP I422ToARGBRow_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_I422TOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_I422TOAR30ROW_AVX2) | 
|  | // 16 pixels | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 AR30 (64 bytes). | 
|  | void OMITFP I422ToAR30Row_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_ar30, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"  // AR30 constants | 
|  | "vpsrlw      $14,%%ymm5,%%ymm5             \n" | 
|  | "vpsllw      $4,%%ymm5,%%ymm5              \n"  // 2 alpha bits | 
|  | "vpxor       %%ymm6,%%ymm6,%%ymm6          \n"  // 0 for min | 
|  | "vpcmpeqb    %%ymm7,%%ymm7,%%ymm7          \n"  // 1023 for max | 
|  | "vpsrlw      $6,%%ymm7,%%ymm7              \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422_AVX2 | 
|  | YUVTORGB16_AVX2(yuvconstants) | 
|  | STOREAR30_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_ar30]"+r"(dst_ar30),  // %[dst_ar30] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_I422TOAR30ROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_I210TOARGBROW_AVX2) | 
|  | // 16 pixels | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). | 
|  | void OMITFP I210ToARGBRow_AVX2(const uint16_t* y_buf, | 
|  | const uint16_t* u_buf, | 
|  | const uint16_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV210_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_I210TOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_I210TOAR30ROW_AVX2) | 
|  | // 16 pixels | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 AR30 (64 bytes). | 
|  | void OMITFP I210ToAR30Row_AVX2(const uint16_t* y_buf, | 
|  | const uint16_t* u_buf, | 
|  | const uint16_t* v_buf, | 
|  | uint8_t* dst_ar30, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"  // AR30 constants | 
|  | "vpsrlw      $14,%%ymm5,%%ymm5             \n" | 
|  | "vpsllw      $4,%%ymm5,%%ymm5              \n"  // 2 alpha bits | 
|  | "vpxor       %%ymm6,%%ymm6,%%ymm6          \n"  // 0 for min | 
|  | "vpcmpeqb    %%ymm7,%%ymm7,%%ymm7          \n"  // 1023 for max | 
|  | "vpsrlw      $6,%%ymm7,%%ymm7              \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV210_AVX2 | 
|  | YUVTORGB16_AVX2(yuvconstants) | 
|  | STOREAR30_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_ar30]"+r"(dst_ar30),  // %[dst_ar30] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_I210TOAR30ROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_I422ALPHATOARGBROW_AVX2) | 
|  | // 16 pixels | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y and 16 A producing 16 ARGB. | 
|  | void OMITFP I422AlphaToARGBRow_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | const uint8_t* a_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUVA422_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "subl        $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [a_buf]"+r"(a_buf),    // %[a_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | #if defined(__i386__) | 
|  | [width]"+m"(width)     // %[width] | 
|  | #else | 
|  | [width]"+rm"(width)    // %[width] | 
|  | #endif | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_I422ALPHATOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_I422TORGBAROW_AVX2) | 
|  | // 16 pixels | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 RGBA (64 bytes). | 
|  | void OMITFP I422ToRGBARow_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* u_buf, | 
|  | const uint8_t* v_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "sub         %[u_buf],%[v_buf]             \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUV422_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  |  | 
|  | // Step 3: Weave into RGBA | 
|  | "vpunpcklbw %%ymm2,%%ymm1,%%ymm1           \n" | 
|  | "vpermq     $0xd8,%%ymm1,%%ymm1            \n" | 
|  | "vpunpcklbw %%ymm0,%%ymm5,%%ymm2           \n" | 
|  | "vpermq     $0xd8,%%ymm2,%%ymm2            \n" | 
|  | "vpunpcklwd %%ymm1,%%ymm2,%%ymm0           \n" | 
|  | "vpunpckhwd %%ymm1,%%ymm2,%%ymm1           \n" | 
|  | "vmovdqu    %%ymm0,(%[dst_argb])           \n" | 
|  | "vmovdqu    %%ymm1,0x20(%[dst_argb])       \n" | 
|  | "lea        0x40(%[dst_argb]),%[dst_argb]  \n" | 
|  | "sub        $0x10,%[width]                 \n" | 
|  | "jg         1b                             \n" | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [u_buf]"+r"(u_buf),    // %[u_buf] | 
|  | [v_buf]"+r"(v_buf),    // %[v_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_I422TORGBAROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_NV12TOARGBROW_AVX2) | 
|  | // 16 pixels. | 
|  | // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). | 
|  | void OMITFP NV12ToARGBRow_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* uv_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READNV12_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [uv_buf]"+r"(uv_buf),    // %[uv_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants] | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_NV12TOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_NV21TOARGBROW_AVX2) | 
|  | // 16 pixels. | 
|  | // 8 VU values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). | 
|  | void OMITFP NV21ToARGBRow_AVX2(const uint8_t* y_buf, | 
|  | const uint8_t* vu_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READNV21_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : [y_buf]"+r"(y_buf),    // %[y_buf] | 
|  | [vu_buf]"+r"(vu_buf),    // %[vu_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] | 
|  | [kShuffleNV21]"m"(kShuffleNV21) | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_NV21TOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_YUY2TOARGBROW_AVX2) | 
|  | // 16 pixels. | 
|  | // 8 YUY2 values with 16 Y and 8 UV producing 16 ARGB (64 bytes). | 
|  | void OMITFP YUY2ToARGBRow_AVX2(const uint8_t* yuy2_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READYUY2_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : [yuy2_buf]"+r"(yuy2_buf),    // %[yuy2_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] | 
|  | [kShuffleYUY2Y]"m"(kShuffleYUY2Y), | 
|  | [kShuffleYUY2UV]"m"(kShuffleYUY2UV) | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_YUY2TOARGBROW_AVX2 | 
|  |  | 
|  | #if defined(HAS_UYVYTOARGBROW_AVX2) | 
|  | // 16 pixels. | 
|  | // 8 UYVY values with 16 Y and 8 UV producing 16 ARGB (64 bytes). | 
|  | void OMITFP UYVYToARGBRow_AVX2(const uint8_t* uyvy_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | YUVTORGB_SETUP_AVX2(yuvconstants) | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | READUYVY_AVX2 | 
|  | YUVTORGB_AVX2(yuvconstants) | 
|  | STOREARGB_AVX2 | 
|  | "sub         $0x10,%[width]                \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : [uyvy_buf]"+r"(uyvy_buf),    // %[uyvy_buf] | 
|  | [dst_argb]"+r"(dst_argb),  // %[dst_argb] | 
|  | [width]"+rm"(width)    // %[width] | 
|  | : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] | 
|  | [kShuffleUYVYY]"m"(kShuffleUYVYY), | 
|  | [kShuffleUYVYUV]"m"(kShuffleUYVYUV) | 
|  | : "memory", "cc", YUVTORGB_REGS_AVX2 | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" | 
|  | ); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_UYVYTOARGBROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_I400TOARGBROW_SSE2 | 
|  | void I400ToARGBRow_SSE2(const uint8_t* y_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqa      192(%3),%%xmm2                \n"  // yg = 18997 = 1.164 | 
|  | "movdqa      224(%3),%%xmm3                \n"  // ygb = 1160 = 1.164 * 16 | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n"  // 0xff000000 | 
|  | "pslld       $0x18,%%xmm4                  \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164 | 
|  | "movq      (%0),%%xmm0                     \n" | 
|  | "lea       0x8(%0),%0                      \n" | 
|  | "punpcklbw %%xmm0,%%xmm0                   \n" | 
|  | "pmulhuw   %%xmm2,%%xmm0                   \n" | 
|  | "paddsw    %%xmm3,%%xmm0                   \n" | 
|  | "psraw     $6, %%xmm0                      \n" | 
|  | "packuswb  %%xmm0,%%xmm0                   \n" | 
|  |  | 
|  | // Step 2: Weave into ARGB | 
|  | "punpcklbw %%xmm0,%%xmm0                   \n" | 
|  | "movdqa    %%xmm0,%%xmm1                   \n" | 
|  | "punpcklwd %%xmm0,%%xmm0                   \n" | 
|  | "punpckhwd %%xmm1,%%xmm1                   \n" | 
|  | "por       %%xmm4,%%xmm0                   \n" | 
|  | "por       %%xmm4,%%xmm1                   \n" | 
|  | "movdqu    %%xmm0,(%1)                     \n" | 
|  | "movdqu    %%xmm1,0x10(%1)                 \n" | 
|  | "lea       0x20(%1),%1                     \n" | 
|  |  | 
|  | "sub       $0x8,%2                         \n" | 
|  | "jg        1b                              \n" | 
|  | : "+r"(y_buf),       // %0 | 
|  | "+r"(dst_argb),    // %1 | 
|  | "+rm"(width)       // %2 | 
|  | : "r"(yuvconstants)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); | 
|  | } | 
|  | #endif  // HAS_I400TOARGBROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_I400TOARGBROW_AVX2 | 
|  | // 16 pixels of Y converted to 16 pixels of ARGB (64 bytes). | 
|  | // note: vpunpcklbw mutates and vpackuswb unmutates. | 
|  | void I400ToARGBRow_AVX2(const uint8_t* y_buf, | 
|  | uint8_t* dst_argb, | 
|  | const struct YuvConstants* yuvconstants, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vmovdqa     192(%3),%%ymm2                \n"  // yg = 18997 = 1.164 | 
|  | "vmovdqa     224(%3),%%ymm3                \n"  // ygb = -1160 = 1.164*16 | 
|  | "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n"  // 0xff000000 | 
|  | "vpslld      $0x18,%%ymm4,%%ymm4           \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | // Step 1: Scale Y contribution to 16 G values. G = (y - 16) * 1.164 | 
|  | "vmovdqu    (%0),%%xmm0                    \n" | 
|  | "lea        0x10(%0),%0                    \n" | 
|  | "vpermq     $0xd8,%%ymm0,%%ymm0            \n" | 
|  | "vpunpcklbw %%ymm0,%%ymm0,%%ymm0           \n" | 
|  | "vpmulhuw   %%ymm2,%%ymm0,%%ymm0           \n" | 
|  | "vpaddsw    %%ymm3,%%ymm0,%%ymm0           \n" | 
|  | "vpsraw     $0x6,%%ymm0,%%ymm0             \n" | 
|  | "vpackuswb  %%ymm0,%%ymm0,%%ymm0           \n" | 
|  | "vpunpcklbw %%ymm0,%%ymm0,%%ymm1           \n" | 
|  | "vpermq     $0xd8,%%ymm1,%%ymm1            \n" | 
|  | "vpunpcklwd %%ymm1,%%ymm1,%%ymm0           \n" | 
|  | "vpunpckhwd %%ymm1,%%ymm1,%%ymm1           \n" | 
|  | "vpor       %%ymm4,%%ymm0,%%ymm0           \n" | 
|  | "vpor       %%ymm4,%%ymm1,%%ymm1           \n" | 
|  | "vmovdqu    %%ymm0,(%1)                    \n" | 
|  | "vmovdqu    %%ymm1,0x20(%1)                \n" | 
|  | "lea        0x40(%1),%1                     \n" | 
|  | "sub        $0x10,%2                       \n" | 
|  | "jg        1b                              \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(y_buf),       // %0 | 
|  | "+r"(dst_argb),    // %1 | 
|  | "+rm"(width)       // %2 | 
|  | : "r"(yuvconstants)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); | 
|  | } | 
|  | #endif  // HAS_I400TOARGBROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_MIRRORROW_SSSE3 | 
|  | // Shuffle table for reversing the bytes. | 
|  | static const uvec8 kShuffleMirror = {15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, | 
|  | 7u,  6u,  5u,  4u,  3u,  2u,  1u, 0u}; | 
|  |  | 
|  | void MirrorRow_SSSE3(const uint8_t* src, uint8_t* dst, int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "movdqa      %3,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      -0x10(%0,%2,1),%%xmm0         \n" | 
|  | "pshufb      %%xmm5,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),           // %0 | 
|  | "+r"(dst),           // %1 | 
|  | "+r"(temp_width)     // %2 | 
|  | : "m"(kShuffleMirror)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_MIRRORROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_MIRRORROW_AVX2 | 
|  | void MirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "vbroadcastf128 %3,%%ymm5                  \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     -0x20(%0,%2,1),%%ymm0         \n" | 
|  | "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0x4e,%%ymm0,%%ymm0           \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),           // %0 | 
|  | "+r"(dst),           // %1 | 
|  | "+r"(temp_width)     // %2 | 
|  | : "m"(kShuffleMirror)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_MIRRORROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_MIRRORUVROW_SSSE3 | 
|  | // Shuffle table for reversing the UV. | 
|  | static const uvec8 kShuffleMirrorUV = {14u, 15u, 12u, 13u, 10u, 11u, 8u, 9u, | 
|  | 6u,  7u,  4u,  5u,  2u,  3u,  0u, 1u}; | 
|  |  | 
|  | void MirrorUVRow_SSSE3(const uint8_t* src_uv, uint8_t* dst_uv, int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "movdqa      %3,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      -0x10(%0,%2,2),%%xmm0         \n" | 
|  | "pshufb      %%xmm5,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_uv),          // %0 | 
|  | "+r"(dst_uv),          // %1 | 
|  | "+r"(temp_width)       // %2 | 
|  | : "m"(kShuffleMirrorUV)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_MIRRORUVROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_MIRRORUVROW_AVX2 | 
|  | void MirrorUVRow_AVX2(const uint8_t* src_uv, uint8_t* dst_uv, int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "vbroadcastf128 %3,%%ymm5                  \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     -0x20(%0,%2,2),%%ymm0         \n" | 
|  | "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0x4e,%%ymm0,%%ymm0           \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_uv),          // %0 | 
|  | "+r"(dst_uv),          // %1 | 
|  | "+r"(temp_width)       // %2 | 
|  | : "m"(kShuffleMirrorUV)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_MIRRORUVROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_MIRRORSPLITUVROW_SSSE3 | 
|  | // Shuffle table for reversing the bytes of UV channels. | 
|  | static const uvec8 kShuffleMirrorSplitUV = {14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, | 
|  | 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u}; | 
|  | void MirrorSplitUVRow_SSSE3(const uint8_t* src, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  | "movdqa      %4,%%xmm1                     \n" | 
|  | "lea         -0x10(%0,%3,2),%0             \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "lea         -0x10(%0),%0                  \n" | 
|  | "pshufb      %%xmm1,%%xmm0                 \n" | 
|  | "movlpd      %%xmm0,(%1)                   \n" | 
|  | "movhpd      %%xmm0,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $8,%3                         \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),                  // %0 | 
|  | "+r"(dst_u),                // %1 | 
|  | "+r"(dst_v),                // %2 | 
|  | "+r"(temp_width)            // %3 | 
|  | : "m"(kShuffleMirrorSplitUV)  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_MIRRORSPLITUVROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_RGB24MIRRORROW_SSSE3 | 
|  |  | 
|  | // Shuffle first 5 pixels to last 5 mirrored.  first byte zero | 
|  | static const uvec8 kShuffleMirrorRGB0 = {128u, 12u, 13u, 14u, 9u, 10u, 11u, 6u, | 
|  | 7u,   8u,  3u,  4u,  5u, 0u,  1u,  2u}; | 
|  |  | 
|  | // Shuffle last 5 pixels to first 5 mirrored.  last byte zero | 
|  | static const uvec8 kShuffleMirrorRGB1 = { | 
|  | 13u, 14u, 15u, 10u, 11u, 12u, 7u, 8u, 9u, 4u, 5u, 6u, 1u, 2u, 3u, 128u}; | 
|  |  | 
|  | // Shuffle 5 pixels at a time (15 bytes) | 
|  | void RGB24MirrorRow_SSSE3(const uint8_t* src_rgb24, | 
|  | uint8_t* dst_rgb24, | 
|  | int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | src_rgb24 += width * 3 - 48; | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n"  // first 5 | 
|  | "movdqu      15(%0),%%xmm1                 \n"  // next 5 | 
|  | "movdqu      30(%0),%%xmm2                 \n"  // next 5 | 
|  | "movdqu      32(%0),%%xmm3                 \n"  // last 1 special | 
|  | "pshufb      %%xmm4,%%xmm0                 \n" | 
|  | "pshufb      %%xmm4,%%xmm1                 \n" | 
|  | "pshufb      %%xmm4,%%xmm2                 \n" | 
|  | "pshufb      %%xmm5,%%xmm3                 \n" | 
|  | "lea         -0x30(%0),%0                  \n" | 
|  | "movdqu      %%xmm0,32(%1)                 \n"  // last 5 | 
|  | "movdqu      %%xmm1,17(%1)                 \n"  // next 5 | 
|  | "movdqu      %%xmm2,2(%1)                  \n"  // next 5 | 
|  | "movlpd      %%xmm3,0(%1)                  \n"  // first 1 | 
|  | "lea         0x30(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_rgb24),          // %0 | 
|  | "+r"(dst_rgb24),          // %1 | 
|  | "+r"(temp_width)          // %2 | 
|  | : "m"(kShuffleMirrorRGB0),  // %3 | 
|  | "m"(kShuffleMirrorRGB1)   // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_RGB24MIRRORROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBMIRRORROW_SSE2 | 
|  |  | 
|  | void ARGBMirrorRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "lea         -0x10(%0,%2,4),%0             \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "pshufd      $0x1b,%%xmm0,%%xmm0           \n" | 
|  | "lea         -0x10(%0),%0                  \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),        // %0 | 
|  | "+r"(dst),        // %1 | 
|  | "+r"(temp_width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0"); | 
|  | } | 
|  | #endif  // HAS_ARGBMIRRORROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBMIRRORROW_AVX2 | 
|  | // Shuffle table for reversing the bytes. | 
|  | static const ulvec32 kARGBShuffleMirror_AVX2 = {7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u}; | 
|  | void ARGBMirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | intptr_t temp_width = (intptr_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "vmovdqu     %3,%%ymm5                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpermd      -0x20(%0,%2,4),%%ymm5,%%ymm0  \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),                    // %0 | 
|  | "+r"(dst),                    // %1 | 
|  | "+r"(temp_width)              // %2 | 
|  | : "m"(kARGBShuffleMirror_AVX2)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBMIRRORROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_SPLITUVROW_AVX2 | 
|  | void SplitUVRow_AVX2(const uint8_t* src_uv, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsrlw      $0x8,%%ymm5,%%ymm5            \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm2            \n" | 
|  | "vpsrlw      $0x8,%%ymm1,%%ymm3            \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpand       %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpackuswb   %%ymm3,%%ymm2,%%ymm2          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpermq      $0xd8,%%ymm2,%%ymm2           \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vmovdqu     %%ymm2,0x00(%1,%2,1)          \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_uv),  // %0 | 
|  | "+r"(dst_u),   // %1 | 
|  | "+r"(dst_v),   // %2 | 
|  | "+r"(width)    // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SPLITUVROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_SPLITUVROW_SSE2 | 
|  | void SplitUVRow_SSE2(const uint8_t* src_uv, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $0x8,%%xmm5                   \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "movdqa      %%xmm1,%%xmm3                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "psrlw       $0x8,%%xmm2                   \n" | 
|  | "psrlw       $0x8,%%xmm3                   \n" | 
|  | "packuswb    %%xmm3,%%xmm2                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm2,0x00(%1,%2,1)          \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_uv),  // %0 | 
|  | "+r"(dst_u),   // %1 | 
|  | "+r"(dst_v),   // %2 | 
|  | "+r"(width)    // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SPLITUVROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_MERGEUVROW_AVX2 | 
|  | void MergeUVRow_AVX2(const uint8_t* src_u, | 
|  | const uint8_t* src_v, | 
|  | uint8_t* dst_uv, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x00(%0,%1,1),%%ymm1          \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "vpunpcklbw  %%ymm1,%%ymm0,%%ymm2          \n" | 
|  | "vpunpckhbw  %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vextractf128 $0x0,%%ymm2,(%2)             \n" | 
|  | "vextractf128 $0x0,%%ymm0,0x10(%2)         \n" | 
|  | "vextractf128 $0x1,%%ymm2,0x20(%2)         \n" | 
|  | "vextractf128 $0x1,%%ymm0,0x30(%2)         \n" | 
|  | "lea         0x40(%2),%2                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_u),   // %0 | 
|  | "+r"(src_v),   // %1 | 
|  | "+r"(dst_uv),  // %2 | 
|  | "+r"(width)    // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_MERGEUVROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_MERGEUVROW_SSE2 | 
|  | void MergeUVRow_SSE2(const uint8_t* src_u, | 
|  | const uint8_t* src_v, | 
|  | uint8_t* dst_uv, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%1,1),%%xmm1          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "punpcklbw   %%xmm1,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm1,%%xmm2                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "movdqu      %%xmm2,0x10(%2)               \n" | 
|  | "lea         0x20(%2),%2                   \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_u),   // %0 | 
|  | "+r"(src_v),   // %1 | 
|  | "+r"(dst_uv),  // %2 | 
|  | "+r"(width)    // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_MERGEUVROW_SSE2 | 
|  |  | 
|  | // Use scale to convert lsb formats to msb, depending how many bits there are: | 
|  | // 128 = 9 bits | 
|  | // 64 = 10 bits | 
|  | // 16 = 12 bits | 
|  | // 1 = 16 bits | 
|  | #ifdef HAS_MERGEUVROW_16_AVX2 | 
|  | void MergeUVRow_16_AVX2(const uint16_t* src_u, | 
|  | const uint16_t* src_v, | 
|  | uint16_t* dst_uv, | 
|  | int scale, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | "vmovd       %4,%%xmm3                     \n" | 
|  | "vpunpcklwd  %%xmm3,%%xmm3,%%xmm3          \n" | 
|  | "vbroadcastss %%xmm3,%%ymm3                \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | // 16 pixels per loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     (%0,%1,1),%%ymm1              \n" | 
|  | "add         $0x20,%0                      \n" | 
|  |  | 
|  | "vpmullw     %%ymm3,%%ymm0,%%ymm0          \n" | 
|  | "vpmullw     %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vpunpcklwd  %%ymm1,%%ymm0,%%ymm2          \n"  // mutates | 
|  | "vpunpckhwd  %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vextractf128 $0x0,%%ymm2,(%2)             \n" | 
|  | "vextractf128 $0x0,%%ymm0,0x10(%2)         \n" | 
|  | "vextractf128 $0x1,%%ymm2,0x20(%2)         \n" | 
|  | "vextractf128 $0x1,%%ymm0,0x30(%2)         \n" | 
|  | "add         $0x40,%2                      \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_u),   // %0 | 
|  | "+r"(src_v),   // %1 | 
|  | "+r"(dst_uv),  // %2 | 
|  | "+r"(width)    // %3 | 
|  | : "r"(scale)     // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3"); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_MERGEUVROW_AVX2 | 
|  |  | 
|  | // Use scale to convert lsb formats to msb, depending how many bits there are: | 
|  | // 128 = 9 bits | 
|  | // 64 = 10 bits | 
|  | // 16 = 12 bits | 
|  | // 1 = 16 bits | 
|  | #ifdef HAS_MULTIPLYROW_16_AVX2 | 
|  | void MultiplyRow_16_AVX2(const uint16_t* src_y, | 
|  | uint16_t* dst_y, | 
|  | int scale, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | "vmovd       %3,%%xmm3                     \n" | 
|  | "vpunpcklwd  %%xmm3,%%xmm3,%%xmm3          \n" | 
|  | "vbroadcastss %%xmm3,%%ymm3                \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | // 16 pixels per loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vpmullw     %%ymm3,%%ymm0,%%ymm0          \n" | 
|  | "vpmullw     %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     %%ymm0,(%0,%1)                \n" | 
|  | "vmovdqu     %%ymm1,0x20(%0,%1)            \n" | 
|  | "add         $0x40,%0                      \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_y),   // %0 | 
|  | "+r"(dst_y),   // %1 | 
|  | "+r"(width)    // %2 | 
|  | : "r"(scale)     // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm3"); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_MULTIPLYROW_16_AVX2 | 
|  |  | 
|  | // Use scale to convert lsb formats to msb, depending how many bits there are: | 
|  | // 32768 = 9 bits | 
|  | // 16384 = 10 bits | 
|  | // 4096 = 12 bits | 
|  | // 256 = 16 bits | 
|  | void Convert16To8Row_SSSE3(const uint16_t* src_y, | 
|  | uint8_t* dst_y, | 
|  | int scale, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | "movd        %3,%%xmm2                     \n" | 
|  | "punpcklwd   %%xmm2,%%xmm2                 \n" | 
|  | "pshufd      $0x0,%%xmm2,%%xmm2            \n" | 
|  |  | 
|  | // 32 pixels per loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "add         $0x20,%0                      \n" | 
|  | "pmulhuw     %%xmm2,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "add         $0x10,%1                      \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y),   // %0 | 
|  | "+r"(dst_y),   // %1 | 
|  | "+r"(width)    // %2 | 
|  | : "r"(scale)     // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | // clang-format on | 
|  | } | 
|  |  | 
|  | #ifdef HAS_CONVERT16TO8ROW_AVX2 | 
|  | void Convert16To8Row_AVX2(const uint16_t* src_y, | 
|  | uint8_t* dst_y, | 
|  | int scale, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | "vmovd       %3,%%xmm2                     \n" | 
|  | "vpunpcklwd  %%xmm2,%%xmm2,%%xmm2          \n" | 
|  | "vbroadcastss %%xmm2,%%ymm2                \n" | 
|  |  | 
|  | // 32 pixels per loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "add         $0x40,%0                      \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n"  // mutates | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "add         $0x20,%1                      \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_y),   // %0 | 
|  | "+r"(dst_y),   // %1 | 
|  | "+r"(width)    // %2 | 
|  | : "r"(scale)     // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_CONVERT16TO8ROW_AVX2 | 
|  |  | 
|  | // Use scale to convert to lsb formats depending how many bits there are: | 
|  | // 512 = 9 bits | 
|  | // 1024 = 10 bits | 
|  | // 4096 = 12 bits | 
|  | // TODO(fbarchard): reduce to SSE2 | 
|  | void Convert8To16Row_SSE2(const uint8_t* src_y, | 
|  | uint16_t* dst_y, | 
|  | int scale, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | "movd        %3,%%xmm2                     \n" | 
|  | "punpcklwd   %%xmm2,%%xmm2                 \n" | 
|  | "pshufd      $0x0,%%xmm2,%%xmm2            \n" | 
|  |  | 
|  | // 32 pixels per loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm0,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm1,%%xmm1                 \n" | 
|  | "add         $0x10,%0                      \n" | 
|  | "pmulhuw     %%xmm2,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "add         $0x20,%1                      \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y),   // %0 | 
|  | "+r"(dst_y),   // %1 | 
|  | "+r"(width)    // %2 | 
|  | : "r"(scale)     // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | // clang-format on | 
|  | } | 
|  |  | 
|  | #ifdef HAS_CONVERT8TO16ROW_AVX2 | 
|  | void Convert8To16Row_AVX2(const uint8_t* src_y, | 
|  | uint16_t* dst_y, | 
|  | int scale, | 
|  | int width) { | 
|  | // clang-format off | 
|  | asm volatile ( | 
|  | "vmovd       %3,%%xmm2                     \n" | 
|  | "vpunpcklwd  %%xmm2,%%xmm2,%%xmm2          \n" | 
|  | "vbroadcastss %%xmm2,%%ymm2                \n" | 
|  |  | 
|  | // 32 pixels per loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "add         $0x20,%0                      \n" | 
|  | "vpunpckhbw  %%ymm0,%%ymm0,%%ymm1          \n" | 
|  | "vpunpcklbw  %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "add         $0x40,%1                      \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_y),   // %0 | 
|  | "+r"(dst_y),   // %1 | 
|  | "+r"(width)    // %2 | 
|  | : "r"(scale)     // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | // clang-format on | 
|  | } | 
|  | #endif  // HAS_CONVERT8TO16ROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_SPLITRGBROW_SSSE3 | 
|  |  | 
|  | // Shuffle table for converting RGB to Planar. | 
|  | static const uvec8 kShuffleMaskRGBToR0 = {0u,   3u,   6u,   9u,   12u,  15u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRGBToR1 = {128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 2u,   5u,   8u,   11u,  14u,  128u, | 
|  | 128u, 128u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRGBToR2 = {128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u, 128u, 1u, | 
|  | 4u,   7u,   10u,  13u}; | 
|  |  | 
|  | static const uvec8 kShuffleMaskRGBToG0 = {1u,   4u,   7u,   10u,  13u,  128u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRGBToG1 = {128u, 128u, 128u, 128u, 128u, 0u, | 
|  | 3u,   6u,   9u,   12u,  15u,  128u, | 
|  | 128u, 128u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRGBToG2 = {128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u, 128u, 2u, | 
|  | 5u,   8u,   11u,  14u}; | 
|  |  | 
|  | static const uvec8 kShuffleMaskRGBToB0 = {2u,   5u,   8u,   11u,  14u,  128u, | 
|  | 128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRGBToB1 = {128u, 128u, 128u, 128u, 128u, 1u, | 
|  | 4u,   7u,   10u,  13u,  128u, 128u, | 
|  | 128u, 128u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRGBToB2 = {128u, 128u, 128u, 128u, 128u, 128u, | 
|  | 128u, 128u, 128u, 128u, 0u,   3u, | 
|  | 6u,   9u,   12u,  15u}; | 
|  |  | 
|  | void SplitRGBRow_SSSE3(const uint8_t* src_rgb, | 
|  | uint8_t* dst_r, | 
|  | uint8_t* dst_g, | 
|  | uint8_t* dst_b, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "pshufb      %5, %%xmm0                    \n" | 
|  | "pshufb      %6, %%xmm1                    \n" | 
|  | "pshufb      %7, %%xmm2                    \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  |  | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "pshufb      %8, %%xmm0                    \n" | 
|  | "pshufb      %9, %%xmm1                    \n" | 
|  | "pshufb      %10, %%xmm2                   \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  |  | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "pshufb      %11, %%xmm0                   \n" | 
|  | "pshufb      %12, %%xmm1                   \n" | 
|  | "pshufb      %13, %%xmm2                   \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%3)                   \n" | 
|  | "lea         0x10(%3),%3                   \n" | 
|  | "lea         0x30(%0),%0                   \n" | 
|  | "sub         $0x10,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_rgb),             // %0 | 
|  | "+r"(dst_r),               // %1 | 
|  | "+r"(dst_g),               // %2 | 
|  | "+r"(dst_b),               // %3 | 
|  | "+r"(width)                // %4 | 
|  | : "m"(kShuffleMaskRGBToR0),  // %5 | 
|  | "m"(kShuffleMaskRGBToR1),  // %6 | 
|  | "m"(kShuffleMaskRGBToR2),  // %7 | 
|  | "m"(kShuffleMaskRGBToG0),  // %8 | 
|  | "m"(kShuffleMaskRGBToG1),  // %9 | 
|  | "m"(kShuffleMaskRGBToG2),  // %10 | 
|  | "m"(kShuffleMaskRGBToB0),  // %11 | 
|  | "m"(kShuffleMaskRGBToB1),  // %12 | 
|  | "m"(kShuffleMaskRGBToB2)   // %13 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_SPLITRGBROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_MERGERGBROW_SSSE3 | 
|  |  | 
|  | // Shuffle table for converting RGB to Planar. | 
|  | static const uvec8 kShuffleMaskRToRGB0 = {0u, 128u, 128u, 1u, 128u, 128u, | 
|  | 2u, 128u, 128u, 3u, 128u, 128u, | 
|  | 4u, 128u, 128u, 5u}; | 
|  | static const uvec8 kShuffleMaskGToRGB0 = {128u, 0u, 128u, 128u, 1u, 128u, | 
|  | 128u, 2u, 128u, 128u, 3u, 128u, | 
|  | 128u, 4u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskBToRGB0 = {128u, 128u, 0u, 128u, 128u, 1u, | 
|  | 128u, 128u, 2u, 128u, 128u, 3u, | 
|  | 128u, 128u, 4u, 128u}; | 
|  |  | 
|  | static const uvec8 kShuffleMaskGToRGB1 = {5u, 128u, 128u, 6u, 128u, 128u, | 
|  | 7u, 128u, 128u, 8u, 128u, 128u, | 
|  | 9u, 128u, 128u, 10u}; | 
|  | static const uvec8 kShuffleMaskBToRGB1 = {128u, 5u, 128u, 128u, 6u, 128u, | 
|  | 128u, 7u, 128u, 128u, 8u, 128u, | 
|  | 128u, 9u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskRToRGB1 = {128u, 128u, 6u,  128u, 128u, 7u, | 
|  | 128u, 128u, 8u,  128u, 128u, 9u, | 
|  | 128u, 128u, 10u, 128u}; | 
|  |  | 
|  | static const uvec8 kShuffleMaskBToRGB2 = {10u, 128u, 128u, 11u, 128u, 128u, | 
|  | 12u, 128u, 128u, 13u, 128u, 128u, | 
|  | 14u, 128u, 128u, 15u}; | 
|  | static const uvec8 kShuffleMaskRToRGB2 = {128u, 11u, 128u, 128u, 12u, 128u, | 
|  | 128u, 13u, 128u, 128u, 14u, 128u, | 
|  | 128u, 15u, 128u, 128u}; | 
|  | static const uvec8 kShuffleMaskGToRGB2 = {128u, 128u, 11u, 128u, 128u, 12u, | 
|  | 128u, 128u, 13u, 128u, 128u, 14u, | 
|  | 128u, 128u, 15u, 128u}; | 
|  |  | 
|  | void MergeRGBRow_SSSE3(const uint8_t* src_r, | 
|  | const uint8_t* src_g, | 
|  | const uint8_t* src_b, | 
|  | uint8_t* dst_rgb, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      (%1),%%xmm1                   \n" | 
|  | "movdqu      (%2),%%xmm2                   \n" | 
|  | "pshufb      %5, %%xmm0                    \n" | 
|  | "pshufb      %6, %%xmm1                    \n" | 
|  | "pshufb      %7, %%xmm2                    \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%3)                   \n" | 
|  |  | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      (%1),%%xmm1                   \n" | 
|  | "movdqu      (%2),%%xmm2                   \n" | 
|  | "pshufb      %8, %%xmm0                    \n" | 
|  | "pshufb      %9, %%xmm1                    \n" | 
|  | "pshufb      %10, %%xmm2                   \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,16(%3)                 \n" | 
|  |  | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      (%1),%%xmm1                   \n" | 
|  | "movdqu      (%2),%%xmm2                   \n" | 
|  | "pshufb      %11, %%xmm0                   \n" | 
|  | "pshufb      %12, %%xmm1                   \n" | 
|  | "pshufb      %13, %%xmm2                   \n" | 
|  | "por         %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,32(%3)                 \n" | 
|  |  | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "lea         0x30(%3),%3                   \n" | 
|  | "sub         $0x10,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_r),               // %0 | 
|  | "+r"(src_g),               // %1 | 
|  | "+r"(src_b),               // %2 | 
|  | "+r"(dst_rgb),             // %3 | 
|  | "+r"(width)                // %4 | 
|  | : "m"(kShuffleMaskRToRGB0),  // %5 | 
|  | "m"(kShuffleMaskGToRGB0),  // %6 | 
|  | "m"(kShuffleMaskBToRGB0),  // %7 | 
|  | "m"(kShuffleMaskRToRGB1),  // %8 | 
|  | "m"(kShuffleMaskGToRGB1),  // %9 | 
|  | "m"(kShuffleMaskBToRGB1),  // %10 | 
|  | "m"(kShuffleMaskRToRGB2),  // %11 | 
|  | "m"(kShuffleMaskGToRGB2),  // %12 | 
|  | "m"(kShuffleMaskBToRGB2)   // %13 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_MERGERGBROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_COPYROW_SSE2 | 
|  | void CopyRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "test        $0xf,%0                       \n" | 
|  | "jne         2f                            \n" | 
|  | "test        $0xf,%1                       \n" | 
|  | "jne         2f                            \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqa      (%0),%%xmm0                   \n" | 
|  | "movdqa      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,(%1)                   \n" | 
|  | "movdqa      %%xmm1,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "jmp         9f                            \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "2:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          2b                            \n" | 
|  |  | 
|  | LABELALIGN "9:                                        \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_COPYROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_COPYROW_AVX | 
|  | void CopyRow_AVX(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x40,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_COPYROW_AVX | 
|  |  | 
|  | #ifdef HAS_COPYROW_ERMS | 
|  | // Multiple of 1. | 
|  | void CopyRow_ERMS(const uint8_t* src, uint8_t* dst, int width) { | 
|  | size_t width_tmp = (size_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "rep         movsb                         \n" | 
|  | : "+S"(src),       // %0 | 
|  | "+D"(dst),       // %1 | 
|  | "+c"(width_tmp)  // %2 | 
|  | : | 
|  | : "memory", "cc"); | 
|  | } | 
|  | #endif  // HAS_COPYROW_ERMS | 
|  |  | 
|  | #ifdef HAS_ARGBCOPYALPHAROW_SSE2 | 
|  | // width in pixels | 
|  | void ARGBCopyAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm0,%%xmm0                 \n" | 
|  | "pslld       $0x18,%%xmm0                  \n" | 
|  | "pcmpeqb     %%xmm1,%%xmm1                 \n" | 
|  | "psrld       $0x8,%%xmm1                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm2                   \n" | 
|  | "movdqu      0x10(%0),%%xmm3               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "movdqu      (%1),%%xmm4                   \n" | 
|  | "movdqu      0x10(%1),%%xmm5               \n" | 
|  | "pand        %%xmm0,%%xmm2                 \n" | 
|  | "pand        %%xmm0,%%xmm3                 \n" | 
|  | "pand        %%xmm1,%%xmm4                 \n" | 
|  | "pand        %%xmm1,%%xmm5                 \n" | 
|  | "por         %%xmm4,%%xmm2                 \n" | 
|  | "por         %%xmm5,%%xmm3                 \n" | 
|  | "movdqu      %%xmm2,(%1)                   \n" | 
|  | "movdqu      %%xmm3,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBCOPYALPHAROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBCOPYALPHAROW_AVX2 | 
|  | // width in pixels | 
|  | void ARGBCopyAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpsrld      $0x8,%%ymm0,%%ymm0            \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm1                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm2               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpblendvb   %%ymm0,(%1),%%ymm1,%%ymm1     \n" | 
|  | "vpblendvb   %%ymm0,0x20(%1),%%ymm2,%%ymm2 \n" | 
|  | "vmovdqu     %%ymm1,(%1)                   \n" | 
|  | "vmovdqu     %%ymm2,0x20(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_ARGBCOPYALPHAROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBEXTRACTALPHAROW_SSE2 | 
|  | // width in pixels | 
|  | void ARGBExtractAlphaRow_SSE2(const uint8_t* src_argb, | 
|  | uint8_t* dst_a, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0), %%xmm0                  \n" | 
|  | "movdqu      0x10(%0), %%xmm1              \n" | 
|  | "lea         0x20(%0), %0                  \n" | 
|  | "psrld       $0x18, %%xmm0                 \n" | 
|  | "psrld       $0x18, %%xmm1                 \n" | 
|  | "packssdw    %%xmm1, %%xmm0                \n" | 
|  | "packuswb    %%xmm0, %%xmm0                \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1), %1                   \n" | 
|  | "sub         $0x8, %2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_a),     // %1 | 
|  | "+rm"(width)     // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_ARGBEXTRACTALPHAROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBEXTRACTALPHAROW_AVX2 | 
|  | static const uvec8 kShuffleAlphaShort_AVX2 = { | 
|  | 3u,  128u, 128u, 128u, 7u,  128u, 128u, 128u, | 
|  | 11u, 128u, 128u, 128u, 15u, 128u, 128u, 128u}; | 
|  |  | 
|  | void ARGBExtractAlphaRow_AVX2(const uint8_t* src_argb, | 
|  | uint8_t* dst_a, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vmovdqa     %3,%%ymm4                     \n" | 
|  | "vbroadcastf128 %4,%%ymm5                  \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0), %%ymm0                  \n" | 
|  | "vmovdqu     0x20(%0), %%ymm1              \n" | 
|  | "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"  // vpsrld $0x18, %%ymm0 | 
|  | "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     0x40(%0), %%ymm2              \n" | 
|  | "vmovdqu     0x60(%0), %%ymm3              \n" | 
|  | "lea         0x80(%0), %0                  \n" | 
|  | "vpackssdw   %%ymm1, %%ymm0, %%ymm0        \n"  // mutates | 
|  | "vpshufb     %%ymm5,%%ymm2,%%ymm2          \n" | 
|  | "vpshufb     %%ymm5,%%ymm3,%%ymm3          \n" | 
|  | "vpackssdw   %%ymm3, %%ymm2, %%ymm2        \n"  // mutates | 
|  | "vpackuswb   %%ymm2,%%ymm0,%%ymm0          \n"  // mutates. | 
|  | "vpermd      %%ymm0,%%ymm4,%%ymm0          \n"  // unmutate. | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20, %2                     \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb),               // %0 | 
|  | "+r"(dst_a),                  // %1 | 
|  | "+rm"(width)                  // %2 | 
|  | : "m"(kPermdARGBToY_AVX),       // %3 | 
|  | "m"(kShuffleAlphaShort_AVX2)  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBEXTRACTALPHAROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBCOPYYTOALPHAROW_SSE2 | 
|  | // width in pixels | 
|  | void ARGBCopyYToAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm0,%%xmm0                 \n" | 
|  | "pslld       $0x18,%%xmm0                  \n" | 
|  | "pcmpeqb     %%xmm1,%%xmm1                 \n" | 
|  | "psrld       $0x8,%%xmm1                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%0),%%xmm2                   \n" | 
|  | "lea         0x8(%0),%0                    \n" | 
|  | "punpcklbw   %%xmm2,%%xmm2                 \n" | 
|  | "punpckhwd   %%xmm2,%%xmm3                 \n" | 
|  | "punpcklwd   %%xmm2,%%xmm2                 \n" | 
|  | "movdqu      (%1),%%xmm4                   \n" | 
|  | "movdqu      0x10(%1),%%xmm5               \n" | 
|  | "pand        %%xmm0,%%xmm2                 \n" | 
|  | "pand        %%xmm0,%%xmm3                 \n" | 
|  | "pand        %%xmm1,%%xmm4                 \n" | 
|  | "pand        %%xmm1,%%xmm5                 \n" | 
|  | "por         %%xmm4,%%xmm2                 \n" | 
|  | "por         %%xmm5,%%xmm3                 \n" | 
|  | "movdqu      %%xmm2,(%1)                   \n" | 
|  | "movdqu      %%xmm3,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBCOPYYTOALPHAROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2 | 
|  | // width in pixels | 
|  | void ARGBCopyYToAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpsrld      $0x8,%%ymm0,%%ymm0            \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpmovzxbd   (%0),%%ymm1                   \n" | 
|  | "vpmovzxbd   0x8(%0),%%ymm2                \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "vpslld      $0x18,%%ymm1,%%ymm1           \n" | 
|  | "vpslld      $0x18,%%ymm2,%%ymm2           \n" | 
|  | "vpblendvb   %%ymm0,(%1),%%ymm1,%%ymm1     \n" | 
|  | "vpblendvb   %%ymm0,0x20(%1),%%ymm2,%%ymm2 \n" | 
|  | "vmovdqu     %%ymm1,(%1)                   \n" | 
|  | "vmovdqu     %%ymm2,0x20(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_ARGBCOPYYTOALPHAROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_SETROW_X86 | 
|  | void SetRow_X86(uint8_t* dst, uint8_t v8, int width) { | 
|  | size_t width_tmp = (size_t)(width >> 2); | 
|  | const uint32_t v32 = v8 * 0x01010101u;  // Duplicate byte to all bytes. | 
|  | asm volatile( | 
|  |  | 
|  | "rep         stosl                         \n" | 
|  | : "+D"(dst),       // %0 | 
|  | "+c"(width_tmp)  // %1 | 
|  | : "a"(v32)         // %2 | 
|  | : "memory", "cc"); | 
|  | } | 
|  |  | 
|  | void SetRow_ERMS(uint8_t* dst, uint8_t v8, int width) { | 
|  | size_t width_tmp = (size_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "rep         stosb                         \n" | 
|  | : "+D"(dst),       // %0 | 
|  | "+c"(width_tmp)  // %1 | 
|  | : "a"(v8)          // %2 | 
|  | : "memory", "cc"); | 
|  | } | 
|  |  | 
|  | void ARGBSetRow_X86(uint8_t* dst_argb, uint32_t v32, int width) { | 
|  | size_t width_tmp = (size_t)(width); | 
|  | asm volatile( | 
|  |  | 
|  | "rep         stosl                         \n" | 
|  | : "+D"(dst_argb),  // %0 | 
|  | "+c"(width_tmp)  // %1 | 
|  | : "a"(v32)         // %2 | 
|  | : "memory", "cc"); | 
|  | } | 
|  | #endif  // HAS_SETROW_X86 | 
|  |  | 
|  | #ifdef HAS_YUY2TOYROW_SSE2 | 
|  | void YUY2ToYRow_SSE2(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $0x8,%%xmm5                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_yuy2),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  |  | 
|  | void YUY2ToUVRow_SSE2(const uint8_t* src_yuy2, | 
|  | int stride_yuy2, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $0x8,%%xmm5                   \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm2          \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm3          \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "pavgb       %%xmm2,%%xmm0                 \n" | 
|  | "pavgb       %%xmm3,%%xmm1                 \n" | 
|  | "psrlw       $0x8,%%xmm0                   \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm1                 \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "movq        %%xmm1,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_yuy2),               // %0 | 
|  | "+r"(dst_u),                  // %1 | 
|  | "+r"(dst_v),                  // %2 | 
|  | "+r"(width)                   // %3 | 
|  | : "r"((intptr_t)(stride_yuy2))  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  |  | 
|  | void YUY2ToUV422Row_SSE2(const uint8_t* src_yuy2, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $0x8,%%xmm5                   \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "psrlw       $0x8,%%xmm0                   \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm1                 \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "movq        %%xmm1,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_yuy2),  // %0 | 
|  | "+r"(dst_u),     // %1 | 
|  | "+r"(dst_v),     // %2 | 
|  | "+r"(width)      // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  |  | 
|  | void UYVYToYRow_SSE2(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "psrlw       $0x8,%%xmm0                   \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_uyvy),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  |  | 
|  | void UYVYToUVRow_SSE2(const uint8_t* src_uyvy, | 
|  | int stride_uyvy, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $0x8,%%xmm5                   \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x00(%0,%4,1),%%xmm2          \n" | 
|  | "movdqu      0x10(%0,%4,1),%%xmm3          \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "pavgb       %%xmm2,%%xmm0                 \n" | 
|  | "pavgb       %%xmm3,%%xmm1                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm1                 \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "movq        %%xmm1,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_uyvy),               // %0 | 
|  | "+r"(dst_u),                  // %1 | 
|  | "+r"(dst_v),                  // %2 | 
|  | "+r"(width)                   // %3 | 
|  | : "r"((intptr_t)(stride_uyvy))  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  |  | 
|  | void UYVYToUV422Row_SSE2(const uint8_t* src_uyvy, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psrlw       $0x8,%%xmm5                   \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "pand        %%xmm5,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm1                 \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "movq        %%xmm1,0x00(%1,%2,1)          \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_uyvy),  // %0 | 
|  | "+r"(dst_u),     // %1 | 
|  | "+r"(dst_v),     // %2 | 
|  | "+r"(width)      // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_YUY2TOYROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_YUY2TOYROW_AVX2 | 
|  | void YUY2ToYRow_AVX2(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsrlw      $0x8,%%ymm5,%%ymm5            \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpand       %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_yuy2),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  |  | 
|  | void YUY2ToUVRow_AVX2(const uint8_t* src_yuy2, | 
|  | int stride_yuy2, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsrlw      $0x8,%%ymm5,%%ymm5            \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n" | 
|  | "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpsrlw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm1          \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm1,%%ymm1           \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vextractf128 $0x0,%%ymm1,(%1)             \n" | 
|  | "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1)    \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_yuy2),               // %0 | 
|  | "+r"(dst_u),                  // %1 | 
|  | "+r"(dst_v),                  // %2 | 
|  | "+r"(width)                   // %3 | 
|  | : "r"((intptr_t)(stride_yuy2))  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  |  | 
|  | void YUY2ToUV422Row_AVX2(const uint8_t* src_yuy2, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsrlw      $0x8,%%ymm5,%%ymm5            \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpsrlw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm1          \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm1,%%ymm1           \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vextractf128 $0x0,%%ymm1,(%1)             \n" | 
|  | "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1)    \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_yuy2),  // %0 | 
|  | "+r"(dst_u),     // %1 | 
|  | "+r"(dst_v),     // %2 | 
|  | "+r"(width)      // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  |  | 
|  | void UYVYToYRow_AVX2(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpsrlw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_uyvy),  // %0 | 
|  | "+r"(dst_y),     // %1 | 
|  | "+r"(width)      // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | void UYVYToUVRow_AVX2(const uint8_t* src_uyvy, | 
|  | int stride_uyvy, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsrlw      $0x8,%%ymm5,%%ymm5            \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n" | 
|  | "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpand       %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm1          \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm1,%%ymm1           \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vextractf128 $0x0,%%ymm1,(%1)             \n" | 
|  | "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1)    \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_uyvy),               // %0 | 
|  | "+r"(dst_u),                  // %1 | 
|  | "+r"(dst_v),                  // %2 | 
|  | "+r"(width)                   // %3 | 
|  | : "r"((intptr_t)(stride_uyvy))  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  |  | 
|  | void UYVYToUV422Row_AVX2(const uint8_t* src_uyvy, | 
|  | uint8_t* dst_u, | 
|  | uint8_t* dst_v, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsrlw      $0x8,%%ymm5,%%ymm5            \n" | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpand       %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpand       %%ymm5,%%ymm0,%%ymm1          \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm1,%%ymm1           \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vextractf128 $0x0,%%ymm1,(%1)             \n" | 
|  | "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1)    \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x20,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_uyvy),  // %0 | 
|  | "+r"(dst_u),     // %1 | 
|  | "+r"(dst_v),     // %2 | 
|  | "+r"(width)      // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_YUY2TOYROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBBLENDROW_SSSE3 | 
|  | // Shuffle table for isolating alpha. | 
|  | static const uvec8 kShuffleAlpha = {3u,  0x80, 3u,  0x80, 7u,  0x80, 7u,  0x80, | 
|  | 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80}; | 
|  |  | 
|  | // Blend 8 pixels at a time | 
|  | void ARGBBlendRow_SSSE3(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm7,%%xmm7                 \n" | 
|  | "psrlw       $0xf,%%xmm7                   \n" | 
|  | "pcmpeqb     %%xmm6,%%xmm6                 \n" | 
|  | "psrlw       $0x8,%%xmm6                   \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psllw       $0x8,%%xmm5                   \n" | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "pslld       $0x18,%%xmm4                  \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jl          49f                           \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "40:                                       \n" | 
|  | "movdqu      (%0),%%xmm3                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqa      %%xmm3,%%xmm0                 \n" | 
|  | "pxor        %%xmm4,%%xmm3                 \n" | 
|  | "movdqu      (%1),%%xmm2                   \n" | 
|  | "pshufb      %4,%%xmm3                     \n" | 
|  | "pand        %%xmm6,%%xmm2                 \n" | 
|  | "paddw       %%xmm7,%%xmm3                 \n" | 
|  | "pmullw      %%xmm3,%%xmm2                 \n" | 
|  | "movdqu      (%1),%%xmm1                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "por         %%xmm4,%%xmm0                 \n" | 
|  | "pmullw      %%xmm3,%%xmm1                 \n" | 
|  | "psrlw       $0x8,%%xmm2                   \n" | 
|  | "paddusb     %%xmm2,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm1                 \n" | 
|  | "paddusb     %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jge         40b                           \n" | 
|  |  | 
|  | "49:                                       \n" | 
|  | "add         $0x3,%3                       \n" | 
|  | "jl          99f                           \n" | 
|  |  | 
|  | // 1 pixel loop. | 
|  | "91:                                       \n" | 
|  | "movd        (%0),%%xmm3                   \n" | 
|  | "lea         0x4(%0),%0                    \n" | 
|  | "movdqa      %%xmm3,%%xmm0                 \n" | 
|  | "pxor        %%xmm4,%%xmm3                 \n" | 
|  | "movd        (%1),%%xmm2                   \n" | 
|  | "pshufb      %4,%%xmm3                     \n" | 
|  | "pand        %%xmm6,%%xmm2                 \n" | 
|  | "paddw       %%xmm7,%%xmm3                 \n" | 
|  | "pmullw      %%xmm3,%%xmm2                 \n" | 
|  | "movd        (%1),%%xmm1                   \n" | 
|  | "lea         0x4(%1),%1                    \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "por         %%xmm4,%%xmm0                 \n" | 
|  | "pmullw      %%xmm3,%%xmm1                 \n" | 
|  | "psrlw       $0x8,%%xmm2                   \n" | 
|  | "paddusb     %%xmm2,%%xmm0                 \n" | 
|  | "pand        %%xmm5,%%xmm1                 \n" | 
|  | "paddusb     %%xmm1,%%xmm0                 \n" | 
|  | "movd        %%xmm0,(%2)                   \n" | 
|  | "lea         0x4(%2),%2                    \n" | 
|  | "sub         $0x1,%3                       \n" | 
|  | "jge         91b                           \n" | 
|  | "99:                                       \n" | 
|  | : "+r"(src_argb0),    // %0 | 
|  | "+r"(src_argb1),    // %1 | 
|  | "+r"(dst_argb),     // %2 | 
|  | "+r"(width)         // %3 | 
|  | : "m"(kShuffleAlpha)  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBBLENDROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_BLENDPLANEROW_SSSE3 | 
|  | // Blend 8 pixels at a time. | 
|  | // unsigned version of math | 
|  | // =((A2*C2)+(B2*(255-C2))+255)/256 | 
|  | // signed version of math | 
|  | // =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 | 
|  | void BlendPlaneRow_SSSE3(const uint8_t* src0, | 
|  | const uint8_t* src1, | 
|  | const uint8_t* alpha, | 
|  | uint8_t* dst, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "psllw       $0x8,%%xmm5                   \n" | 
|  | "mov         $0x80808080,%%eax             \n" | 
|  | "movd        %%eax,%%xmm6                  \n" | 
|  | "pshufd      $0x0,%%xmm6,%%xmm6            \n" | 
|  | "mov         $0x807f807f,%%eax             \n" | 
|  | "movd        %%eax,%%xmm7                  \n" | 
|  | "pshufd      $0x0,%%xmm7,%%xmm7            \n" | 
|  | "sub         %2,%0                         \n" | 
|  | "sub         %2,%1                         \n" | 
|  | "sub         %2,%3                         \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%2),%%xmm0                   \n" | 
|  | "punpcklbw   %%xmm0,%%xmm0                 \n" | 
|  | "pxor        %%xmm5,%%xmm0                 \n" | 
|  | "movq        (%0,%2,1),%%xmm1              \n" | 
|  | "movq        (%1,%2,1),%%xmm2              \n" | 
|  | "punpcklbw   %%xmm2,%%xmm1                 \n" | 
|  | "psubb       %%xmm6,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm1,%%xmm0                 \n" | 
|  | "paddw       %%xmm7,%%xmm0                 \n" | 
|  | "psrlw       $0x8,%%xmm0                   \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "movq        %%xmm0,(%3,%2,1)              \n" | 
|  | "lea         0x8(%2),%2                    \n" | 
|  | "sub         $0x8,%4                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src0),   // %0 | 
|  | "+r"(src1),   // %1 | 
|  | "+r"(alpha),  // %2 | 
|  | "+r"(dst),    // %3 | 
|  | "+rm"(width)  // %4 | 
|  | ::"memory", | 
|  | "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm5", "xmm6", "xmm7"); | 
|  | } | 
|  | #endif  // HAS_BLENDPLANEROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_BLENDPLANEROW_AVX2 | 
|  | // Blend 32 pixels at a time. | 
|  | // unsigned version of math | 
|  | // =((A2*C2)+(B2*(255-C2))+255)/256 | 
|  | // signed version of math | 
|  | // =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 | 
|  | void BlendPlaneRow_AVX2(const uint8_t* src0, | 
|  | const uint8_t* src1, | 
|  | const uint8_t* alpha, | 
|  | uint8_t* dst, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpsllw      $0x8,%%ymm5,%%ymm5            \n" | 
|  | "mov         $0x80808080,%%eax             \n" | 
|  | "vmovd       %%eax,%%xmm6                  \n" | 
|  | "vbroadcastss %%xmm6,%%ymm6                \n" | 
|  | "mov         $0x807f807f,%%eax             \n" | 
|  | "vmovd       %%eax,%%xmm7                  \n" | 
|  | "vbroadcastss %%xmm7,%%ymm7                \n" | 
|  | "sub         %2,%0                         \n" | 
|  | "sub         %2,%1                         \n" | 
|  | "sub         %2,%3                         \n" | 
|  |  | 
|  | // 32 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%2),%%ymm0                   \n" | 
|  | "vpunpckhbw  %%ymm0,%%ymm0,%%ymm3          \n" | 
|  | "vpunpcklbw  %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpxor       %%ymm5,%%ymm3,%%ymm3          \n" | 
|  | "vpxor       %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     (%0,%2,1),%%ymm1              \n" | 
|  | "vmovdqu     (%1,%2,1),%%ymm2              \n" | 
|  | "vpunpckhbw  %%ymm2,%%ymm1,%%ymm4          \n" | 
|  | "vpunpcklbw  %%ymm2,%%ymm1,%%ymm1          \n" | 
|  | "vpsubb      %%ymm6,%%ymm4,%%ymm4          \n" | 
|  | "vpsubb      %%ymm6,%%ymm1,%%ymm1          \n" | 
|  | "vpmaddubsw  %%ymm4,%%ymm3,%%ymm3          \n" | 
|  | "vpmaddubsw  %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpaddw      %%ymm7,%%ymm3,%%ymm3          \n" | 
|  | "vpaddw      %%ymm7,%%ymm0,%%ymm0          \n" | 
|  | "vpsrlw      $0x8,%%ymm3,%%ymm3            \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpackuswb   %%ymm3,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,(%3,%2,1)              \n" | 
|  | "lea         0x20(%2),%2                   \n" | 
|  | "sub         $0x20,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src0),   // %0 | 
|  | "+r"(src1),   // %1 | 
|  | "+r"(alpha),  // %2 | 
|  | "+r"(dst),    // %3 | 
|  | "+rm"(width)  // %4 | 
|  | ::"memory", | 
|  | "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_BLENDPLANEROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBATTENUATEROW_SSSE3 | 
|  | // Shuffle table duplicating alpha. | 
|  | static const uvec8 kShuffleAlpha0 = {3u, 3u, 3u, 3u, 3u, 3u, 128u, 128u, | 
|  | 7u, 7u, 7u, 7u, 7u, 7u, 128u, 128u}; | 
|  | static const uvec8 kShuffleAlpha1 = {11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u, | 
|  | 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u}; | 
|  | // Attenuate 4 pixels at a time. | 
|  | void ARGBAttenuateRow_SSSE3(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm3,%%xmm3                 \n" | 
|  | "pslld       $0x18,%%xmm3                  \n" | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "pshufb      %%xmm4,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm1                   \n" | 
|  | "punpcklbw   %%xmm1,%%xmm1                 \n" | 
|  | "pmulhuw     %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm1                   \n" | 
|  | "pshufb      %%xmm5,%%xmm1                 \n" | 
|  | "movdqu      (%0),%%xmm2                   \n" | 
|  | "punpckhbw   %%xmm2,%%xmm2                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm1                 \n" | 
|  | "movdqu      (%0),%%xmm2                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "pand        %%xmm3,%%xmm2                 \n" | 
|  | "psrlw       $0x8,%%xmm0                   \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),       // %0 | 
|  | "+r"(dst_argb),       // %1 | 
|  | "+r"(width)           // %2 | 
|  | : "m"(kShuffleAlpha0),  // %3 | 
|  | "m"(kShuffleAlpha1)   // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBATTENUATEROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBATTENUATEROW_AVX2 | 
|  | // Shuffle table duplicating alpha. | 
|  | static const uvec8 kShuffleAlpha_AVX2 = {6u,   7u,   6u,   7u,  6u,  7u, | 
|  | 128u, 128u, 14u,  15u, 14u, 15u, | 
|  | 14u,  15u,  128u, 128u}; | 
|  | // Attenuate 8 pixels at a time. | 
|  | void ARGBAttenuateRow_AVX2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 %3,%%ymm4                  \n" | 
|  | "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "vpslld      $0x18,%%ymm5,%%ymm5           \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm6                   \n" | 
|  | "vpunpcklbw  %%ymm6,%%ymm6,%%ymm0          \n" | 
|  | "vpunpckhbw  %%ymm6,%%ymm6,%%ymm1          \n" | 
|  | "vpshufb     %%ymm4,%%ymm0,%%ymm2          \n" | 
|  | "vpshufb     %%ymm4,%%ymm1,%%ymm3          \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vpand       %%ymm5,%%ymm6,%%ymm6          \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpsrlw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vpor        %%ymm6,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,0x00(%0,%1,1)          \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb),          // %0 | 
|  | "+r"(dst_argb),          // %1 | 
|  | "+r"(width)              // %2 | 
|  | : "m"(kShuffleAlpha_AVX2)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_ARGBATTENUATEROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBUNATTENUATEROW_SSE2 | 
|  | // Unattenuate 4 pixels at a time. | 
|  | void ARGBUnattenuateRow_SSE2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | uintptr_t alpha; | 
|  | asm volatile( | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movzb       0x03(%0),%3                   \n" | 
|  | "punpcklbw   %%xmm0,%%xmm0                 \n" | 
|  | "movd        0x00(%4,%3,4),%%xmm2          \n" | 
|  | "movzb       0x07(%0),%3                   \n" | 
|  | "movd        0x00(%4,%3,4),%%xmm3          \n" | 
|  | "pshuflw     $0x40,%%xmm2,%%xmm2           \n" | 
|  | "pshuflw     $0x40,%%xmm3,%%xmm3           \n" | 
|  | "movlhps     %%xmm3,%%xmm2                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm1                   \n" | 
|  | "movzb       0x0b(%0),%3                   \n" | 
|  | "punpckhbw   %%xmm1,%%xmm1                 \n" | 
|  | "movd        0x00(%4,%3,4),%%xmm2          \n" | 
|  | "movzb       0x0f(%0),%3                   \n" | 
|  | "movd        0x00(%4,%3,4),%%xmm3          \n" | 
|  | "pshuflw     $0x40,%%xmm2,%%xmm2           \n" | 
|  | "pshuflw     $0x40,%%xmm3,%%xmm3           \n" | 
|  | "movlhps     %%xmm3,%%xmm2                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm1                 \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),     // %0 | 
|  | "+r"(dst_argb),     // %1 | 
|  | "+r"(width),        // %2 | 
|  | "=&r"(alpha)        // %3 | 
|  | : "r"(fixed_invtbl8)  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBUNATTENUATEROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBUNATTENUATEROW_AVX2 | 
|  | // Shuffle table duplicating alpha. | 
|  | static const uvec8 kUnattenShuffleAlpha_AVX2 = { | 
|  | 0u, 1u, 0u, 1u, 0u, 1u, 6u, 7u, 8u, 9u, 8u, 9u, 8u, 9u, 14u, 15u}; | 
|  | // Unattenuate 8 pixels at a time. | 
|  | void ARGBUnattenuateRow_AVX2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | uintptr_t alpha; | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | "vbroadcastf128 %5,%%ymm5                  \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | // replace VPGATHER | 
|  | "movzb       0x03(%0),%3                   \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm0          \n" | 
|  | "movzb       0x07(%0),%3                   \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm1          \n" | 
|  | "movzb       0x0b(%0),%3                   \n" | 
|  | "vpunpckldq  %%xmm1,%%xmm0,%%xmm6          \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm2          \n" | 
|  | "movzb       0x0f(%0),%3                   \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm3          \n" | 
|  | "movzb       0x13(%0),%3                   \n" | 
|  | "vpunpckldq  %%xmm3,%%xmm2,%%xmm7          \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm0          \n" | 
|  | "movzb       0x17(%0),%3                   \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm1          \n" | 
|  | "movzb       0x1b(%0),%3                   \n" | 
|  | "vpunpckldq  %%xmm1,%%xmm0,%%xmm0          \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm2          \n" | 
|  | "movzb       0x1f(%0),%3                   \n" | 
|  | "vmovd       0x00(%4,%3,4),%%xmm3          \n" | 
|  | "vpunpckldq  %%xmm3,%%xmm2,%%xmm2          \n" | 
|  | "vpunpcklqdq %%xmm7,%%xmm6,%%xmm3          \n" | 
|  | "vpunpcklqdq %%xmm2,%%xmm0,%%xmm0          \n" | 
|  | "vinserti128 $0x1,%%xmm0,%%ymm3,%%ymm3     \n" | 
|  | // end of VPGATHER | 
|  |  | 
|  | "vmovdqu     (%0),%%ymm6                   \n" | 
|  | "vpunpcklbw  %%ymm6,%%ymm6,%%ymm0          \n" | 
|  | "vpunpckhbw  %%ymm6,%%ymm6,%%ymm1          \n" | 
|  | "vpunpcklwd  %%ymm3,%%ymm3,%%ymm2          \n" | 
|  | "vpunpckhwd  %%ymm3,%%ymm3,%%ymm3          \n" | 
|  | "vpshufb     %%ymm5,%%ymm2,%%ymm2          \n" | 
|  | "vpshufb     %%ymm5,%%ymm3,%%ymm3          \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,0x00(%0,%1,1)          \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb),                 // %0 | 
|  | "+r"(dst_argb),                 // %1 | 
|  | "+r"(width),                    // %2 | 
|  | "=&r"(alpha)                    // %3 | 
|  | : "r"(fixed_invtbl8),             // %4 | 
|  | "m"(kUnattenShuffleAlpha_AVX2)  // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBUNATTENUATEROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBGRAYROW_SSSE3 | 
|  | // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels | 
|  | void ARGBGrayRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_argb, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %3,%%xmm4                     \n" | 
|  | "movdqa      %4,%%xmm5                     \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "psubb       %%xmm5,%%xmm0                 \n" | 
|  | "psubb       %%xmm5,%%xmm1                 \n" | 
|  | "movdqu      %%xmm4,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm0,%%xmm6                 \n" | 
|  | "movdqu      %%xmm4,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm1,%%xmm0                 \n" | 
|  | "phaddw      %%xmm0,%%xmm6                 \n" | 
|  | "paddw       %%xmm5,%%xmm6                 \n" | 
|  | "psrlw       $0x8,%%xmm6                   \n" | 
|  | "packuswb    %%xmm6,%%xmm6                 \n" | 
|  | "movdqu      (%0),%%xmm2                   \n" | 
|  | "movdqu      0x10(%0),%%xmm3               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "psrld       $0x18,%%xmm2                  \n" | 
|  | "psrld       $0x18,%%xmm3                  \n" | 
|  | "packuswb    %%xmm3,%%xmm2                 \n" | 
|  | "packuswb    %%xmm2,%%xmm2                 \n" | 
|  | "movdqa      %%xmm6,%%xmm3                 \n" | 
|  | "punpcklbw   %%xmm6,%%xmm6                 \n" | 
|  | "punpcklbw   %%xmm2,%%xmm3                 \n" | 
|  | "movdqa      %%xmm6,%%xmm1                 \n" | 
|  | "punpcklwd   %%xmm3,%%xmm6                 \n" | 
|  | "punpckhwd   %%xmm3,%%xmm1                 \n" | 
|  | "movdqu      %%xmm6,(%1)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "m"(kARGBToYJ),  // %3 | 
|  | "m"(kSub128)     // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_ARGBGRAYROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBSEPIAROW_SSSE3 | 
|  | //    b = (r * 35 + g * 68 + b * 17) >> 7 | 
|  | //    g = (r * 45 + g * 88 + b * 22) >> 7 | 
|  | //    r = (r * 50 + g * 98 + b * 24) >> 7 | 
|  | // Constant for ARGB color to sepia tone | 
|  | static const vec8 kARGBToSepiaB = {17, 68, 35, 0, 17, 68, 35, 0, | 
|  | 17, 68, 35, 0, 17, 68, 35, 0}; | 
|  |  | 
|  | static const vec8 kARGBToSepiaG = {22, 88, 45, 0, 22, 88, 45, 0, | 
|  | 22, 88, 45, 0, 22, 88, 45, 0}; | 
|  |  | 
|  | static const vec8 kARGBToSepiaR = {24, 98, 50, 0, 24, 98, 50, 0, | 
|  | 24, 98, 50, 0, 24, 98, 50, 0}; | 
|  |  | 
|  | // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels. | 
|  | void ARGBSepiaRow_SSSE3(uint8_t* dst_argb, int width) { | 
|  | asm volatile( | 
|  | "movdqa      %2,%%xmm2                     \n" | 
|  | "movdqa      %3,%%xmm3                     \n" | 
|  | "movdqa      %4,%%xmm4                     \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm6               \n" | 
|  | "pmaddubsw   %%xmm2,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm2,%%xmm6                 \n" | 
|  | "phaddw      %%xmm6,%%xmm0                 \n" | 
|  | "psrlw       $0x7,%%xmm0                   \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm5                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm5                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "phaddw      %%xmm1,%%xmm5                 \n" | 
|  | "psrlw       $0x7,%%xmm5                   \n" | 
|  | "packuswb    %%xmm5,%%xmm5                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm5                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm5                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm1                 \n" | 
|  | "phaddw      %%xmm1,%%xmm5                 \n" | 
|  | "psrlw       $0x7,%%xmm5                   \n" | 
|  | "packuswb    %%xmm5,%%xmm5                 \n" | 
|  | "movdqu      (%0),%%xmm6                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "psrld       $0x18,%%xmm6                  \n" | 
|  | "psrld       $0x18,%%xmm1                  \n" | 
|  | "packuswb    %%xmm1,%%xmm6                 \n" | 
|  | "packuswb    %%xmm6,%%xmm6                 \n" | 
|  | "punpcklbw   %%xmm6,%%xmm5                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklwd   %%xmm5,%%xmm0                 \n" | 
|  | "punpckhwd   %%xmm5,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%0)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%0)               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "sub         $0x8,%1                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(dst_argb),      // %0 | 
|  | "+r"(width)          // %1 | 
|  | : "m"(kARGBToSepiaB),  // %2 | 
|  | "m"(kARGBToSepiaG),  // %3 | 
|  | "m"(kARGBToSepiaR)   // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_ARGBSEPIAROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBCOLORMATRIXROW_SSSE3 | 
|  | // Tranform 8 ARGB pixels (32 bytes) with color matrix. | 
|  | // Same as Sepia except matrix is provided. | 
|  | void ARGBColorMatrixRow_SSSE3(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | const int8_t* matrix_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movdqu      (%3),%%xmm5                   \n" | 
|  | "pshufd      $0x00,%%xmm5,%%xmm2           \n" | 
|  | "pshufd      $0x55,%%xmm5,%%xmm3           \n" | 
|  | "pshufd      $0xaa,%%xmm5,%%xmm4           \n" | 
|  | "pshufd      $0xff,%%xmm5,%%xmm5           \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm7               \n" | 
|  | "pmaddubsw   %%xmm2,%%xmm0                 \n" | 
|  | "pmaddubsw   %%xmm2,%%xmm7                 \n" | 
|  | "movdqu      (%0),%%xmm6                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm1                 \n" | 
|  | "phaddsw     %%xmm7,%%xmm0                 \n" | 
|  | "phaddsw     %%xmm1,%%xmm6                 \n" | 
|  | "psraw       $0x6,%%xmm0                   \n" | 
|  | "psraw       $0x6,%%xmm6                   \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "packuswb    %%xmm6,%%xmm6                 \n" | 
|  | "punpcklbw   %%xmm6,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm1                   \n" | 
|  | "movdqu      0x10(%0),%%xmm7               \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm7                 \n" | 
|  | "phaddsw     %%xmm7,%%xmm1                 \n" | 
|  | "movdqu      (%0),%%xmm6                   \n" | 
|  | "movdqu      0x10(%0),%%xmm7               \n" | 
|  | "pmaddubsw   %%xmm5,%%xmm6                 \n" | 
|  | "pmaddubsw   %%xmm5,%%xmm7                 \n" | 
|  | "phaddsw     %%xmm7,%%xmm6                 \n" | 
|  | "psraw       $0x6,%%xmm1                   \n" | 
|  | "psraw       $0x6,%%xmm6                   \n" | 
|  | "packuswb    %%xmm1,%%xmm1                 \n" | 
|  | "packuswb    %%xmm6,%%xmm6                 \n" | 
|  | "punpcklbw   %%xmm6,%%xmm1                 \n" | 
|  | "movdqa      %%xmm0,%%xmm6                 \n" | 
|  | "punpcklwd   %%xmm1,%%xmm0                 \n" | 
|  | "punpckhwd   %%xmm1,%%xmm6                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm6,0x10(%1)               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),   // %0 | 
|  | "+r"(dst_argb),   // %1 | 
|  | "+r"(width)       // %2 | 
|  | : "r"(matrix_argb)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBCOLORMATRIXROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBQUANTIZEROW_SSE2 | 
|  | // Quantize 4 ARGB pixels (16 bytes). | 
|  | void ARGBQuantizeRow_SSE2(uint8_t* dst_argb, | 
|  | int scale, | 
|  | int interval_size, | 
|  | int interval_offset, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "movd        %2,%%xmm2                     \n" | 
|  | "movd        %3,%%xmm3                     \n" | 
|  | "movd        %4,%%xmm4                     \n" | 
|  | "pshuflw     $0x40,%%xmm2,%%xmm2           \n" | 
|  | "pshufd      $0x44,%%xmm2,%%xmm2           \n" | 
|  | "pshuflw     $0x40,%%xmm3,%%xmm3           \n" | 
|  | "pshufd      $0x44,%%xmm3,%%xmm3           \n" | 
|  | "pshuflw     $0x40,%%xmm4,%%xmm4           \n" | 
|  | "pshufd      $0x44,%%xmm4,%%xmm4           \n" | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  | "pcmpeqb     %%xmm6,%%xmm6                 \n" | 
|  | "pslld       $0x18,%%xmm6                  \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "punpcklbw   %%xmm5,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm1                   \n" | 
|  | "punpckhbw   %%xmm5,%%xmm1                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm1                 \n" | 
|  | "pmullw      %%xmm3,%%xmm0                 \n" | 
|  | "movdqu      (%0),%%xmm7                   \n" | 
|  | "pmullw      %%xmm3,%%xmm1                 \n" | 
|  | "pand        %%xmm6,%%xmm7                 \n" | 
|  | "paddw       %%xmm4,%%xmm0                 \n" | 
|  | "paddw       %%xmm4,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "por         %%xmm7,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%0)                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "sub         $0x4,%1                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(dst_argb),       // %0 | 
|  | "+r"(width)           // %1 | 
|  | : "r"(scale),           // %2 | 
|  | "r"(interval_size),   // %3 | 
|  | "r"(interval_offset)  // %4 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBQUANTIZEROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBSHADEROW_SSE2 | 
|  | // Shade 4 pixels at a time by specified value. | 
|  | void ARGBShadeRow_SSE2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | int width, | 
|  | uint32_t value) { | 
|  | asm volatile( | 
|  | "movd        %3,%%xmm2                     \n" | 
|  | "punpcklbw   %%xmm2,%%xmm2                 \n" | 
|  | "punpcklqdq  %%xmm2,%%xmm2                 \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm0,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm1,%%xmm1                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm1                 \n" | 
|  | "psrlw       $0x8,%%xmm0                   \n" | 
|  | "psrlw       $0x8,%%xmm1                   \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x4,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "r"(value)       // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_ARGBSHADEROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBMULTIPLYROW_SSE2 | 
|  | // Multiply 2 rows of ARGB pixels together, 4 pixels at a time. | 
|  | void ARGBMultiplyRow_SSE2(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqu      (%1),%%xmm2                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "movdqu      %%xmm0,%%xmm1                 \n" | 
|  | "movdqu      %%xmm2,%%xmm3                 \n" | 
|  | "punpcklbw   %%xmm0,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm1,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm2                 \n" | 
|  | "punpckhbw   %%xmm5,%%xmm3                 \n" | 
|  | "pmulhuw     %%xmm2,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm3,%%xmm1                 \n" | 
|  | "packuswb    %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb0),  // %0 | 
|  | "+r"(src_argb1),  // %1 | 
|  | "+r"(dst_argb),   // %2 | 
|  | "+r"(width)       // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBMULTIPLYROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBMULTIPLYROW_AVX2 | 
|  | // Multiply 2 rows of ARGB pixels together, 8 pixels at a time. | 
|  | void ARGBMultiplyRow_AVX2(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "vpxor       %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm1                   \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "vmovdqu     (%1),%%ymm3                   \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "vpunpcklbw  %%ymm1,%%ymm1,%%ymm0          \n" | 
|  | "vpunpckhbw  %%ymm1,%%ymm1,%%ymm1          \n" | 
|  | "vpunpcklbw  %%ymm5,%%ymm3,%%ymm2          \n" | 
|  | "vpunpckhbw  %%ymm5,%%ymm3,%%ymm3          \n" | 
|  | "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,(%2)                   \n" | 
|  | "lea         0x20(%2),%2                   \n" | 
|  | "sub         $0x8,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb0),  // %0 | 
|  | "+r"(src_argb1),  // %1 | 
|  | "+r"(dst_argb),   // %2 | 
|  | "+r"(width)       // %3 | 
|  | : | 
|  | : "memory", "cc" | 
|  | #if defined(__AVX2__) | 
|  | , | 
|  | "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" | 
|  | #endif | 
|  | ); | 
|  | } | 
|  | #endif  // HAS_ARGBMULTIPLYROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBADDROW_SSE2 | 
|  | // Add 2 rows of ARGB pixels together, 4 pixels at a time. | 
|  | void ARGBAddRow_SSE2(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqu      (%1),%%xmm1                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "paddusb     %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb0),  // %0 | 
|  | "+r"(src_argb1),  // %1 | 
|  | "+r"(dst_argb),   // %2 | 
|  | "+r"(width)       // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_ARGBADDROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBADDROW_AVX2 | 
|  | // Add 2 rows of ARGB pixels together, 4 pixels at a time. | 
|  | void ARGBAddRow_AVX2(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "vpaddusb    (%1),%%ymm0,%%ymm0            \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "vmovdqu     %%ymm0,(%2)                   \n" | 
|  | "lea         0x20(%2),%2                   \n" | 
|  | "sub         $0x8,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb0),  // %0 | 
|  | "+r"(src_argb1),  // %1 | 
|  | "+r"(dst_argb),   // %2 | 
|  | "+r"(width)       // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0"); | 
|  | } | 
|  | #endif  // HAS_ARGBADDROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBSUBTRACTROW_SSE2 | 
|  | // Subtract 2 rows of ARGB pixels, 4 pixels at a time. | 
|  | void ARGBSubtractRow_SSE2(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqu      (%1),%%xmm1                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "psubusb     %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb0),  // %0 | 
|  | "+r"(src_argb1),  // %1 | 
|  | "+r"(dst_argb),   // %2 | 
|  | "+r"(width)       // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_ARGBSUBTRACTROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBSUBTRACTROW_AVX2 | 
|  | // Subtract 2 rows of ARGB pixels, 8 pixels at a time. | 
|  | void ARGBSubtractRow_AVX2(const uint8_t* src_argb0, | 
|  | const uint8_t* src_argb1, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "vpsubusb    (%1),%%ymm0,%%ymm0            \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "vmovdqu     %%ymm0,(%2)                   \n" | 
|  | "lea         0x20(%2),%2                   \n" | 
|  | "sub         $0x8,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb0),  // %0 | 
|  | "+r"(src_argb1),  // %1 | 
|  | "+r"(dst_argb),   // %2 | 
|  | "+r"(width)       // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0"); | 
|  | } | 
|  | #endif  // HAS_ARGBSUBTRACTROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_SOBELXROW_SSE2 | 
|  | // SobelX as a matrix is | 
|  | // -1  0  1 | 
|  | // -2  0  2 | 
|  | // -1  0  1 | 
|  | void SobelXRow_SSE2(const uint8_t* src_y0, | 
|  | const uint8_t* src_y1, | 
|  | const uint8_t* src_y2, | 
|  | uint8_t* dst_sobelx, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | "sub         %0,%2                         \n" | 
|  | "sub         %0,%3                         \n" | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%0),%%xmm0                   \n" | 
|  | "movq        0x2(%0),%%xmm1                \n" | 
|  | "punpcklbw   %%xmm5,%%xmm0                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm1                 \n" | 
|  | "psubw       %%xmm1,%%xmm0                 \n" | 
|  | "movq        0x00(%0,%1,1),%%xmm1          \n" | 
|  | "movq        0x02(%0,%1,1),%%xmm2          \n" | 
|  | "punpcklbw   %%xmm5,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm2                 \n" | 
|  | "psubw       %%xmm2,%%xmm1                 \n" | 
|  | "movq        0x00(%0,%2,1),%%xmm2          \n" | 
|  | "movq        0x02(%0,%2,1),%%xmm3          \n" | 
|  | "punpcklbw   %%xmm5,%%xmm2                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm3                 \n" | 
|  | "psubw       %%xmm3,%%xmm2                 \n" | 
|  | "paddw       %%xmm2,%%xmm0                 \n" | 
|  | "paddw       %%xmm1,%%xmm0                 \n" | 
|  | "paddw       %%xmm1,%%xmm0                 \n" | 
|  | "pxor        %%xmm1,%%xmm1                 \n" | 
|  | "psubw       %%xmm0,%%xmm1                 \n" | 
|  | "pmaxsw      %%xmm1,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "movq        %%xmm0,0x00(%0,%3,1)          \n" | 
|  | "lea         0x8(%0),%0                    \n" | 
|  | "sub         $0x8,%4                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y0),      // %0 | 
|  | "+r"(src_y1),      // %1 | 
|  | "+r"(src_y2),      // %2 | 
|  | "+r"(dst_sobelx),  // %3 | 
|  | "+r"(width)        // %4 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SOBELXROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_SOBELYROW_SSE2 | 
|  | // SobelY as a matrix is | 
|  | // -1 -2 -1 | 
|  | //  0  0  0 | 
|  | //  1  2  1 | 
|  | void SobelYRow_SSE2(const uint8_t* src_y0, | 
|  | const uint8_t* src_y1, | 
|  | uint8_t* dst_sobely, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | "sub         %0,%2                         \n" | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%0),%%xmm0                   \n" | 
|  | "movq        0x00(%0,%1,1),%%xmm1          \n" | 
|  | "punpcklbw   %%xmm5,%%xmm0                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm1                 \n" | 
|  | "psubw       %%xmm1,%%xmm0                 \n" | 
|  | "movq        0x1(%0),%%xmm1                \n" | 
|  | "movq        0x01(%0,%1,1),%%xmm2          \n" | 
|  | "punpcklbw   %%xmm5,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm2                 \n" | 
|  | "psubw       %%xmm2,%%xmm1                 \n" | 
|  | "movq        0x2(%0),%%xmm2                \n" | 
|  | "movq        0x02(%0,%1,1),%%xmm3          \n" | 
|  | "punpcklbw   %%xmm5,%%xmm2                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm3                 \n" | 
|  | "psubw       %%xmm3,%%xmm2                 \n" | 
|  | "paddw       %%xmm2,%%xmm0                 \n" | 
|  | "paddw       %%xmm1,%%xmm0                 \n" | 
|  | "paddw       %%xmm1,%%xmm0                 \n" | 
|  | "pxor        %%xmm1,%%xmm1                 \n" | 
|  | "psubw       %%xmm0,%%xmm1                 \n" | 
|  | "pmaxsw      %%xmm1,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "movq        %%xmm0,0x00(%0,%2,1)          \n" | 
|  | "lea         0x8(%0),%0                    \n" | 
|  | "sub         $0x8,%3                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y0),      // %0 | 
|  | "+r"(src_y1),      // %1 | 
|  | "+r"(dst_sobely),  // %2 | 
|  | "+r"(width)        // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SOBELYROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_SOBELROW_SSE2 | 
|  | // Adds Sobel X and Sobel Y and stores Sobel into ARGB. | 
|  | // A = 255 | 
|  | // R = Sobel | 
|  | // G = Sobel | 
|  | // B = Sobel | 
|  | void SobelRow_SSE2(const uint8_t* src_sobelx, | 
|  | const uint8_t* src_sobely, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "pslld       $0x18,%%xmm5                  \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%1,1),%%xmm1          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "paddusb     %%xmm1,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "punpcklbw   %%xmm0,%%xmm2                 \n" | 
|  | "punpckhbw   %%xmm0,%%xmm0                 \n" | 
|  | "movdqa      %%xmm2,%%xmm1                 \n" | 
|  | "punpcklwd   %%xmm2,%%xmm1                 \n" | 
|  | "punpckhwd   %%xmm2,%%xmm2                 \n" | 
|  | "por         %%xmm5,%%xmm1                 \n" | 
|  | "por         %%xmm5,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm3                 \n" | 
|  | "punpcklwd   %%xmm0,%%xmm3                 \n" | 
|  | "punpckhwd   %%xmm0,%%xmm0                 \n" | 
|  | "por         %%xmm5,%%xmm3                 \n" | 
|  | "por         %%xmm5,%%xmm0                 \n" | 
|  | "movdqu      %%xmm1,(%2)                   \n" | 
|  | "movdqu      %%xmm2,0x10(%2)               \n" | 
|  | "movdqu      %%xmm3,0x20(%2)               \n" | 
|  | "movdqu      %%xmm0,0x30(%2)               \n" | 
|  | "lea         0x40(%2),%2                   \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_sobelx),  // %0 | 
|  | "+r"(src_sobely),  // %1 | 
|  | "+r"(dst_argb),    // %2 | 
|  | "+r"(width)        // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SOBELROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_SOBELTOPLANEROW_SSE2 | 
|  | // Adds Sobel X and Sobel Y and stores Sobel into a plane. | 
|  | void SobelToPlaneRow_SSE2(const uint8_t* src_sobelx, | 
|  | const uint8_t* src_sobely, | 
|  | uint8_t* dst_y, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  | "pslld       $0x18,%%xmm5                  \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%1,1),%%xmm1          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "paddusb     %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_sobelx),  // %0 | 
|  | "+r"(src_sobely),  // %1 | 
|  | "+r"(dst_y),       // %2 | 
|  | "+r"(width)        // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  | #endif  // HAS_SOBELTOPLANEROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_SOBELXYROW_SSE2 | 
|  | // Mixes Sobel X, Sobel Y and Sobel into ARGB. | 
|  | // A = 255 | 
|  | // R = Sobel X | 
|  | // G = Sobel | 
|  | // B = Sobel Y | 
|  | void SobelXYRow_SSE2(const uint8_t* src_sobelx, | 
|  | const uint8_t* src_sobely, | 
|  | uint8_t* dst_argb, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | "pcmpeqb     %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | // 8 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x00(%0,%1,1),%%xmm1          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqa      %%xmm0,%%xmm2                 \n" | 
|  | "paddusb     %%xmm1,%%xmm2                 \n" | 
|  | "movdqa      %%xmm0,%%xmm3                 \n" | 
|  | "punpcklbw   %%xmm5,%%xmm3                 \n" | 
|  | "punpckhbw   %%xmm5,%%xmm0                 \n" | 
|  | "movdqa      %%xmm1,%%xmm4                 \n" | 
|  | "punpcklbw   %%xmm2,%%xmm4                 \n" | 
|  | "punpckhbw   %%xmm2,%%xmm1                 \n" | 
|  | "movdqa      %%xmm4,%%xmm6                 \n" | 
|  | "punpcklwd   %%xmm3,%%xmm6                 \n" | 
|  | "punpckhwd   %%xmm3,%%xmm4                 \n" | 
|  | "movdqa      %%xmm1,%%xmm7                 \n" | 
|  | "punpcklwd   %%xmm0,%%xmm7                 \n" | 
|  | "punpckhwd   %%xmm0,%%xmm1                 \n" | 
|  | "movdqu      %%xmm6,(%2)                   \n" | 
|  | "movdqu      %%xmm4,0x10(%2)               \n" | 
|  | "movdqu      %%xmm7,0x20(%2)               \n" | 
|  | "movdqu      %%xmm1,0x30(%2)               \n" | 
|  | "lea         0x40(%2),%2                   \n" | 
|  | "sub         $0x10,%3                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_sobelx),  // %0 | 
|  | "+r"(src_sobely),  // %1 | 
|  | "+r"(dst_argb),    // %2 | 
|  | "+r"(width)        // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_SOBELXYROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_COMPUTECUMULATIVESUMROW_SSE2 | 
|  | // Creates a table of cumulative sums where each value is a sum of all values | 
|  | // above and to the left of the value, inclusive of the value. | 
|  | void ComputeCumulativeSumRow_SSE2(const uint8_t* row, | 
|  | int32_t* cumsum, | 
|  | const int32_t* previous_cumsum, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pxor        %%xmm0,%%xmm0                 \n" | 
|  | "pxor        %%xmm1,%%xmm1                 \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jl          49f                           \n" | 
|  | "test        $0xf,%1                       \n" | 
|  | "jne         49f                           \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "40:                                       \n" | 
|  | "movdqu      (%0),%%xmm2                   \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "movdqa      %%xmm2,%%xmm4                 \n" | 
|  | "punpcklbw   %%xmm1,%%xmm2                 \n" | 
|  | "movdqa      %%xmm2,%%xmm3                 \n" | 
|  | "punpcklwd   %%xmm1,%%xmm2                 \n" | 
|  | "punpckhwd   %%xmm1,%%xmm3                 \n" | 
|  | "punpckhbw   %%xmm1,%%xmm4                 \n" | 
|  | "movdqa      %%xmm4,%%xmm5                 \n" | 
|  | "punpcklwd   %%xmm1,%%xmm4                 \n" | 
|  | "punpckhwd   %%xmm1,%%xmm5                 \n" | 
|  | "paddd       %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      (%2),%%xmm2                   \n" | 
|  | "paddd       %%xmm0,%%xmm2                 \n" | 
|  | "paddd       %%xmm3,%%xmm0                 \n" | 
|  | "movdqu      0x10(%2),%%xmm3               \n" | 
|  | "paddd       %%xmm0,%%xmm3                 \n" | 
|  | "paddd       %%xmm4,%%xmm0                 \n" | 
|  | "movdqu      0x20(%2),%%xmm4               \n" | 
|  | "paddd       %%xmm0,%%xmm4                 \n" | 
|  | "paddd       %%xmm5,%%xmm0                 \n" | 
|  | "movdqu      0x30(%2),%%xmm5               \n" | 
|  | "lea         0x40(%2),%2                   \n" | 
|  | "paddd       %%xmm0,%%xmm5                 \n" | 
|  | "movdqu      %%xmm2,(%1)                   \n" | 
|  | "movdqu      %%xmm3,0x10(%1)               \n" | 
|  | "movdqu      %%xmm4,0x20(%1)               \n" | 
|  | "movdqu      %%xmm5,0x30(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jge         40b                           \n" | 
|  |  | 
|  | "49:                                       \n" | 
|  | "add         $0x3,%3                       \n" | 
|  | "jl          19f                           \n" | 
|  |  | 
|  | // 1 pixel loop. | 
|  | LABELALIGN | 
|  | "10:                                       \n" | 
|  | "movd        (%0),%%xmm2                   \n" | 
|  | "lea         0x4(%0),%0                    \n" | 
|  | "punpcklbw   %%xmm1,%%xmm2                 \n" | 
|  | "punpcklwd   %%xmm1,%%xmm2                 \n" | 
|  | "paddd       %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      (%2),%%xmm2                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "paddd       %%xmm0,%%xmm2                 \n" | 
|  | "movdqu      %%xmm2,(%1)                   \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x1,%3                       \n" | 
|  | "jge         10b                           \n" | 
|  |  | 
|  | "19:                                       \n" | 
|  | : "+r"(row),              // %0 | 
|  | "+r"(cumsum),           // %1 | 
|  | "+r"(previous_cumsum),  // %2 | 
|  | "+r"(width)             // %3 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_COMPUTECUMULATIVESUMROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 | 
|  | void CumulativeSumToAverageRow_SSE2(const int32_t* topleft, | 
|  | const int32_t* botleft, | 
|  | int width, | 
|  | int area, | 
|  | uint8_t* dst, | 
|  | int count) { | 
|  | asm volatile( | 
|  | "movd        %5,%%xmm5                     \n" | 
|  | "cvtdq2ps    %%xmm5,%%xmm5                 \n" | 
|  | "rcpss       %%xmm5,%%xmm4                 \n" | 
|  | "pshufd      $0x0,%%xmm4,%%xmm4            \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jl          49f                           \n" | 
|  | "cmpl        $0x80,%5                      \n" | 
|  | "ja          40f                           \n" | 
|  |  | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "pcmpeqb     %%xmm6,%%xmm6                 \n" | 
|  | "psrld       $0x10,%%xmm6                  \n" | 
|  | "cvtdq2ps    %%xmm6,%%xmm6                 \n" | 
|  | "addps       %%xmm6,%%xmm5                 \n" | 
|  | "mulps       %%xmm4,%%xmm5                 \n" | 
|  | "cvtps2dq    %%xmm5,%%xmm5                 \n" | 
|  | "packssdw    %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | // 4 pixel small loop. | 
|  | LABELALIGN | 
|  | "4:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x30(%0),%%xmm3               \n" | 
|  | "psubd       0x00(%0,%4,4),%%xmm0          \n" | 
|  | "psubd       0x10(%0,%4,4),%%xmm1          \n" | 
|  | "psubd       0x20(%0,%4,4),%%xmm2          \n" | 
|  | "psubd       0x30(%0,%4,4),%%xmm3          \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "psubd       (%1),%%xmm0                   \n" | 
|  | "psubd       0x10(%1),%%xmm1               \n" | 
|  | "psubd       0x20(%1),%%xmm2               \n" | 
|  | "psubd       0x30(%1),%%xmm3               \n" | 
|  | "paddd       0x00(%1,%4,4),%%xmm0          \n" | 
|  | "paddd       0x10(%1,%4,4),%%xmm1          \n" | 
|  | "paddd       0x20(%1,%4,4),%%xmm2          \n" | 
|  | "paddd       0x30(%1,%4,4),%%xmm3          \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "packssdw    %%xmm1,%%xmm0                 \n" | 
|  | "packssdw    %%xmm3,%%xmm2                 \n" | 
|  | "pmulhuw     %%xmm5,%%xmm0                 \n" | 
|  | "pmulhuw     %%xmm5,%%xmm2                 \n" | 
|  | "packuswb    %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jge         4b                            \n" | 
|  | "jmp         49f                           \n" | 
|  |  | 
|  | // 4 pixel loop | 
|  | LABELALIGN | 
|  | "40:                                       \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "movdqu      0x20(%0),%%xmm2               \n" | 
|  | "movdqu      0x30(%0),%%xmm3               \n" | 
|  | "psubd       0x00(%0,%4,4),%%xmm0          \n" | 
|  | "psubd       0x10(%0,%4,4),%%xmm1          \n" | 
|  | "psubd       0x20(%0,%4,4),%%xmm2          \n" | 
|  | "psubd       0x30(%0,%4,4),%%xmm3          \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "psubd       (%1),%%xmm0                   \n" | 
|  | "psubd       0x10(%1),%%xmm1               \n" | 
|  | "psubd       0x20(%1),%%xmm2               \n" | 
|  | "psubd       0x30(%1),%%xmm3               \n" | 
|  | "paddd       0x00(%1,%4,4),%%xmm0          \n" | 
|  | "paddd       0x10(%1,%4,4),%%xmm1          \n" | 
|  | "paddd       0x20(%1,%4,4),%%xmm2          \n" | 
|  | "paddd       0x30(%1,%4,4),%%xmm3          \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "cvtdq2ps    %%xmm0,%%xmm0                 \n" | 
|  | "cvtdq2ps    %%xmm1,%%xmm1                 \n" | 
|  | "mulps       %%xmm4,%%xmm0                 \n" | 
|  | "mulps       %%xmm4,%%xmm1                 \n" | 
|  | "cvtdq2ps    %%xmm2,%%xmm2                 \n" | 
|  | "cvtdq2ps    %%xmm3,%%xmm3                 \n" | 
|  | "mulps       %%xmm4,%%xmm2                 \n" | 
|  | "mulps       %%xmm4,%%xmm3                 \n" | 
|  | "cvtps2dq    %%xmm0,%%xmm0                 \n" | 
|  | "cvtps2dq    %%xmm1,%%xmm1                 \n" | 
|  | "cvtps2dq    %%xmm2,%%xmm2                 \n" | 
|  | "cvtps2dq    %%xmm3,%%xmm3                 \n" | 
|  | "packssdw    %%xmm1,%%xmm0                 \n" | 
|  | "packssdw    %%xmm3,%%xmm2                 \n" | 
|  | "packuswb    %%xmm2,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%3                       \n" | 
|  | "jge         40b                           \n" | 
|  |  | 
|  | "49:                                       \n" | 
|  | "add         $0x3,%3                       \n" | 
|  | "jl          19f                           \n" | 
|  |  | 
|  | // 1 pixel loop | 
|  | LABELALIGN | 
|  | "10:                                       \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "psubd       0x00(%0,%4,4),%%xmm0          \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "psubd       (%1),%%xmm0                   \n" | 
|  | "paddd       0x00(%1,%4,4),%%xmm0          \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "cvtdq2ps    %%xmm0,%%xmm0                 \n" | 
|  | "mulps       %%xmm4,%%xmm0                 \n" | 
|  | "cvtps2dq    %%xmm0,%%xmm0                 \n" | 
|  | "packssdw    %%xmm0,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "movd        %%xmm0,(%2)                   \n" | 
|  | "lea         0x4(%2),%2                    \n" | 
|  | "sub         $0x1,%3                       \n" | 
|  | "jge         10b                           \n" | 
|  | "19:                                       \n" | 
|  | : "+r"(topleft),           // %0 | 
|  | "+r"(botleft),           // %1 | 
|  | "+r"(dst),               // %2 | 
|  | "+rm"(count)             // %3 | 
|  | : "r"((intptr_t)(width)),  // %4 | 
|  | "rm"(area)               // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBAFFINEROW_SSE2 | 
|  | // Copy ARGB pixels from source image with slope to a row of destination. | 
|  | LIBYUV_API | 
|  | void ARGBAffineRow_SSE2(const uint8_t* src_argb, | 
|  | int src_argb_stride, | 
|  | uint8_t* dst_argb, | 
|  | const float* src_dudv, | 
|  | int width) { | 
|  | intptr_t src_argb_stride_temp = src_argb_stride; | 
|  | intptr_t temp; | 
|  | asm volatile( | 
|  | "movq        (%3),%%xmm2                   \n" | 
|  | "movq        0x08(%3),%%xmm7               \n" | 
|  | "shl         $0x10,%1                      \n" | 
|  | "add         $0x4,%1                       \n" | 
|  | "movd        %1,%%xmm5                     \n" | 
|  | "sub         $0x4,%4                       \n" | 
|  | "jl          49f                           \n" | 
|  |  | 
|  | "pshufd      $0x44,%%xmm7,%%xmm7           \n" | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "movdqa      %%xmm2,%%xmm0                 \n" | 
|  | "addps       %%xmm7,%%xmm0                 \n" | 
|  | "movlhps     %%xmm0,%%xmm2                 \n" | 
|  | "movdqa      %%xmm7,%%xmm4                 \n" | 
|  | "addps       %%xmm4,%%xmm4                 \n" | 
|  | "movdqa      %%xmm2,%%xmm3                 \n" | 
|  | "addps       %%xmm4,%%xmm3                 \n" | 
|  | "addps       %%xmm4,%%xmm4                 \n" | 
|  |  | 
|  | // 4 pixel loop | 
|  | LABELALIGN | 
|  | "40:                                       \n" | 
|  | "cvttps2dq   %%xmm2,%%xmm0                 \n"  // x,y float->int first 2 | 
|  | "cvttps2dq   %%xmm3,%%xmm1                 \n"  // x,y float->int next 2 | 
|  | "packssdw    %%xmm1,%%xmm0                 \n"  // x, y as 8 shorts | 
|  | "pmaddwd     %%xmm5,%%xmm0                 \n"  // off = x*4 + y*stride | 
|  | "movd        %%xmm0,%k1                    \n" | 
|  | "pshufd      $0x39,%%xmm0,%%xmm0           \n" | 
|  | "movd        %%xmm0,%k5                    \n" | 
|  | "pshufd      $0x39,%%xmm0,%%xmm0           \n" | 
|  | "movd        0x00(%0,%1,1),%%xmm1          \n" | 
|  | "movd        0x00(%0,%5,1),%%xmm6          \n" | 
|  | "punpckldq   %%xmm6,%%xmm1                 \n" | 
|  | "addps       %%xmm4,%%xmm2                 \n" | 
|  | "movq        %%xmm1,(%2)                   \n" | 
|  | "movd        %%xmm0,%k1                    \n" | 
|  | "pshufd      $0x39,%%xmm0,%%xmm0           \n" | 
|  | "movd        %%xmm0,%k5                    \n" | 
|  | "movd        0x00(%0,%1,1),%%xmm0          \n" | 
|  | "movd        0x00(%0,%5,1),%%xmm6          \n" | 
|  | "punpckldq   %%xmm6,%%xmm0                 \n" | 
|  | "addps       %%xmm4,%%xmm3                 \n" | 
|  | "movq        %%xmm0,0x08(%2)               \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x4,%4                       \n" | 
|  | "jge         40b                           \n" | 
|  |  | 
|  | "49:                                       \n" | 
|  | "add         $0x3,%4                       \n" | 
|  | "jl          19f                           \n" | 
|  |  | 
|  | // 1 pixel loop | 
|  | LABELALIGN | 
|  | "10:                                       \n" | 
|  | "cvttps2dq   %%xmm2,%%xmm0                 \n" | 
|  | "packssdw    %%xmm0,%%xmm0                 \n" | 
|  | "pmaddwd     %%xmm5,%%xmm0                 \n" | 
|  | "addps       %%xmm7,%%xmm2                 \n" | 
|  | "movd        %%xmm0,%k1                    \n" | 
|  | "movd        0x00(%0,%1,1),%%xmm0          \n" | 
|  | "movd        %%xmm0,(%2)                   \n" | 
|  | "lea         0x04(%2),%2                   \n" | 
|  | "sub         $0x1,%4                       \n" | 
|  | "jge         10b                           \n" | 
|  | "19:                                       \n" | 
|  | : "+r"(src_argb),              // %0 | 
|  | "+r"(src_argb_stride_temp),  // %1 | 
|  | "+r"(dst_argb),              // %2 | 
|  | "+r"(src_dudv),              // %3 | 
|  | "+rm"(width),                // %4 | 
|  | "=&r"(temp)                  // %5 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBAFFINEROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_INTERPOLATEROW_SSSE3 | 
|  | // Bilinear filter 16x2 -> 16x1 | 
|  | void InterpolateRow_SSSE3(uint8_t* dst_ptr, | 
|  | const uint8_t* src_ptr, | 
|  | ptrdiff_t src_stride, | 
|  | int dst_width, | 
|  | int source_y_fraction) { | 
|  | asm volatile( | 
|  | "sub         %1,%0                         \n" | 
|  | "cmp         $0x0,%3                       \n" | 
|  | "je          100f                          \n" | 
|  | "cmp         $0x80,%3                      \n" | 
|  | "je          50f                           \n" | 
|  |  | 
|  | "movd        %3,%%xmm0                     \n" | 
|  | "neg         %3                            \n" | 
|  | "add         $0x100,%3                     \n" | 
|  | "movd        %3,%%xmm5                     \n" | 
|  | "punpcklbw   %%xmm0,%%xmm5                 \n" | 
|  | "punpcklwd   %%xmm5,%%xmm5                 \n" | 
|  | "pshufd      $0x0,%%xmm5,%%xmm5            \n" | 
|  | "mov         $0x80808080,%%eax             \n" | 
|  | "movd        %%eax,%%xmm4                  \n" | 
|  | "pshufd      $0x0,%%xmm4,%%xmm4            \n" | 
|  |  | 
|  | // General purpose row blend. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%1),%%xmm0                   \n" | 
|  | "movdqu      0x00(%1,%4,1),%%xmm2          \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm2,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm2,%%xmm1                 \n" | 
|  | "psubb       %%xmm4,%%xmm0                 \n" | 
|  | "psubb       %%xmm4,%%xmm1                 \n" | 
|  | "movdqa      %%xmm5,%%xmm2                 \n" | 
|  | "movdqa      %%xmm5,%%xmm3                 \n" | 
|  | "pmaddubsw   %%xmm0,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm1,%%xmm3                 \n" | 
|  | "paddw       %%xmm4,%%xmm2                 \n" | 
|  | "paddw       %%xmm4,%%xmm3                 \n" | 
|  | "psrlw       $0x8,%%xmm2                   \n" | 
|  | "psrlw       $0x8,%%xmm3                   \n" | 
|  | "packuswb    %%xmm3,%%xmm2                 \n" | 
|  | "movdqu      %%xmm2,0x00(%1,%0,1)          \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "jmp         99f                           \n" | 
|  |  | 
|  | // Blend 50 / 50. | 
|  | LABELALIGN | 
|  | "50:                                       \n" | 
|  | "movdqu      (%1),%%xmm0                   \n" | 
|  | "movdqu      0x00(%1,%4,1),%%xmm1          \n" | 
|  | "pavgb       %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,0x00(%1,%0,1)          \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          50b                           \n" | 
|  | "jmp         99f                           \n" | 
|  |  | 
|  | // Blend 100 / 0 - Copy row unchanged. | 
|  | LABELALIGN | 
|  | "100:                                      \n" | 
|  | "movdqu      (%1),%%xmm0                   \n" | 
|  | "movdqu      %%xmm0,0x00(%1,%0,1)          \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          100b                          \n" | 
|  |  | 
|  | "99:                                       \n" | 
|  | : "+r"(dst_ptr),               // %0 | 
|  | "+r"(src_ptr),               // %1 | 
|  | "+rm"(dst_width),            // %2 | 
|  | "+r"(source_y_fraction)      // %3 | 
|  | : "r"((intptr_t)(src_stride))  // %4 | 
|  | : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_INTERPOLATEROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_INTERPOLATEROW_AVX2 | 
|  | // Bilinear filter 32x2 -> 32x1 | 
|  | void InterpolateRow_AVX2(uint8_t* dst_ptr, | 
|  | const uint8_t* src_ptr, | 
|  | ptrdiff_t src_stride, | 
|  | int dst_width, | 
|  | int source_y_fraction) { | 
|  | asm volatile( | 
|  | "cmp         $0x0,%3                       \n" | 
|  | "je          100f                          \n" | 
|  | "sub         %1,%0                         \n" | 
|  | "cmp         $0x80,%3                      \n" | 
|  | "je          50f                           \n" | 
|  |  | 
|  | "vmovd       %3,%%xmm0                     \n" | 
|  | "neg         %3                            \n" | 
|  | "add         $0x100,%3                     \n" | 
|  | "vmovd       %3,%%xmm5                     \n" | 
|  | "vpunpcklbw  %%xmm0,%%xmm5,%%xmm5          \n" | 
|  | "vpunpcklwd  %%xmm5,%%xmm5,%%xmm5          \n" | 
|  | "vbroadcastss %%xmm5,%%ymm5                \n" | 
|  | "mov         $0x80808080,%%eax             \n" | 
|  | "vmovd       %%eax,%%xmm4                  \n" | 
|  | "vbroadcastss %%xmm4,%%ymm4                \n" | 
|  |  | 
|  | // General purpose row blend. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%1),%%ymm0                   \n" | 
|  | "vmovdqu     0x00(%1,%4,1),%%ymm2          \n" | 
|  | "vpunpckhbw  %%ymm2,%%ymm0,%%ymm1          \n" | 
|  | "vpunpcklbw  %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpsubb      %%ymm4,%%ymm1,%%ymm1          \n" | 
|  | "vpsubb      %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vpmaddubsw  %%ymm1,%%ymm5,%%ymm1          \n" | 
|  | "vpmaddubsw  %%ymm0,%%ymm5,%%ymm0          \n" | 
|  | "vpaddw      %%ymm4,%%ymm1,%%ymm1          \n" | 
|  | "vpaddw      %%ymm4,%%ymm0,%%ymm0          \n" | 
|  | "vpsrlw      $0x8,%%ymm1,%%ymm1            \n" | 
|  | "vpsrlw      $0x8,%%ymm0,%%ymm0            \n" | 
|  | "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,0x00(%1,%0,1)          \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "jmp         99f                           \n" | 
|  |  | 
|  | // Blend 50 / 50. | 
|  | LABELALIGN | 
|  | "50:                                       \n" | 
|  | "vmovdqu     (%1),%%ymm0                   \n" | 
|  | "vpavgb      0x00(%1,%4,1),%%ymm0,%%ymm0   \n" | 
|  | "vmovdqu     %%ymm0,0x00(%1,%0,1)          \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          50b                           \n" | 
|  | "jmp         99f                           \n" | 
|  |  | 
|  | // Blend 100 / 0 - Copy row unchanged. | 
|  | LABELALIGN | 
|  | "100:                                      \n" | 
|  | "rep         movsb                         \n" | 
|  | "jmp         999f                          \n" | 
|  |  | 
|  | "99:                                       \n" | 
|  | "vzeroupper                                \n" | 
|  | "999:                                      \n" | 
|  | : "+D"(dst_ptr),               // %0 | 
|  | "+S"(src_ptr),               // %1 | 
|  | "+cm"(dst_width),            // %2 | 
|  | "+r"(source_y_fraction)      // %3 | 
|  | : "r"((intptr_t)(src_stride))  // %4 | 
|  | : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_INTERPOLATEROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBSHUFFLEROW_SSSE3 | 
|  | // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. | 
|  | void ARGBShuffleRow_SSSE3(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | const uint8_t* shuffler, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "movdqu      (%3),%%xmm5                   \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "pshufb      %%xmm5,%%xmm0                 \n" | 
|  | "pshufb      %%xmm5,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "r"(shuffler)    // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBSHUFFLEROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_ARGBSHUFFLEROW_AVX2 | 
|  | // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. | 
|  | void ARGBShuffleRow_AVX2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | const uint8_t* shuffler, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "vbroadcastf128 (%3),%%ymm5                \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "r"(shuffler)    // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBSHUFFLEROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_I422TOYUY2ROW_SSE2 | 
|  | void I422ToYUY2Row_SSE2(const uint8_t* src_y, | 
|  | const uint8_t* src_u, | 
|  | const uint8_t* src_v, | 
|  | uint8_t* dst_yuy2, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%1),%%xmm2                   \n" | 
|  | "movq        0x00(%1,%2,1),%%xmm1          \n" | 
|  | "add         $0x8,%1                       \n" | 
|  | "punpcklbw   %%xmm1,%%xmm2                 \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "add         $0x10,%0                      \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm2,%%xmm0                 \n" | 
|  | "punpckhbw   %%xmm2,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%3)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%3)               \n" | 
|  | "lea         0x20(%3),%3                   \n" | 
|  | "sub         $0x10,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y),     // %0 | 
|  | "+r"(src_u),     // %1 | 
|  | "+r"(src_v),     // %2 | 
|  | "+r"(dst_yuy2),  // %3 | 
|  | "+rm"(width)     // %4 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_I422TOYUY2ROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_I422TOUYVYROW_SSE2 | 
|  | void I422ToUYVYRow_SSE2(const uint8_t* src_y, | 
|  | const uint8_t* src_u, | 
|  | const uint8_t* src_v, | 
|  | uint8_t* dst_uyvy, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%1),%%xmm2                   \n" | 
|  | "movq        0x00(%1,%2,1),%%xmm1          \n" | 
|  | "add         $0x8,%1                       \n" | 
|  | "punpcklbw   %%xmm1,%%xmm2                 \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqa      %%xmm2,%%xmm1                 \n" | 
|  | "add         $0x10,%0                      \n" | 
|  | "punpcklbw   %%xmm0,%%xmm1                 \n" | 
|  | "punpckhbw   %%xmm0,%%xmm2                 \n" | 
|  | "movdqu      %%xmm1,(%3)                   \n" | 
|  | "movdqu      %%xmm2,0x10(%3)               \n" | 
|  | "lea         0x20(%3),%3                   \n" | 
|  | "sub         $0x10,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_y),     // %0 | 
|  | "+r"(src_u),     // %1 | 
|  | "+r"(src_v),     // %2 | 
|  | "+r"(dst_uyvy),  // %3 | 
|  | "+rm"(width)     // %4 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_I422TOUYVYROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_I422TOYUY2ROW_AVX2 | 
|  | void I422ToYUY2Row_AVX2(const uint8_t* src_y, | 
|  | const uint8_t* src_u, | 
|  | const uint8_t* src_v, | 
|  | uint8_t* dst_yuy2, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpmovzxbw   (%1),%%ymm1                   \n" | 
|  | "vpmovzxbw   0x00(%1,%2,1),%%ymm2          \n" | 
|  | "add         $0x10,%1                      \n" | 
|  | "vpsllw      $0x8,%%ymm2,%%ymm2            \n" | 
|  | "vpor        %%ymm1,%%ymm2,%%ymm2          \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "add         $0x20,%0                      \n" | 
|  | "vpunpcklbw  %%ymm2,%%ymm0,%%ymm1          \n" | 
|  | "vpunpckhbw  %%ymm2,%%ymm0,%%ymm2          \n" | 
|  | "vextractf128 $0x0,%%ymm1,(%3)             \n" | 
|  | "vextractf128 $0x0,%%ymm2,0x10(%3)         \n" | 
|  | "vextractf128 $0x1,%%ymm1,0x20(%3)         \n" | 
|  | "vextractf128 $0x1,%%ymm2,0x30(%3)         \n" | 
|  | "lea         0x40(%3),%3                   \n" | 
|  | "sub         $0x20,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_y),     // %0 | 
|  | "+r"(src_u),     // %1 | 
|  | "+r"(src_v),     // %2 | 
|  | "+r"(dst_yuy2),  // %3 | 
|  | "+rm"(width)     // %4 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_I422TOYUY2ROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_I422TOUYVYROW_AVX2 | 
|  | void I422ToUYVYRow_AVX2(const uint8_t* src_y, | 
|  | const uint8_t* src_u, | 
|  | const uint8_t* src_v, | 
|  | uint8_t* dst_uyvy, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "sub         %1,%2                         \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpmovzxbw   (%1),%%ymm1                   \n" | 
|  | "vpmovzxbw   0x00(%1,%2,1),%%ymm2          \n" | 
|  | "add         $0x10,%1                      \n" | 
|  | "vpsllw      $0x8,%%ymm2,%%ymm2            \n" | 
|  | "vpor        %%ymm1,%%ymm2,%%ymm2          \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "add         $0x20,%0                      \n" | 
|  | "vpunpcklbw  %%ymm0,%%ymm2,%%ymm1          \n" | 
|  | "vpunpckhbw  %%ymm0,%%ymm2,%%ymm2          \n" | 
|  | "vextractf128 $0x0,%%ymm1,(%3)             \n" | 
|  | "vextractf128 $0x0,%%ymm2,0x10(%3)         \n" | 
|  | "vextractf128 $0x1,%%ymm1,0x20(%3)         \n" | 
|  | "vextractf128 $0x1,%%ymm2,0x30(%3)         \n" | 
|  | "lea         0x40(%3),%3                   \n" | 
|  | "sub         $0x20,%4                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_y),     // %0 | 
|  | "+r"(src_u),     // %1 | 
|  | "+r"(src_v),     // %2 | 
|  | "+r"(dst_uyvy),  // %3 | 
|  | "+rm"(width)     // %4 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2"); | 
|  | } | 
|  | #endif  // HAS_I422TOUYVYROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_ARGBPOLYNOMIALROW_SSE2 | 
|  | void ARGBPolynomialRow_SSE2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | const float* poly, | 
|  | int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "pxor        %%xmm3,%%xmm3                 \n" | 
|  |  | 
|  | // 2 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movq        (%0),%%xmm0                   \n" | 
|  | "lea         0x8(%0),%0                    \n" | 
|  | "punpcklbw   %%xmm3,%%xmm0                 \n" | 
|  | "movdqa      %%xmm0,%%xmm4                 \n" | 
|  | "punpcklwd   %%xmm3,%%xmm0                 \n" | 
|  | "punpckhwd   %%xmm3,%%xmm4                 \n" | 
|  | "cvtdq2ps    %%xmm0,%%xmm0                 \n" | 
|  | "cvtdq2ps    %%xmm4,%%xmm4                 \n" | 
|  | "movdqa      %%xmm0,%%xmm1                 \n" | 
|  | "movdqa      %%xmm4,%%xmm5                 \n" | 
|  | "mulps       0x10(%3),%%xmm0               \n" | 
|  | "mulps       0x10(%3),%%xmm4               \n" | 
|  | "addps       (%3),%%xmm0                   \n" | 
|  | "addps       (%3),%%xmm4                   \n" | 
|  | "movdqa      %%xmm1,%%xmm2                 \n" | 
|  | "movdqa      %%xmm5,%%xmm6                 \n" | 
|  | "mulps       %%xmm1,%%xmm2                 \n" | 
|  | "mulps       %%xmm5,%%xmm6                 \n" | 
|  | "mulps       %%xmm2,%%xmm1                 \n" | 
|  | "mulps       %%xmm6,%%xmm5                 \n" | 
|  | "mulps       0x20(%3),%%xmm2               \n" | 
|  | "mulps       0x20(%3),%%xmm6               \n" | 
|  | "mulps       0x30(%3),%%xmm1               \n" | 
|  | "mulps       0x30(%3),%%xmm5               \n" | 
|  | "addps       %%xmm2,%%xmm0                 \n" | 
|  | "addps       %%xmm6,%%xmm4                 \n" | 
|  | "addps       %%xmm1,%%xmm0                 \n" | 
|  | "addps       %%xmm5,%%xmm4                 \n" | 
|  | "cvttps2dq   %%xmm0,%%xmm0                 \n" | 
|  | "cvttps2dq   %%xmm4,%%xmm4                 \n" | 
|  | "packuswb    %%xmm4,%%xmm0                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "movq        %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x2,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "r"(poly)        // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); | 
|  | } | 
|  | #endif  // HAS_ARGBPOLYNOMIALROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_ARGBPOLYNOMIALROW_AVX2 | 
|  | void ARGBPolynomialRow_AVX2(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | const float* poly, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastf128 (%3),%%ymm4                \n" | 
|  | "vbroadcastf128 0x10(%3),%%ymm5            \n" | 
|  | "vbroadcastf128 0x20(%3),%%ymm6            \n" | 
|  | "vbroadcastf128 0x30(%3),%%ymm7            \n" | 
|  |  | 
|  | // 2 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpmovzxbd   (%0),%%ymm0                   \n"  // 2 ARGB pixels | 
|  | "lea         0x8(%0),%0                    \n" | 
|  | "vcvtdq2ps   %%ymm0,%%ymm0                 \n"  // X 8 floats | 
|  | "vmulps      %%ymm0,%%ymm0,%%ymm2          \n"  // X * X | 
|  | "vmulps      %%ymm7,%%ymm0,%%ymm3          \n"  // C3 * X | 
|  | "vfmadd132ps %%ymm5,%%ymm4,%%ymm0          \n"  // result = C0 + C1 * X | 
|  | "vfmadd231ps %%ymm6,%%ymm2,%%ymm0          \n"  // result += C2 * X * X | 
|  | "vfmadd231ps %%ymm3,%%ymm2,%%ymm0          \n"  // result += C3 * X * X * | 
|  | // X | 
|  | "vcvttps2dq  %%ymm0,%%ymm0                 \n" | 
|  | "vpackusdw   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpermq      $0xd8,%%ymm0,%%ymm0           \n" | 
|  | "vpackuswb   %%xmm0,%%xmm0,%%xmm0          \n" | 
|  | "vmovq       %%xmm0,(%1)                   \n" | 
|  | "lea         0x8(%1),%1                    \n" | 
|  | "sub         $0x2,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_argb),  // %0 | 
|  | "+r"(dst_argb),  // %1 | 
|  | "+r"(width)      // %2 | 
|  | : "r"(poly)        // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", | 
|  | "xmm7"); | 
|  | } | 
|  | #endif  // HAS_ARGBPOLYNOMIALROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_HALFFLOATROW_SSE2 | 
|  | static float kScaleBias = 1.9259299444e-34f; | 
|  | void HalfFloatRow_SSE2(const uint16_t* src, | 
|  | uint16_t* dst, | 
|  | float scale, | 
|  | int width) { | 
|  | scale *= kScaleBias; | 
|  | asm volatile( | 
|  | "movd        %3,%%xmm4                     \n" | 
|  | "pshufd      $0x0,%%xmm4,%%xmm4            \n" | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | // 16 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm2                   \n"  // 8 shorts | 
|  | "add         $0x10,%0                      \n" | 
|  | "movdqa      %%xmm2,%%xmm3                 \n" | 
|  | "punpcklwd   %%xmm5,%%xmm2                 \n"  // 8 ints in xmm2/1 | 
|  | "cvtdq2ps    %%xmm2,%%xmm2                 \n"  // 8 floats | 
|  | "punpckhwd   %%xmm5,%%xmm3                 \n" | 
|  | "cvtdq2ps    %%xmm3,%%xmm3                 \n" | 
|  | "mulps       %%xmm4,%%xmm2                 \n" | 
|  | "mulps       %%xmm4,%%xmm3                 \n" | 
|  | "psrld       $0xd,%%xmm2                   \n" | 
|  | "psrld       $0xd,%%xmm3                   \n" | 
|  | "packssdw    %%xmm3,%%xmm2                 \n" | 
|  | "movdqu      %%xmm2,-0x10(%0,%1,1)         \n" | 
|  | "sub         $0x8,%2                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : "m"(scale)   // %3 | 
|  | : "memory", "cc", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_HALFFLOATROW_SSE2 | 
|  |  | 
|  | #ifdef HAS_HALFFLOATROW_AVX2 | 
|  | void HalfFloatRow_AVX2(const uint16_t* src, | 
|  | uint16_t* dst, | 
|  | float scale, | 
|  | int width) { | 
|  | scale *= kScaleBias; | 
|  | asm volatile( | 
|  | "vbroadcastss %3, %%ymm4                   \n" | 
|  | "vpxor       %%ymm5,%%ymm5,%%ymm5          \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | // 16 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm2                   \n"  // 16 shorts | 
|  | "add         $0x20,%0                      \n" | 
|  | "vpunpckhwd  %%ymm5,%%ymm2,%%ymm3          \n"  // mutates | 
|  | "vpunpcklwd  %%ymm5,%%ymm2,%%ymm2          \n" | 
|  | "vcvtdq2ps   %%ymm3,%%ymm3                 \n" | 
|  | "vcvtdq2ps   %%ymm2,%%ymm2                 \n" | 
|  | "vmulps      %%ymm3,%%ymm4,%%ymm3          \n" | 
|  | "vmulps      %%ymm2,%%ymm4,%%ymm2          \n" | 
|  | "vpsrld      $0xd,%%ymm3,%%ymm3            \n" | 
|  | "vpsrld      $0xd,%%ymm2,%%ymm2            \n" | 
|  | "vpackssdw   %%ymm3, %%ymm2, %%ymm2        \n"  // unmutates | 
|  | "vmovdqu     %%ymm2,-0x20(%0,%1,1)         \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  |  | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | #if defined(__x86_64__) | 
|  | : "x"(scale)  // %3 | 
|  | #else | 
|  | : "m"(scale)  // %3 | 
|  | #endif | 
|  | : "memory", "cc", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_HALFFLOATROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_HALFFLOATROW_F16C | 
|  | void HalfFloatRow_F16C(const uint16_t* src, | 
|  | uint16_t* dst, | 
|  | float scale, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vbroadcastss %3, %%ymm4                   \n" | 
|  | "sub         %0,%1                         \n" | 
|  |  | 
|  | // 16 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpmovzxwd   (%0),%%ymm2                   \n"  // 16 shorts -> 16 ints | 
|  | "vpmovzxwd   0x10(%0),%%ymm3               \n" | 
|  | "vcvtdq2ps   %%ymm2,%%ymm2                 \n" | 
|  | "vcvtdq2ps   %%ymm3,%%ymm3                 \n" | 
|  | "vmulps      %%ymm2,%%ymm4,%%ymm2          \n" | 
|  | "vmulps      %%ymm3,%%ymm4,%%ymm3          \n" | 
|  | "vcvtps2ph   $3, %%ymm2, %%xmm2            \n" | 
|  | "vcvtps2ph   $3, %%ymm3, %%xmm3            \n" | 
|  | "vmovdqu     %%xmm2,0x00(%0,%1,1)          \n" | 
|  | "vmovdqu     %%xmm3,0x10(%0,%1,1)          \n" | 
|  | "add         $0x20,%0                      \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | #if defined(__x86_64__) | 
|  | : "x"(scale)  // %3 | 
|  | #else | 
|  | : "m"(scale)  // %3 | 
|  | #endif | 
|  | : "memory", "cc", "xmm2", "xmm3", "xmm4"); | 
|  | } | 
|  | #endif  // HAS_HALFFLOATROW_F16C | 
|  |  | 
|  | #ifdef HAS_HALFFLOATROW_F16C | 
|  | void HalfFloat1Row_F16C(const uint16_t* src, uint16_t* dst, float, int width) { | 
|  | asm volatile( | 
|  | "sub         %0,%1                         \n" | 
|  | // 16 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vpmovzxwd   (%0),%%ymm2                   \n"  // 16 shorts -> 16 ints | 
|  | "vpmovzxwd   0x10(%0),%%ymm3               \n" | 
|  | "vcvtdq2ps   %%ymm2,%%ymm2                 \n" | 
|  | "vcvtdq2ps   %%ymm3,%%ymm3                 \n" | 
|  | "vcvtps2ph   $3, %%ymm2, %%xmm2            \n" | 
|  | "vcvtps2ph   $3, %%ymm3, %%xmm3            \n" | 
|  | "vmovdqu     %%xmm2,0x00(%0,%1,1)          \n" | 
|  | "vmovdqu     %%xmm3,0x10(%0,%1,1)          \n" | 
|  | "add         $0x20,%0                      \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src),   // %0 | 
|  | "+r"(dst),   // %1 | 
|  | "+r"(width)  // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm2", "xmm3"); | 
|  | } | 
|  | #endif  // HAS_HALFFLOATROW_F16C | 
|  |  | 
|  | #ifdef HAS_ARGBCOLORTABLEROW_X86 | 
|  | // Tranform ARGB pixels with color table. | 
|  | void ARGBColorTableRow_X86(uint8_t* dst_argb, | 
|  | const uint8_t* table_argb, | 
|  | int width) { | 
|  | uintptr_t pixel_temp; | 
|  | asm volatile( | 
|  | // 1 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movzb       (%0),%1                       \n" | 
|  | "lea         0x4(%0),%0                    \n" | 
|  | "movzb       0x00(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x4(%0)                  \n" | 
|  | "movzb       -0x3(%0),%1                   \n" | 
|  | "movzb       0x01(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x3(%0)                  \n" | 
|  | "movzb       -0x2(%0),%1                   \n" | 
|  | "movzb       0x02(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x2(%0)                  \n" | 
|  | "movzb       -0x1(%0),%1                   \n" | 
|  | "movzb       0x03(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x1(%0)                  \n" | 
|  | "dec         %2                            \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(dst_argb),     // %0 | 
|  | "=&d"(pixel_temp),  // %1 | 
|  | "+r"(width)         // %2 | 
|  | : "r"(table_argb)     // %3 | 
|  | : "memory", "cc"); | 
|  | } | 
|  | #endif  // HAS_ARGBCOLORTABLEROW_X86 | 
|  |  | 
|  | #ifdef HAS_RGBCOLORTABLEROW_X86 | 
|  | // Tranform RGB pixels with color table. | 
|  | void RGBColorTableRow_X86(uint8_t* dst_argb, | 
|  | const uint8_t* table_argb, | 
|  | int width) { | 
|  | uintptr_t pixel_temp; | 
|  | asm volatile( | 
|  | // 1 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movzb       (%0),%1                       \n" | 
|  | "lea         0x4(%0),%0                    \n" | 
|  | "movzb       0x00(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x4(%0)                  \n" | 
|  | "movzb       -0x3(%0),%1                   \n" | 
|  | "movzb       0x01(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x3(%0)                  \n" | 
|  | "movzb       -0x2(%0),%1                   \n" | 
|  | "movzb       0x02(%3,%1,4),%1              \n" | 
|  | "mov         %b1,-0x2(%0)                  \n" | 
|  | "dec         %2                            \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(dst_argb),     // %0 | 
|  | "=&d"(pixel_temp),  // %1 | 
|  | "+r"(width)         // %2 | 
|  | : "r"(table_argb)     // %3 | 
|  | : "memory", "cc"); | 
|  | } | 
|  | #endif  // HAS_RGBCOLORTABLEROW_X86 | 
|  |  | 
|  | #ifdef HAS_ARGBLUMACOLORTABLEROW_SSSE3 | 
|  | // Tranform RGB pixels with luma table. | 
|  | void ARGBLumaColorTableRow_SSSE3(const uint8_t* src_argb, | 
|  | uint8_t* dst_argb, | 
|  | int width, | 
|  | const uint8_t* luma, | 
|  | uint32_t lumacoeff) { | 
|  | uintptr_t pixel_temp; | 
|  | uintptr_t table_temp; | 
|  | asm volatile( | 
|  | "movd        %6,%%xmm3                     \n" | 
|  | "pshufd      $0x0,%%xmm3,%%xmm3            \n" | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psllw       $0x8,%%xmm4                   \n" | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | // 4 pixel loop. | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%2),%%xmm0                   \n" | 
|  | "pmaddubsw   %%xmm3,%%xmm0                 \n" | 
|  | "phaddw      %%xmm0,%%xmm0                 \n" | 
|  | "pand        %%xmm4,%%xmm0                 \n" | 
|  | "punpcklwd   %%xmm5,%%xmm0                 \n" | 
|  | "movd        %%xmm0,%k1                    \n"  // 32 bit offset | 
|  | "add         %5,%1                         \n" | 
|  | "pshufd      $0x39,%%xmm0,%%xmm0           \n" | 
|  |  | 
|  | "movzb       (%2),%0                       \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,(%3)                      \n" | 
|  | "movzb       0x1(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x1(%3)                   \n" | 
|  | "movzb       0x2(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x2(%3)                   \n" | 
|  | "movzb       0x3(%2),%0                    \n" | 
|  | "mov         %b0,0x3(%3)                   \n" | 
|  |  | 
|  | "movd        %%xmm0,%k1                    \n"  // 32 bit offset | 
|  | "add         %5,%1                         \n" | 
|  | "pshufd      $0x39,%%xmm0,%%xmm0           \n" | 
|  |  | 
|  | "movzb       0x4(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x4(%3)                   \n" | 
|  | "movzb       0x5(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x5(%3)                   \n" | 
|  | "movzb       0x6(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x6(%3)                   \n" | 
|  | "movzb       0x7(%2),%0                    \n" | 
|  | "mov         %b0,0x7(%3)                   \n" | 
|  |  | 
|  | "movd        %%xmm0,%k1                    \n"  // 32 bit offset | 
|  | "add         %5,%1                         \n" | 
|  | "pshufd      $0x39,%%xmm0,%%xmm0           \n" | 
|  |  | 
|  | "movzb       0x8(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x8(%3)                   \n" | 
|  | "movzb       0x9(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0x9(%3)                   \n" | 
|  | "movzb       0xa(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0xa(%3)                   \n" | 
|  | "movzb       0xb(%2),%0                    \n" | 
|  | "mov         %b0,0xb(%3)                   \n" | 
|  |  | 
|  | "movd        %%xmm0,%k1                    \n"  // 32 bit offset | 
|  | "add         %5,%1                         \n" | 
|  |  | 
|  | "movzb       0xc(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0xc(%3)                   \n" | 
|  | "movzb       0xd(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0xd(%3)                   \n" | 
|  | "movzb       0xe(%2),%0                    \n" | 
|  | "movzb       0x00(%1,%0,1),%0              \n" | 
|  | "mov         %b0,0xe(%3)                   \n" | 
|  | "movzb       0xf(%2),%0                    \n" | 
|  | "mov         %b0,0xf(%3)                   \n" | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "lea         0x10(%3),%3                   \n" | 
|  | "sub         $0x4,%4                       \n" | 
|  | "jg          1b                            \n" | 
|  | : "=&d"(pixel_temp),  // %0 | 
|  | "=&a"(table_temp),  // %1 | 
|  | "+r"(src_argb),     // %2 | 
|  | "+r"(dst_argb),     // %3 | 
|  | "+rm"(width)        // %4 | 
|  | : "r"(luma),          // %5 | 
|  | "rm"(lumacoeff)     // %6 | 
|  | : "memory", "cc", "xmm0", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_ARGBLUMACOLORTABLEROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_NV21TOYUV24ROW_AVX2 | 
|  |  | 
|  | // begin NV21ToYUV24Row_C avx2 constants | 
|  | static const ulvec8 kBLEND0 = {0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, | 
|  | 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, | 
|  | 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, | 
|  | 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00}; | 
|  |  | 
|  | static const ulvec8 kBLEND1 = {0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, | 
|  | 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, | 
|  | 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, | 
|  | 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}; | 
|  |  | 
|  | static const ulvec8 kBLEND2 = {0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, | 
|  | 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, | 
|  | 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, | 
|  | 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00}; | 
|  |  | 
|  | static const ulvec8 kSHUF0 = {0x00, 0x0b, 0x80, 0x01, 0x0c, 0x80, 0x02, 0x0d, | 
|  | 0x80, 0x03, 0x0e, 0x80, 0x04, 0x0f, 0x80, 0x05, | 
|  | 0x00, 0x0b, 0x80, 0x01, 0x0c, 0x80, 0x02, 0x0d, | 
|  | 0x80, 0x03, 0x0e, 0x80, 0x04, 0x0f, 0x80, 0x05}; | 
|  |  | 
|  | static const ulvec8 kSHUF1 = {0x80, 0x00, 0x0b, 0x80, 0x01, 0x0c, 0x80, 0x02, | 
|  | 0x0d, 0x80, 0x03, 0x0e, 0x80, 0x04, 0x0f, 0x80, | 
|  | 0x80, 0x00, 0x0b, 0x80, 0x01, 0x0c, 0x80, 0x02, | 
|  | 0x0d, 0x80, 0x03, 0x0e, 0x80, 0x04, 0x0f, 0x80}; | 
|  |  | 
|  | static const ulvec8 kSHUF2 = {0x0a, 0x80, 0x00, 0x0b, 0x80, 0x01, 0x0c, 0x80, | 
|  | 0x02, 0x0d, 0x80, 0x03, 0x0e, 0x80, 0x04, 0x0f, | 
|  | 0x0a, 0x80, 0x00, 0x0b, 0x80, 0x01, 0x0c, 0x80, | 
|  | 0x02, 0x0d, 0x80, 0x03, 0x0e, 0x80, 0x04, 0x0f}; | 
|  |  | 
|  | static const ulvec8 kSHUF3 = {0x80, 0x80, 0x06, 0x80, 0x80, 0x07, 0x80, 0x80, | 
|  | 0x08, 0x80, 0x80, 0x09, 0x80, 0x80, 0x0a, 0x80, | 
|  | 0x80, 0x80, 0x06, 0x80, 0x80, 0x07, 0x80, 0x80, | 
|  | 0x08, 0x80, 0x80, 0x09, 0x80, 0x80, 0x0a, 0x80}; | 
|  |  | 
|  | static const ulvec8 kSHUF4 = {0x05, 0x80, 0x80, 0x06, 0x80, 0x80, 0x07, 0x80, | 
|  | 0x80, 0x08, 0x80, 0x80, 0x09, 0x80, 0x80, 0x0a, | 
|  | 0x05, 0x80, 0x80, 0x06, 0x80, 0x80, 0x07, 0x80, | 
|  | 0x80, 0x08, 0x80, 0x80, 0x09, 0x80, 0x80, 0x0a}; | 
|  |  | 
|  | static const ulvec8 kSHUF5 = {0x80, 0x05, 0x80, 0x80, 0x06, 0x80, 0x80, 0x07, | 
|  | 0x80, 0x80, 0x08, 0x80, 0x80, 0x09, 0x80, 0x80, | 
|  | 0x80, 0x05, 0x80, 0x80, 0x06, 0x80, 0x80, 0x07, | 
|  | 0x80, 0x80, 0x08, 0x80, 0x80, 0x09, 0x80, 0x80}; | 
|  |  | 
|  | // NV21ToYUV24Row_AVX2 | 
|  | void NV21ToYUV24Row_AVX2(const uint8_t* src_y, | 
|  | const uint8_t* src_vu, | 
|  | uint8_t* dst_yuv24, | 
|  | int width) { | 
|  | uint8_t* src_y_ptr; | 
|  | uint64_t src_offset = 0; | 
|  | uint64_t width64; | 
|  |  | 
|  | width64 = width; | 
|  | src_y_ptr = (uint8_t*)src_y; | 
|  |  | 
|  | asm volatile( | 
|  | "vmovdqu     %5, %%ymm0                    \n"  // init blend value | 
|  | "vmovdqu     %6, %%ymm1                    \n"  // init blend value | 
|  | "vmovdqu     %7, %%ymm2                    \n"  // init blend value | 
|  | //      "sub         $0x20, %3                     \n"  //sub 32 from | 
|  | //      width for final loop | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n"      // label 1 | 
|  | "vmovdqu     (%0,%4), %%ymm3               \n"      // src_y | 
|  | "vmovdqu     1(%1,%4), %%ymm4              \n"      // src_uv+1 | 
|  | "vmovdqu     (%1), %%ymm5                  \n"      // src_uv | 
|  | "vpshufb     %8, %%ymm3, %%ymm13           \n"      // y, kSHUF0 for shuf | 
|  | "vpshufb     %9, %%ymm4, %%ymm14           \n"      // uv+1, kSHUF1 for | 
|  | // shuf | 
|  | "vpshufb     %10, %%ymm5, %%ymm15          \n"      // uv, kSHUF2 for | 
|  | // shuf | 
|  | "vpshufb     %11, %%ymm3, %%ymm3           \n"      // y kSHUF3 for shuf | 
|  | "vpshufb     %12, %%ymm4, %%ymm4           \n"      // uv+1 kSHUF4 for | 
|  | // shuf | 
|  | "vpblendvb   %%ymm0, %%ymm14, %%ymm13, %%ymm12 \n"  // blend 0 | 
|  | "vpblendvb   %%ymm0, %%ymm13, %%ymm14, %%ymm14 \n"  // blend 0 | 
|  | "vpblendvb   %%ymm2, %%ymm15, %%ymm12, %%ymm12 \n"  // blend 2 | 
|  | "vpblendvb   %%ymm1, %%ymm15, %%ymm14, %%ymm13 \n"  // blend 1 | 
|  | "vpshufb     %13, %%ymm5, %%ymm15          \n"      // shuffle const | 
|  | "vpor        %%ymm4, %%ymm3, %%ymm5        \n"      // get results | 
|  | "vmovdqu     %%ymm12, 0x20(%2)             \n"      // store dst_yuv+20h | 
|  | "vpor        %%ymm15, %%ymm5, %%ymm3       \n"      // get results | 
|  | "add         $0x20, %4                     \n"      // add to src buffer | 
|  | // ptr | 
|  | "vinserti128 $0x1, %%xmm3, %%ymm13, %%ymm4 \n"      // insert | 
|  | "vperm2i128  $0x31, %%ymm13, %%ymm3, %%ymm5 \n"     // insert | 
|  | "vmovdqu     %%ymm4, (%2)                  \n"      // store dst_yuv | 
|  | "vmovdqu     %%ymm5, 0x40(%2)              \n"      // store dst_yuv+40h | 
|  | "add         $0x60,%2                      \n"      // add to dst buffer | 
|  | // ptr | 
|  | //      "cmp         %3, %4                        \n" //(width64 - | 
|  | //      32 bytes) and src_offset | 
|  | "sub         $0x20,%3                      \n"  // 32 pixels per loop | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n"  // sse-avx2 | 
|  | // transistions | 
|  |  | 
|  | : "+r"(src_y),      //%0 | 
|  | "+r"(src_vu),     //%1 | 
|  | "+r"(dst_yuv24),  //%2 | 
|  | "+r"(width64),    //%3 | 
|  | "+r"(src_offset)  //%4 | 
|  | : "m"(kBLEND0),     //%5 | 
|  | "m"(kBLEND1),     //%6 | 
|  | "m"(kBLEND2),     //%7 | 
|  | "m"(kSHUF0),      //%8 | 
|  | "m"(kSHUF1),      //%9 | 
|  | "m"(kSHUF2),      //%10 | 
|  | "m"(kSHUF3),      //%11 | 
|  | "m"(kSHUF4),      //%12 | 
|  | "m"(kSHUF5)       //%13 | 
|  | : "memory", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm12", | 
|  | "xmm13", "xmm14", "xmm15"); | 
|  | } | 
|  | #endif  // HAS_NV21TOYUV24ROW_AVX2 | 
|  |  | 
|  | #ifdef HAS_SWAPUVROW_SSSE3 | 
|  |  | 
|  | // Shuffle table for reversing the bytes. | 
|  | static const uvec8 kShuffleUVToVU = {1u, 0u, 3u,  2u,  5u,  4u,  7u,  6u, | 
|  | 9u, 8u, 11u, 10u, 13u, 12u, 15u, 14u}; | 
|  |  | 
|  | // Convert UV plane of NV12 to VU of NV21. | 
|  | void SwapUVRow_SSSE3(const uint8_t* src_uv, uint8_t* dst_vu, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "movdqu      %3,%%xmm5                     \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n" | 
|  | "movdqu      0x10(%0),%%xmm1               \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "pshufb      %%xmm5,%%xmm0                 \n" | 
|  | "pshufb      %%xmm5,%%xmm1                 \n" | 
|  | "movdqu      %%xmm0,(%1)                   \n" | 
|  | "movdqu      %%xmm1,0x10(%1)               \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "sub         $0x10,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_uv),        // %0 | 
|  | "+r"(dst_vu),        // %1 | 
|  | "+r"(width)          // %2 | 
|  | : "m"(kShuffleUVToVU)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SWAPUVROW_SSSE3 | 
|  |  | 
|  | #ifdef HAS_SWAPUVROW_AVX2 | 
|  | void SwapUVRow_AVX2(const uint8_t* src_uv, uint8_t* dst_vu, int width) { | 
|  | asm volatile( | 
|  |  | 
|  | "vbroadcastf128 %3,%%ymm5                  \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n" | 
|  | "vmovdqu     0x20(%0),%%ymm1               \n" | 
|  | "lea         0x40(%0),%0                   \n" | 
|  | "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vmovdqu     %%ymm0,(%1)                   \n" | 
|  | "vmovdqu     %%ymm1,0x20(%1)               \n" | 
|  | "lea         0x40(%1),%1                   \n" | 
|  | "sub         $0x20,%2                      \n" | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_uv),        // %0 | 
|  | "+r"(dst_vu),        // %1 | 
|  | "+r"(width)          // %2 | 
|  | : "m"(kShuffleUVToVU)  // %3 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm5"); | 
|  | } | 
|  | #endif  // HAS_SWAPUVROW_AVX2 | 
|  |  | 
|  | void HalfMergeUVRow_SSSE3(const uint8_t* src_u, | 
|  | int src_stride_u, | 
|  | const uint8_t* src_v, | 
|  | int src_stride_v, | 
|  | uint8_t* dst_uv, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "pcmpeqb     %%xmm4,%%xmm4                 \n" | 
|  | "psrlw       $0xf,%%xmm4                   \n" | 
|  | "packuswb    %%xmm4,%%xmm4                 \n" | 
|  | "pxor        %%xmm5,%%xmm5                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movdqu      (%0),%%xmm0                   \n"  // load 16 U values | 
|  | "movdqu      (%1),%%xmm1                   \n"  // load 16 V values | 
|  | "movdqu      0(%0,%4,1),%%xmm2             \n"  // 16 from next row | 
|  | "movdqu      0(%1,%5,1),%%xmm3             \n" | 
|  | "lea         0x10(%0),%0                   \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm0                 \n"  // half size | 
|  | "pmaddubsw   %%xmm4,%%xmm1                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm2                 \n" | 
|  | "pmaddubsw   %%xmm4,%%xmm3                 \n" | 
|  | "lea         0x10(%1),%1                   \n" | 
|  | "paddw       %%xmm2,%%xmm0                 \n" | 
|  | "paddw       %%xmm3,%%xmm1                 \n" | 
|  | "psrlw       $0x1,%%xmm0                   \n" | 
|  | "psrlw       $0x1,%%xmm1                   \n" | 
|  | "pavgw       %%xmm5,%%xmm0                 \n" | 
|  | "pavgw       %%xmm5,%%xmm1                 \n" | 
|  | "packuswb    %%xmm0,%%xmm0                 \n" | 
|  | "packuswb    %%xmm1,%%xmm1                 \n" | 
|  | "punpcklbw   %%xmm1,%%xmm0                 \n" | 
|  | "movdqu      %%xmm0,(%2)                   \n"  // store 8 UV pixels | 
|  | "lea         0x10(%2),%2                   \n" | 
|  | "sub         $0x10,%3                      \n"  // 16 src pixels per loop | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_u),                    // %0 | 
|  | "+r"(src_v),                    // %1 | 
|  | "+r"(dst_uv),                   // %2 | 
|  | "+r"(width)                     // %3 | 
|  | : "r"((intptr_t)(src_stride_u)),  // %4 | 
|  | "r"((intptr_t)(src_stride_v))   // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void HalfMergeUVRow_AVX2(const uint8_t* src_u, | 
|  | int src_stride_u, | 
|  | const uint8_t* src_v, | 
|  | int src_stride_v, | 
|  | uint8_t* dst_uv, | 
|  | int width) { | 
|  | asm volatile( | 
|  | "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n" | 
|  | "vpsrlw      $0xf,%%ymm4,%%ymm4            \n" | 
|  | "vpackuswb   %%ymm4,%%ymm4,%%ymm4          \n" | 
|  | "vpxor       %%ymm5,%%ymm5,%%ymm5          \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "vmovdqu     (%0),%%ymm0                   \n"  // load 32 U values | 
|  | "vmovdqu     (%1),%%ymm1                   \n"  // load 32 V values | 
|  | "vmovdqu     0(%0,%4,1),%%ymm2             \n"  // 32 from next row | 
|  | "vmovdqu     0(%1,%5,1),%%ymm3             \n" | 
|  | "lea         0x20(%0),%0                   \n" | 
|  | "vpmaddubsw  %%ymm4,%%ymm0,%%ymm0          \n"  // half size | 
|  | "vpmaddubsw  %%ymm4,%%ymm1,%%ymm1          \n" | 
|  | "vpmaddubsw  %%ymm4,%%ymm2,%%ymm2          \n" | 
|  | "vpmaddubsw  %%ymm4,%%ymm3,%%ymm3          \n" | 
|  | "lea         0x20(%1),%1                   \n" | 
|  | "vpaddw      %%ymm2,%%ymm0,%%ymm0          \n" | 
|  | "vpaddw      %%ymm3,%%ymm1,%%ymm1          \n" | 
|  | "vpsrlw      $0x1,%%ymm0,%%ymm0            \n" | 
|  | "vpsrlw      $0x1,%%ymm1,%%ymm1            \n" | 
|  | "vpavgw      %%ymm5,%%ymm0,%%ymm0          \n" | 
|  | "vpavgw      %%ymm5,%%ymm1,%%ymm1          \n" | 
|  | "vpackuswb   %%ymm0,%%ymm0,%%ymm0          \n" | 
|  | "vpackuswb   %%ymm1,%%ymm1,%%ymm1          \n" | 
|  | "vpunpcklbw  %%ymm1,%%ymm0,%%ymm0          \n" | 
|  | "vmovdqu     %%ymm0,(%2)                   \n"  // store 16 UV pixels | 
|  | "lea         0x20(%2),%2                   \n" | 
|  | "sub         $0x20,%3                      \n"  // 32 src pixels per loop | 
|  | "jg          1b                            \n" | 
|  | "vzeroupper                                \n" | 
|  | : "+r"(src_u),                    // %0 | 
|  | "+r"(src_v),                    // %1 | 
|  | "+r"(dst_uv),                   // %2 | 
|  | "+r"(width)                     // %3 | 
|  | : "r"((intptr_t)(src_stride_u)),  // %4 | 
|  | "r"((intptr_t)(src_stride_v))   // %5 | 
|  | : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); | 
|  | } | 
|  |  | 
|  | void ClampFloatToZero_SSE2(const float* src_x, float* dst_y, int width) { | 
|  | asm volatile( | 
|  | "pxor        %%xmm1,%%xmm1                 \n" | 
|  |  | 
|  | LABELALIGN | 
|  | "1:                                        \n" | 
|  | "movd        (%0),%%xmm0                   \n"  // load float | 
|  | "maxss       %%xmm1, %%xmm0                \n"  // clamp to zero | 
|  | "add         4, %0                         \n" | 
|  | "movd        %%xmm0, (%1)                  \n"  // store float | 
|  | "add         4, %1                         \n" | 
|  | "sub         $0x4,%2                       \n"  // 1 float per loop | 
|  | "jg          1b                            \n" | 
|  | : "+r"(src_x),  // %0 | 
|  | "+r"(dst_y),  // %1 | 
|  | "+r"(width)   // %2 | 
|  | : | 
|  | : "memory", "cc", "xmm0", "xmm1"); | 
|  | } | 
|  |  | 
|  | #endif  // defined(__x86_64__) || defined(__i386__) | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | }  // extern "C" | 
|  | }  // namespace libyuv | 
|  | #endif |