Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/aom/third_party/libyuv/source/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 306 kB image not shown  

Impressum row_gcc.cc

  Sprache: C
 

/*
 *  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, floatint 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

Messung V0.5 in Prozent
C=86 H=87 G=86

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.348Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-26) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.