shithub: openh264

Download patch

ref: 14750b4797a011da07c8cb718b13aa3a02ac3d84
parent: 906dacd34972e42819dab320960ffcfb7b84aada
author: gxw <guxiwei-hf@loongson.cn>
date: Mon Aug 13 05:23:03 EDT 2018

Add optimization files for loongson platform

1. Add dct_mmi.c in codec/decoder/core/mips
2. Add vaa_mmi.c in codec/processing/src/mips
3. Add optimization functions in codec/common/src/mc.cpp

Change-Id: I9060a5f42ac7903b377b48ef7fe92809a2ba4481

--- a/codec/common/src/mc.cpp
+++ b/codec/common/src/mc.cpp
@@ -43,6 +43,7 @@
 #include "cpu_core.h"
 #include "ls_defines.h"
 #include "macros.h"
+#include "asmdefs_mmi.h"
 
 namespace {
 
@@ -1659,6 +1660,2541 @@
 }
 #endif
 
+#if defined(HAVE_MMI)
+#define MMI_LOAD_8P(f0, f2, f4, r0) \
+  "gsldlc1    "#f0", 0x7("#r0")               \n\t" \
+  "gsldrc1    "#f0", 0x0("#r0")               \n\t" \
+  "punpckhbh  "#f2", "#f0", "#f4"             \n\t" \
+  "punpcklbh  "#f0", "#f0", "#f4"             \n\t"
+
+#define FILTER_HV_W4(f0, f2, f4, f6, f8, f10, f12, f14, f16, f18, \
+                     f20, f22, f24, f26, f28, f30, r0, r1, r2) \
+  "paddh      "#f0", "#f0", "#f20"            \n\t" \
+  "paddh      "#f2", "#f2", "#f22"            \n\t" \
+  "mov.d      "#f28", "#f8"                   \n\t" \
+  "mov.d      "#f30", "#f10"                  \n\t" \
+  "mov.d      "#f24", "#f4"                   \n\t" \
+  "mov.d      "#f26", "#f6"                   \n\t" \
+  "dmfc1      "#r2", "#f8"                    \n\t" \
+  "dli        "#r1", 0x0010001000100010       \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "paddh      "#f0", "#f0", "#f8"             \n\t" \
+  "paddh      "#f2", "#f2", "#f8"             \n\t" \
+  "paddh      "#f28", "#f28", "#f12"          \n\t" \
+  "paddh      "#f30", "#f30", "#f14"          \n\t" \
+  "paddh      "#f24", "#f24", "#f16"          \n\t" \
+  "paddh      "#f26", "#f26", "#f18"          \n\t" \
+  "dli        "#r1", 0x2                      \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "psllh      "#f28", "#f28", "#f8"           \n\t" \
+  "psllh      "#f30", "#f30", "#f8"           \n\t" \
+  "psubh      "#f28", "#f28", "#f24"          \n\t" \
+  "psubh      "#f30", "#f30", "#f26"          \n\t" \
+  "paddh      "#f0", "#f0", "#f28"            \n\t" \
+  "paddh      "#f2", "#f2", "#f30"            \n\t" \
+  "psllh      "#f28", "#f28", "#f8"           \n\t" \
+  "psllh      "#f30", "#f30", "#f8"           \n\t" \
+  "paddh      "#f0", "#f0", "#f28"            \n\t" \
+  "paddh      "#f2", "#f2", "#f30"            \n\t" \
+  "dli        "#r1", 0x5                      \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "psrah      "#f0", "#f0", "#f8"             \n\t" \
+  "psrah      "#f2", "#f2", "#f8"             \n\t" \
+  "xor        "#f28", "#f28", "#f28"          \n\t" \
+  "packushb   "#f0", "#f0", "#f2"             \n\t" \
+  "gsswlc1    "#f0", 0x3("#r0")               \n\t" \
+  "gsswrc1    "#f0", 0x0("#r0")               \n\t" \
+  "dmtc1      "#r2", "#f8"                    \n\t"
+
+#define FILTER_HV_W8(f0, f2, f4, f6, f8, f10, f12, f14, f16, f18, \
+                     f20, f22, f24, f26, f28, f30, r0, r1, r2) \
+  "paddh      "#f0", "#f0", "#f20"            \n\t" \
+  "paddh      "#f2", "#f2", "#f22"            \n\t" \
+  "mov.d      "#f28", "#f8"                   \n\t" \
+  "mov.d      "#f30", "#f10"                  \n\t" \
+  "mov.d      "#f24", "#f4"                   \n\t" \
+  "mov.d      "#f26", "#f6"                   \n\t" \
+  "dmfc1      "#r2", "#f8"                    \n\t" \
+  "dli        "#r1", 0x0010001000100010       \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "paddh      "#f0", "#f0", "#f8"             \n\t" \
+  "paddh      "#f2", "#f2", "#f8"             \n\t" \
+  "paddh      "#f28", "#f28", "#f12"          \n\t" \
+  "paddh      "#f30", "#f30", "#f14"          \n\t" \
+  "paddh      "#f24", "#f24", "#f16"          \n\t" \
+  "paddh      "#f26", "#f26", "#f18"          \n\t" \
+  "dli        "#r1", 0x2                      \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "psllh      "#f28", "#f28", "#f8"           \n\t" \
+  "psllh      "#f30", "#f30", "#f8"           \n\t" \
+  "psubh      "#f28", "#f28", "#f24"          \n\t" \
+  "psubh      "#f30", "#f30", "#f26"          \n\t" \
+  "paddh      "#f0", "#f0", "#f28"            \n\t" \
+  "paddh      "#f2", "#f2", "#f30"            \n\t" \
+  "psllh      "#f28", "#f28", "#f8"           \n\t" \
+  "psllh      "#f30", "#f30", "#f8"           \n\t" \
+  "paddh      "#f0", "#f0", "#f28"            \n\t" \
+  "paddh      "#f2", "#f2", "#f30"            \n\t" \
+  "dli        "#r1", 0x5                      \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "psrah      "#f0", "#f0", "#f8"             \n\t" \
+  "psrah      "#f2", "#f2", "#f8"             \n\t" \
+  "xor        "#f28", "#f28", "#f28"          \n\t" \
+  "packushb   "#f0", "#f0", "#f2"             \n\t" \
+  "gssdlc1    "#f0", 0x7("#r0")               \n\t" \
+  "gssdrc1    "#f0", 0x0("#r0")               \n\t" \
+  "dmtc1      "#r2", "#f8"                    \n\t"
+
+#define FILTER_VER_ALIGN(f0, f2, f4, f6, f8, f10, f12, f14, f16, f18, \
+                         f20, f22, f24, f26, f28, f30, r0, r1, r2, r3, r4) \
+  "paddh      "#f0", "#f0", "#f20"            \n\t" \
+  "paddh      "#f2", "#f2", "#f22"            \n\t" \
+  "mov.d      "#f24", "#f4"                   \n\t" \
+  "mov.d      "#f26", "#f6"                   \n\t" \
+  "mov.d      "#f28", "#f8"                   \n\t" \
+  "mov.d      "#f30", "#f10"                  \n\t" \
+  "dli        "#r2", 0x2                      \n\t" \
+  "paddh      "#f24", "#f24", "#f16"          \n\t" \
+  "paddh      "#f26", "#f26", "#f18"          \n\t" \
+  "dmfc1      "#r3", "#f8"                    \n\t" \
+  "paddh      "#f28", "#f28", "#f12"          \n\t" \
+  "paddh      "#f30", "#f30", "#f14"          \n\t" \
+  "dmtc1      "#r2", "#f8"                    \n\t" \
+  "psubh      "#f0", "#f0", "#f24"            \n\t" \
+  "psubh      "#f2", "#f2", "#f26"            \n\t" \
+  "psrah      "#f0", "#f0", "#f8"             \n\t" \
+  "psrah      "#f2", "#f2", "#f8"             \n\t" \
+  "paddh      "#f0", "#f0", "#f28"            \n\t" \
+  "paddh      "#f2", "#f2", "#f30"            \n\t" \
+  "psubh      "#f0", "#f0", "#f24"            \n\t" \
+  "psubh      "#f2", "#f2", "#f26"            \n\t" \
+  "psrah      "#f0", "#f0", "#f8"             \n\t" \
+  "psrah      "#f2", "#f2", "#f8"             \n\t" \
+  "dmtc1      "#r4", "#f8"                    \n\t" \
+  "paddh      "#f28", "#f28", "#f0"           \n\t" \
+  "paddh      "#f30", "#f30", "#f2"           \n\t" \
+  "dli        "#r2", 0x6                      \n\t" \
+  "paddh      "#f28", "#f28", "#f8"           \n\t" \
+  "paddh      "#f30", "#f30", "#f8"           \n\t" \
+  "dmtc1      "#r2", "#f8"                    \n\t" \
+  "psrah      "#f28", "#f28", "#f8"           \n\t" \
+  "psrah      "#f30", "#f30", "#f8"           \n\t" \
+  "packushb   "#f28", "#f28", "#f30"          \n\t" \
+  "gssdxc1    "#f28", 0x0("#r0", "#r1")       \n\t" \
+  "dmtc1      "#r3", "#f8"                    \n\t"
+
+#define FILTER_VER_UNALIGN(f0, f2, f4, f6, f8, f10, f12, f14, f16, f18, \
+                           f20, f22, f24, f26, f28, f30, r0, r1, r2, r3) \
+  "paddh      "#f0", "#f0", "#f20"            \n\t" \
+  "paddh      "#f2", "#f2", "#f22"            \n\t" \
+  "mov.d      "#f24", "#f4"                   \n\t" \
+  "mov.d      "#f26", "#f6"                   \n\t" \
+  "mov.d      "#f28", "#f8"                   \n\t" \
+  "mov.d      "#f30", "#f10"                  \n\t" \
+  "dli        "#r1", 0x2                      \n\t" \
+  "paddh      "#f24", "#f24", "#f16"          \n\t" \
+  "paddh      "#f26", "#f26", "#f18"          \n\t" \
+  "dmfc1      "#r2", "#f8"                    \n\t" \
+  "paddh      "#f28", "#f28", "#f12"          \n\t" \
+  "paddh      "#f30", "#f30", "#f14"          \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "psubh      "#f0", "#f0", "#f24"            \n\t" \
+  "psubh      "#f2", "#f2", "#f26"            \n\t" \
+  "psrah      "#f0", "#f0", "#f8"             \n\t" \
+  "psrah      "#f2", "#f2", "#f8"             \n\t" \
+  "paddh      "#f0", "#f0", "#f28"            \n\t" \
+  "paddh      "#f2", "#f2", "#f30"            \n\t" \
+  "psubh      "#f0", "#f0", "#f24"            \n\t" \
+  "psubh      "#f2", "#f2", "#f26"            \n\t" \
+  "psrah      "#f0", "#f0", "#f8"             \n\t" \
+  "psrah      "#f2", "#f2", "#f8"             \n\t" \
+  "dmtc1      "#r3", "#f8"                    \n\t" \
+  "paddh      "#f28", "#f28", "#f0"           \n\t" \
+  "paddh      "#f30", "#f30", "#f2"           \n\t" \
+  "dli        "#r1", 0x6                      \n\t" \
+  "paddh      "#f28", "#f28", "#f8"           \n\t" \
+  "paddh      "#f30", "#f30", "#f8"           \n\t" \
+  "dmtc1      "#r1", "#f8"                    \n\t" \
+  "psrah      "#f28", "#f28", "#f8"           \n\t" \
+  "psrah      "#f30", "#f30", "#f8"           \n\t" \
+  "packushb   "#f28", "#f28", "#f30"          \n\t" \
+  "gssdlc1    "#f28", 0x7("#r0")              \n\t" \
+  "gssdrc1    "#f28", 0x0("#r0")              \n\t" \
+  "dmtc1      "#r2", "#f8"                    \n\t"
+
+void McHorVer20Width5_mmi(const uint8_t *pSrc, int32_t iSrcStride, uint8_t *pDst,
+                          int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], -0x2          \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dli        $10, 0x0010001000100010         \n\t"
+    "dli        $11, 0x5                        \n\t"
+    "1:                                         \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "mov.d      $f28, $f8                       \n\t"
+    "mov.d      $f30, $f10                      \n\t"
+    "paddh      $f28, $f28, $f12                \n\t"
+    "paddh      $f30, $f30, $f14                \n\t"
+    "mov.d      $f24, $f16                      \n\t"
+    "mov.d      $f26, $f18                      \n\t"
+    "paddh      $f24, $f24, $f20                \n\t"
+    "paddh      $f26, $f26, $f22                \n\t"
+    "dmfc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f12                        \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "psubh      $f24, $f24, $f28                \n\t"
+    "psubh      $f26, $f26, $f30                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+
+    "dmtc1      $10, $f12                       \n\t"
+    "paddh      $f0, $f0, $f12                  \n\t"
+    "paddh      $f2, $f2, $f12                  \n\t"
+    "dmtc1      $11, $f12                       \n\t"
+    "psrah      $f0, $f0, $f12                  \n\t"
+    "psrah      $f2, $f2, $f12                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+
+    "gsswlc1    $f0, 0x3(%[pDst])               \n\t"
+    "gsswrc1    $f0, 0x0(%[pDst])               \n\t"
+
+    "gsldlc1    $f0, 0xd(%[pSrc])               \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f0, 0x6(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "dmtc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+
+    "paddh      $f16, $f16, $f4                 \n\t"
+    "paddh      $f18, $f18, $f6                 \n\t"
+    "paddh      $f20, $f20, $f12                \n\t"
+    "paddh      $f22, $f22, $f14                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "psubh      $f20, $f20, $f16                \n\t"
+    "psubh      $f22, $f22, $f18                \n\t"
+    "paddh      $f8, $f8, $f0                   \n\t"
+    "paddh      $f10, $f10, $f2                 \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+
+    "dmtc1      $10, $f24                       \n\t"
+    "paddh      $f8, $f8, $f24                  \n\t"
+    "paddh      $f10, $f10, $f24                \n\t"
+    "dmtc1      $11, $f24                       \n\t"
+    "psrah      $f8, $f8, $f24                  \n\t"
+    "psrah      $f10, $f10, $f24                \n\t"
+    "packushb   $f8, $f8, $f10                  \n\t"
+    "gsswlc1    $f8, 0x4(%[pDst])               \n\t"
+    "gsswrc1    $f8, 0x1(%[pDst])               \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"((unsigned char *)pSrc), [pDst]"+&r"((unsigned char *)pDst),
+      [iWidth]"+&r"((int)iWidth), [iHeight]"+&r"((int)iHeight)
+    : [iSrcStride]"r"((int)iSrcStride),  [iDstStride]"r"((int)iDstStride)
+    : "memory", "$8", "$9", "$10", "$11", "$f0", "$f2", "$f4", "$f6", "$f8",
+      "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26",
+      "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void McHorVer20Width9Or17_mmi(const uint8_t *pSrc, int32_t iSrcStride, uint8_t *pDst,
+                              int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], -0x2          \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dli        $9, 0x9                         \n\t"
+    "dli        $10, 0x0010001000100010         \n\t"
+    "dli        $11, 0x5                        \n\t"
+    "bne        %[iWidth], $9, 2f               \n\t"
+    "1:                                         \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "mov.d      $f28, $f8                       \n\t"
+    "mov.d      $f30, $f10                      \n\t"
+    "paddh      $f28, $f28, $f12                \n\t"
+    "paddh      $f30, $f30, $f14                \n\t"
+    "mov.d      $f24, $f16                      \n\t"
+    "mov.d      $f26, $f18                      \n\t"
+    "paddh      $f24, $f24, $f20                \n\t"
+    "paddh      $f26, $f26, $f22                \n\t"
+    "dmfc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f12                        \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "psubh      $f24, $f24, $f28                \n\t"
+    "psubh      $f26, $f26, $f30                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+
+    "dmtc1      $10, $f12                       \n\t"
+    "paddh      $f0, $f0, $f12                  \n\t"
+    "paddh      $f2, $f2, $f12                  \n\t"
+    "dmtc1      $11, $f12                       \n\t"
+    "psrah      $f0, $f0, $f12                  \n\t"
+    "psrah      $f2, $f2, $f12                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+
+    "gsswlc1    $f0, 0x3(%[pDst])               \n\t"
+    "gsswrc1    $f0, 0x0(%[pDst])               \n\t"
+
+    "gsldlc1    $f0, 0xd(%[pSrc])               \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f0, 0x6(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "dmtc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+
+    "paddh      $f16, $f16, $f4                 \n\t"
+    "paddh      $f18, $f18, $f6                 \n\t"
+    "paddh      $f20, $f20, $f12                \n\t"
+    "paddh      $f22, $f22, $f14                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "psubh      $f20, $f20, $f16                \n\t"
+    "psubh      $f22, $f22, $f18                \n\t"
+    "paddh      $f8, $f8, $f0                   \n\t"
+    "paddh      $f10, $f10, $f2                 \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+
+    "dmtc1      $10, $f24                       \n\t"
+    "paddh      $f8, $f8, $f24                  \n\t"
+    "paddh      $f10, $f10, $f24                \n\t"
+    "dmtc1      $11, $f24                       \n\t"
+    "psrah      $f8, $f8, $f24                  \n\t"
+    "psrah      $f10, $f10, $f24                \n\t"
+    "packushb   $f8, $f8, $f10                  \n\t"
+    "gssdlc1    $f8, 0x8(%[pDst])               \n\t"
+    "gssdrc1    $f8, 0x1(%[pDst])               \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    "j          3f                              \n\t"
+
+    "2:                                         \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "dmtc1      $8, $f30                        \n\t"
+    "paddh      $f8, $f8, $f12                  \n\t"
+    "paddh      $f10, $f10, $f14                \n\t"
+    "paddh      $f16, $f16, $f20                \n\t"
+    "paddh      $f18, $f18, $f22                \n\t"
+    "psllh      $f16, $f16, $f30                \n\t"
+    "psllh      $f18, $f18, $f30                \n\t"
+    "psubh      $f16, $f16, $f8                 \n\t"
+    "psubh      $f18, $f18, $f10                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "psllh      $f16, $f16, $f30                \n\t"
+    "psllh      $f18, $f18, $f30                \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+
+    "dmtc1      $10, $f30                       \n\t"
+    "paddh      $f0, $f0, $f30                  \n\t"
+    "paddh      $f2, $f2, $f30                  \n\t"
+    "dmtc1      $11, $f30                       \n\t"
+    "psrah      $f0, $f0, $f30                  \n\t"
+    "psrah      $f2, $f2, $f30                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+
+    "gsldlc1    $f0, 15(%[pSrc])                \n\t"
+    "gsldlc1    $f4, 0x14(%[pSrc])              \n\t"
+    "gsldlc1    $f8, 0x10(%[pSrc])              \n\t"
+    "gsldlc1    $f12, 0x13(%[pSrc])             \n\t"
+    "gsldlc1    $f16, 0x11(%[pSrc])             \n\t"
+    "gsldlc1    $f20, 0x12(%[pSrc])             \n\t"
+    "gsldrc1    $f0, 8(%[pSrc])                 \n\t"
+    "gsldrc1    $f4, 0xd(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x9(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0xc(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0xb(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "mov.d      $f28, $f8                       \n\t"
+    "mov.d      $f30, $f10                      \n\t"
+    "paddh      $f28, $f28, $f12                \n\t"
+    "paddh      $f30, $f30, $f14                \n\t"
+    "mov.d      $f24, $f16                      \n\t"
+    "mov.d      $f26, $f18                      \n\t"
+    "paddh      $f24, $f24, $f20                \n\t"
+    "paddh      $f26, $f26, $f22                \n\t"
+    "dmfc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f12                        \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "psubh      $f24, $f24, $f28                \n\t"
+    "psubh      $f26, $f26, $f30                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+
+    "dmtc1      $10, $f30                       \n\t"
+    "paddh      $f0, $f0, $f30                  \n\t"
+    "paddh      $f2, $f2, $f30                  \n\t"
+    "dmtc1      $11, $f30                       \n\t"
+    "psrah      $f0, $f0, $f30                  \n\t"
+    "psrah      $f2, $f2, $f30                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+    "gsswlc1    $f0, 0xb(%[pDst])               \n\t"
+    "gsswrc1    $f0, 0x8(%[pDst])               \n\t"
+
+    "dmtc1      $9, $f12                        \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "dli        $9, 0x20                        \n\t"
+    "gsldlc1    $f0, 0x15(%[pSrc])              \n\t"
+    "dmtc1      $9, $f30                        \n\t"
+    "gsldrc1    $f0, 0xE(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+
+    "paddh      $f16, $f16, $f4                 \n\t"
+    "paddh      $f18, $f18, $f6                 \n\t"
+    "paddh      $f20, $f20, $f12                \n\t"
+    "paddh      $f22, $f22, $f14                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "psubh      $f20, $f20, $f16                \n\t"
+    "psubh      $f22, $f22, $f18                \n\t"
+    "paddh      $f8, $f8, $f0                   \n\t"
+    "paddh      $f10, $f10, $f2                 \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+
+    "dmtc1      $10, $f24                       \n\t"
+    "paddh      $f8, $f8, $f24                  \n\t"
+    "paddh      $f10, $f10, $f24                \n\t"
+    "dmtc1      $11, $f24                       \n\t"
+    "psrah      $f8, $f8, $f24                  \n\t"
+    "psrah      $f10, $f10, $f24                \n\t"
+    "packushb   $f8, $f8, $f10                  \n\t"
+    "gssdlc1    $f8, 0x10(%[pDst])              \n\t"
+    "gssdrc1    $f8, 0x9(%[pDst])               \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 2b                  \n\t"
+    "3:                                         \n\t"
+    : [pSrc]"+&r"((unsigned char *)pSrc), [pDst]"+&r"((unsigned char *)pDst),
+      [iWidth]"+&r"((int)iWidth), [iHeight]"+&r"((int)iHeight)
+    : [iSrcStride]"r"((int)iSrcStride),  [iDstStride]"r"((int)iDstStride)
+    : "memory", "$8", "$9", "$10", "$11", "$f0", "$f2", "$f4", "$f6", "$f8",
+      "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26",
+      "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+//horizontal filter to gain half sample, that is (2, 0) location in quarter sample
+static inline void McHorVer20Width5Or9Or17_mmi(const uint8_t* pSrc, int32_t iSrcStride,
+                                               uint8_t* pDst, int32_t iDstStride,
+                                               int32_t iWidth, int32_t iHeight) {
+  if (iWidth == 17 || iWidth == 9)
+      McHorVer20Width9Or17_mmi(pSrc, iSrcStride, pDst, iDstStride, iWidth, iHeight);
+  else //if (iWidth == 5)
+      McHorVer20Width5_mmi(pSrc, iSrcStride, pDst, iDstStride, iWidth, iHeight);
+}
+
+void McHorVer02Height5_mmi(const uint8_t *pSrc, int32_t iSrcStride, uint8_t *pDst,
+                           int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "move       $12, %[pSrc]                    \n\t"
+    "move       $13, %[pDst]                    \n\t"
+    "move       $14, %[iHeight]                 \n\t"
+
+    "dsrl       %[iWidth], %[iWidth], 0x2       \n\t"
+    PTR_ADDU   "$10, %[iSrcStride], %[iSrcStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], $10           \n\t"
+
+    "1:                                         \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    MMI_LOAD_8P($f0, $f2, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f4, $f6, $f28, $8)
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f8, $f10, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f12, $f14, $f28, $8)
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f16, $f18, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f20, $f22, $f28, $8)
+    FILTER_HV_W4($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                 $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f24, $f26, $f28, %[pSrc])
+    "mov.d      $f0, $f4                        \n\t"
+    "mov.d      $f2, $f6                        \n\t"
+    "mov.d      $f4, $f8                        \n\t"
+    "mov.d      $f6, $f10                       \n\t"
+    "mov.d      $f8, $f12                       \n\t"
+    "mov.d      $f10, $f14                      \n\t"
+    "mov.d      $f12, $f16                      \n\t"
+    "mov.d      $f14, $f18                      \n\t"
+    "mov.d      $f16, $f20                      \n\t"
+    "mov.d      $f18, $f22                      \n\t"
+    "mov.d      $f20, $f24                      \n\t"
+    "mov.d      $f22, $f26                      \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+
+    "2:                                         \n\t"
+    FILTER_HV_W4($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                 $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f24, $f26, $f28, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W4($f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24,
+                 $f26, $f28, $f30, $f0, $f2, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f28, $f30, $f0, $8)
+    FILTER_HV_W4($f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28,
+                 $f30, $f0, $f2, $f4, $f6, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f0, $f2, $f4, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W4($f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0,
+                 $f2, $f4, $f6, $f8, $f10, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f4, $f6, $f8, $8)
+    FILTER_HV_W4($f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6,
+                 $f8, $f10, $f12, $f14, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f8, $f10, $f12, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W4($f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10,
+                 $f12, $f14, $f16, $f18, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f12, $f14, $f16, $8)
+    FILTER_HV_W4($f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14,
+                 $f16, $f18, $f20, $f22, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f16, $f18, $f20, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W4($f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18,
+                 $f20, $f22, $f24, $f26, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f20, $f22, $f24, $8)
+    "j          2b                              \n\t"
+
+    "3:                                         \n\t"
+    PTR_ADDIU  "%[iWidth], %[iWidth], -0x1      \n\t"
+    "beqz       %[iWidth], 4f                   \n\t"
+    "move       %[pSrc], $12                    \n\t"
+    "move       %[pDst], $13                    \n\t"
+    "move       %[iHeight], $14                 \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], $10           \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], 0x4           \n\t"
+    PTR_ADDIU  "%[pDst], %[pDst], 0x4           \n\t"
+    "j          1b                              \n\t"
+    "4:                                         \n\t"
+    : [pSrc]"+&r"((unsigned char *)pSrc), [pDst]"+&r"((unsigned char *)pDst),
+      [iWidth]"+&r"(iWidth), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride),  [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$9", "$10", "$12", "$13", "$14", "$f0", "$f2", "$f4",
+      "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
+      "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void McHorVer02Height9Or17_mmi(const uint8_t *pSrc, int32_t iSrcStride, uint8_t *pDst,
+                               int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "move       $12, %[pSrc]                    \n\t"
+    "move       $13, %[pDst]                    \n\t"
+    "move       $14, %[iHeight]                 \n\t"
+
+    "dsrl       %[iWidth], %[iWidth], 0x3       \n\t"
+    PTR_ADDU   "$10, %[iSrcStride], %[iSrcStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], $10           \n\t"
+
+    "1:                                         \n\t"
+    "dli        $8, 0x20                        \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "dmtc1      $8, $f30                        \n\t"
+
+    MMI_LOAD_8P($f0, $f2, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f4, $f6, $f28, $8)
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f8, $f10, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f12, $f14, $f28, $8)
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f16, $f18, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f20, $f22, $f28, $8)
+    FILTER_HV_W8($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                 $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f24, $f26, $f28, %[pSrc])
+    "mov.d      $f0, $f4                        \n\t"
+    "mov.d      $f2, $f6                        \n\t"
+    "mov.d      $f4, $f8                        \n\t"
+    "mov.d      $f6, $f10                       \n\t"
+    "mov.d      $f8, $f12                       \n\t"
+    "mov.d      $f10, $f14                      \n\t"
+    "mov.d      $f12, $f16                      \n\t"
+    "mov.d      $f14, $f18                      \n\t"
+    "mov.d      $f16, $f20                      \n\t"
+    "mov.d      $f18, $f22                      \n\t"
+    "mov.d      $f20, $f24                      \n\t"
+    "mov.d      $f22, $f26                      \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+
+    "2:                                         \n\t"
+    FILTER_HV_W8($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                 $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9)
+    "dmtc1      $9, $f8                         \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f24, $f26, $f28, %[pSrc])
+    PTR_ADDU   "%[pDst],  %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24,
+                 $f26, $f28, $f30, $f0, $f2, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f28, $f30, $f0, $8)
+    FILTER_HV_W8($f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28,
+                 $f30, $f0, $f2, $f4, $f6, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f0, $f2, $f4, %[pSrc])
+    PTR_ADDU   "%[pDst],  %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0,
+                 $f2, $f4, $f6, $f8, $f10, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f4, $f6, $f8, $8)
+    FILTER_HV_W8($f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4,
+                 $f6, $f8, $f10, $f12, $f14, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f8, $f10, $f12, %[pSrc])
+    PTR_ADDU   "%[pDst],  %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8,
+                 $f10, $f12, $f14, $f16, $f18, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f12, $f14, $f16, $8)
+    FILTER_HV_W8($f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12,
+                 $f14, $f16, $f18, $f20, $f22, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], $10           \n\t"
+    MMI_LOAD_8P($f16, $f18, $f20, %[pSrc])
+    PTR_ADDU   "%[pDst],  %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16,
+                 $f18, $f20, $f22, $f24, $f26, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 3f                  \n\t"
+
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f20, $f22, $f24, $8)
+    "j          2b                              \n\t"
+
+    "3:                                         \n\t"
+    PTR_ADDIU  "%[iWidth], %[iWidth], -0x1      \n\t"
+    "beqz       %[iWidth], 4f                   \n\t"
+
+    "move       %[pSrc], $12                    \n\t"
+    "move       %[pDst], $13                    \n\t"
+    "move       %[iHeight], $14                 \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], $10           \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], 0x8           \n\t"
+    PTR_ADDIU  "%[pDst], %[pDst], 0x8           \n\t"
+    "j          1b                              \n\t"
+    "4:                                         \n\t"
+    : [pSrc]"+&r"((unsigned char *)pSrc), [pDst]"+&r"((unsigned char *)pDst),
+      [iWidth]"+&r"(iWidth), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride),  [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$9", "$10", "$12", "$13", "$14", "$f0", "$f2", "$f4",
+      "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
+      "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+//vertical filter to gain half sample, that is (0, 2) location in quarter sample
+static inline void McHorVer02Height5Or9Or17_mmi(const uint8_t* pSrc, int32_t iSrcStride,
+                                                uint8_t* pDst, int32_t iDstStride,
+                                                int32_t iWidth, int32_t iHeight) {
+  if (iWidth == 16 || iWidth == 8)
+    McHorVer02Height9Or17_mmi(pSrc, iSrcStride, pDst, iDstStride, iWidth, iHeight );
+  else
+    McHorVer02Height5_mmi (pSrc, iSrcStride, pDst, iDstStride, iWidth, iHeight);
+}
+
+static inline void McHorVer22HorFirst_mmi(const uint8_t *pSrc, int32_t iSrcStride,
+                                          uint8_t * pTap, int32_t iTapStride,
+                                          int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "dli        $8, 0x9                         \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    "bne        %[iWidth], $8, 2f               \n\t"
+
+    "1:                                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "mov.d      $f28, $f8                       \n\t"
+    "mov.d      $f30, $f10                      \n\t"
+    "paddh      $f28, $f28, $f12                \n\t"
+    "paddh      $f30, $f30, $f14                \n\t"
+    "mov.d      $f24, $f16                      \n\t"
+    "mov.d      $f26, $f18                      \n\t"
+    "paddh      $f24, $f24, $f20                \n\t"
+    "paddh      $f26, $f26, $f22                \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dmfc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f12                        \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "psubh      $f24, $f24, $f28                \n\t"
+    "psubh      $f26, $f26, $f30                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "gsswlc1    $f0, 0x3(%[pTap])               \n\t"
+    "gsswrc1    $f0, 0x0(%[pTap])               \n\t"
+
+    "gsldlc1    $f0, 0xd(%[pSrc])               \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f0, 0x6(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dmtc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+
+    "paddh      $f16, $f16, $f4                 \n\t"
+    "paddh      $f18, $f18, $f6                 \n\t"
+    "paddh      $f20, $f20, $f12                \n\t"
+    "paddh      $f22, $f22, $f14                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "psubh      $f20, $f20, $f16                \n\t"
+    "psubh      $f22, $f22, $f18                \n\t"
+    "paddh      $f8, $f8, $f0                   \n\t"
+    "paddh      $f10, $f10, $f2                 \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "gssdlc1    $f8, 0x9(%[pTap])               \n\t"
+    "gssdlc1    $f10, 0x11(%[pTap])             \n\t"
+    "gssdrc1    $f8, 0x2(%[pTap])               \n\t"
+    "gssdrc1    $f10, 0xa(%[pTap])              \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], %[iTapStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    "j          3f                              \n\t"
+
+    "2:                                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "dmtc1      $8, $f30                        \n\t"
+    "paddh      $f8, $f8, $f12                  \n\t"
+    "paddh      $f10, $f10, $f14                \n\t"
+    "paddh      $f16, $f16, $f20                \n\t"
+    "paddh      $f18, $f18, $f22                \n\t"
+    "psllh      $f16, $f16, $f30                \n\t"
+    "psllh      $f18, $f18, $f30                \n\t"
+    "psubh      $f16, $f16, $f8                 \n\t"
+    "psubh      $f18, $f18, $f10                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "psllh      $f16, $f16, $f30                \n\t"
+    "psllh      $f18, $f18, $f30                \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pTap])          \n\t"
+
+    "gsldlc1    $f0, 15(%[pSrc])                \n\t"
+    "gsldrc1    $f0, 8(%[pSrc])                 \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "gsldlc1    $f4, 0x14(%[pSrc])              \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "gsldrc1    $f4, 0xd(%[pSrc])               \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "gsldlc1    $f8, 0x10(%[pSrc])              \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "gsldrc1    $f8, 0x9(%[pSrc])               \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "gsldlc1    $f12, 0x13(%[pSrc])             \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "gsldrc1    $f12, 0xc(%[pSrc])              \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "gsldlc1    $f16, 0x11(%[pSrc])             \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "gsldrc1    $f16, 0xa(%[pSrc])              \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "gsldlc1    $f20, 0x12(%[pSrc])             \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "gsldrc1    $f20, 0xb(%[pSrc])              \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+
+    "mov.d      $f28, $f8                       \n\t"
+    "mov.d      $f30, $f10                      \n\t"
+    "paddh      $f28, $f28, $f12                \n\t"
+    "paddh      $f30, $f30, $f14                \n\t"
+    "mov.d      $f24, $f16                      \n\t"
+    "mov.d      $f26, $f18                      \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "paddh      $f24, $f24, $f20                \n\t"
+    "paddh      $f26, $f26, $f22                \n\t"
+    "dmfc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f12                        \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "psubh      $f24, $f24, $f28                \n\t"
+    "psubh      $f26, $f26, $f30                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "psllh      $f24, $f24, $f12                \n\t"
+    "psllh      $f26, $f26, $f12                \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f26                  \n\t"
+    "gsswlc1    $f0, 0x13(%[pTap])              \n\t"
+    "gsswrc1    $f0, 0x10(%[pTap])              \n\t"
+
+    "gsldlc1    $f0, 0x15(%[pSrc])              \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f0, 0xE(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dmtc1      $9, $f12                        \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+
+    "paddh      $f16, $f16, $f4                 \n\t"
+    "paddh      $f18, $f18, $f6                 \n\t"
+    "paddh      $f20, $f20, $f12                \n\t"
+    "paddh      $f22, $f22, $f14                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "psubh      $f20, $f20, $f16                \n\t"
+    "psubh      $f22, $f22, $f18                \n\t"
+    "paddh      $f8, $f8, $f0                   \n\t"
+    "paddh      $f10, $f10, $f2                 \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "psllh      $f20, $f20, $f24                \n\t"
+    "psllh      $f22, $f22, $f24                \n\t"
+    "paddh      $f8, $f8, $f20                  \n\t"
+    "paddh      $f10, $f10, $f22                \n\t"
+    "gssdlc1    $f8, 0x19(%[pTap])              \n\t"
+    "gssdlc1    $f10, 0x21(%[pTap])             \n\t"
+    "gssdrc1    $f8, 0x12(%[pTap])              \n\t"
+    "gssdrc1    $f10, 0x1a(%[pTap])             \n\t"
+
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], %[iTapStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 2b                  \n\t"
+    "3:                                         \n\t"
+    : [pSrc]"+&r"(pSrc), [pTap]"+&r"(pTap), [iWidth]"+&r"(iWidth),
+      [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride),  [iTapStride]"r"(iTapStride)
+    : "memory", "$8", "$9", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+static inline void McHorVer22Width8VerLastAlign_mmi(const uint8_t *pTap,
+                   int32_t iTapStride, uint8_t * pDst, int32_t iDstStride,
+                   int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "move       $10, %[pTap]                    \n\t"
+    "move       $11, %[pDst]                    \n\t"
+    "move       $12, %[iHeight]                 \n\t"
+    "dsrl       %[iWidth], 0x3                  \n\t"
+    PTR_ADDU   "$13, %[iTapStride], %[iTapStride] \n\t"
+    PTR_ADDU   "$14, %[iDstStride], %[iDstStride] \n\t"
+    "dli        $15, 0x0020002000200020         \n\t"
+
+    "4:                                         \n\t"
+    "gslqc1     $f2, $f0, 0x0(%[pTap])          \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f6, $f4, 0x0($8)               \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f10, $f8, 0x0(%[pTap])         \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f14, $f12, 0x0($8)             \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f18, $f16, 0x0(%[pTap])        \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f22, $f20, 0x0($8)             \n\t"
+
+    FILTER_VER_ALIGN($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                     $f22, $f24, $f26, $f28, $f30, %[pDst], $0, $8, $9, $15)
+
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f26, $f24, 0x0(%[pTap])        \n\t"
+    "mov.d      $f0, $f4                        \n\t"
+    "mov.d      $f2, $f6                        \n\t"
+    "mov.d      $f4, $f8                        \n\t"
+    "mov.d      $f6, $f10                       \n\t"
+    "mov.d      $f8, $f12                       \n\t"
+    "mov.d      $f10, $f14                      \n\t"
+    "mov.d      $f12, $f16                      \n\t"
+    "mov.d      $f14, $f18                      \n\t"
+    "mov.d      $f16, $f20                      \n\t"
+    "mov.d      $f18, $f22                      \n\t"
+    "mov.d      $f20, $f24                      \n\t"
+    "mov.d      $f22, $f26                      \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_SUBU   "%[pTap], %[pTap], %[iTapStride] \n\t"
+
+    "5:                                         \n\t"
+    FILTER_VER_ALIGN($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                     $f22, $f24, $f26, $f28, $f30, %[pDst], $0, $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f26, $f24, 0x0(%[pTap])        \n\t"
+
+    FILTER_VER_ALIGN($f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24,
+                     $f26, $f28, $f30, $f0, $f2, %[pDst], %[iDstStride], $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], $14           \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f30, $f28, 0x0($8)             \n\t"
+
+    FILTER_VER_ALIGN($f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28,
+                     $f30, $f0, $f2, $f4, $f6, %[pDst], $0, $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f2, $f0, 0x0(%[pTap])          \n\t"
+
+    FILTER_VER_ALIGN($f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0,
+                     $f2, $f4, $f6, $f8, $f10, %[pDst], %[iDstStride], $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], $14           \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f6, $f4, 0x0($8)               \n\t"
+
+    FILTER_VER_ALIGN($f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4,
+                     $f6, $f8, $f10, $f12, $f14, %[pDst], $0, $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f10, $f8, 0x0(%[pTap])         \n\t"
+
+    FILTER_VER_ALIGN($f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8,
+                     $f10, $f12, $f14, $f16, $f18, %[pDst], %[iDstStride], $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], $14           \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f14, $f12, 0x0($8)             \n\t"
+
+    FILTER_VER_ALIGN($f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12,
+                     $f14, $f16, $f18, $f20, $f22, %[pDst], $0, $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gslqc1     $f18, $f16, 0x0(%[pTap])        \n\t"
+
+    FILTER_VER_ALIGN($f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16,
+                     $f18, $f20, $f22, $f24, $f26, %[pDst], %[iDstStride], $8, $9, $15)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], $14           \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gslqc1     $f22, $f20, 0x0($8)             \n\t"
+    "j          5b                              \n\t"
+
+    "6:                                         \n\t"
+    PTR_ADDIU  "%[iWidth], %[iWidth], -0x1      \n\t"
+    "beqz       %[iWidth], 7f                   \n\t"
+    "move       %[pTap], $10                    \n\t"
+    "move       %[pDst], $11                    \n\t"
+    "move       %[iHeight], $12                 \n\t"
+    PTR_ADDIU  "%[pTap], %[pTap], 0x10          \n\t"
+    PTR_ADDIU  "%[pDst], %[pDst], 0x8           \n\t"
+    "j          4b                              \n\t"
+    "7:                                         \n\t"
+    : [pTap]"+&r"((unsigned char *)pTap), [pDst]"+&r"((unsigned char *)pDst),
+      [iWidth]"+&r"((int)iWidth), [iHeight]"+&r"((int)iHeight)
+    : [iTapStride]"r"((int)iTapStride), [iDstStride]"r"((int)iDstStride)
+    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0",
+      "$f2", "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18",
+      "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+static inline void McHorVer22Width8VerLastUnAlign_mmi(const uint8_t *pTap,
+                   int32_t iTapStride, uint8_t * pDst, int32_t iDstStride,
+                   int32_t iWidth, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "move       $10, %[pTap]                    \n\t"
+    "move       $11, %[pDst]                    \n\t"
+    "move       $12, %[iHeight]                 \n\t"
+    "dsrl       %[iWidth], 0x3                  \n\t"
+    PTR_ADDU   "$13, %[iTapStride], %[iTapStride] \n\t"
+    "dli        $14, 0x0020002000200020         \n\t"
+
+    "4:                                         \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f0, 0x7(%[pTap])               \n\t"
+    "gsldlc1    $f2, 0xF(%[pTap])               \n\t"
+    "gsldlc1    $f4, 0x7($8)                    \n\t"
+    "gsldlc1    $f6, 0xF($8)                    \n\t"
+    "gsldrc1    $f0, 0x0(%[pTap])               \n\t"
+    "gsldrc1    $f2, 0x8(%[pTap])               \n\t"
+    "gsldrc1    $f4, 0x0($8)                    \n\t"
+    "gsldrc1    $f6, 0x8($8)                    \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f8, 0x7(%[pTap])               \n\t"
+    "gsldlc1    $f10, 0xF(%[pTap])              \n\t"
+    "gsldlc1    $f12, 0x7($8)                   \n\t"
+    "gsldlc1    $f14, 0xF($8)                   \n\t"
+    "gsldrc1    $f8, 0x0(%[pTap])               \n\t"
+    "gsldrc1    $f10, 0x8(%[pTap])              \n\t"
+    "gsldrc1    $f12, 0x0($8)                   \n\t"
+    "gsldrc1    $f14, 0x8($8)                   \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f16, 0x7(%[pTap])              \n\t"
+    "gsldlc1    $f18, 0xF(%[pTap])              \n\t"
+    "gsldlc1    $f20, 0x7($8)                   \n\t"
+    "gsldlc1    $f22, 0xF($8)                   \n\t"
+    "gsldrc1    $f16, 0x0(%[pTap])              \n\t"
+    "gsldrc1    $f18, 0x8(%[pTap])              \n\t"
+    "gsldrc1    $f20, 0x0($8)                   \n\t"
+    "gsldrc1    $f22, 0x8($8)                   \n\t"
+
+    FILTER_VER_UNALIGN($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18,
+                       $f20, $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gsldlc1    $f24, 0x7(%[pTap])              \n\t"
+    "gsldlc1    $f26, 0xF(%[pTap])              \n\t"
+    "gsldrc1    $f24, 0x0(%[pTap])              \n\t"
+    "gsldrc1    $f26, 0x8(%[pTap])              \n\t"
+    "mov.d      $f0, $f4                        \n\t"
+    "mov.d      $f2, $f6                        \n\t"
+    "mov.d      $f4, $f8                        \n\t"
+    "mov.d      $f6, $f10                       \n\t"
+    "mov.d      $f8, $f12                       \n\t"
+    "mov.d      $f10, $f14                      \n\t"
+    "mov.d      $f12, $f16                      \n\t"
+    "mov.d      $f14, $f18                      \n\t"
+    "mov.d      $f16, $f20                      \n\t"
+    "mov.d      $f18, $f22                      \n\t"
+    "mov.d      $f20, $f24                      \n\t"
+    "mov.d      $f22, $f26                      \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_SUBU   "%[pTap], %[pTap], %[iTapStride] \n\t"
+
+    "5:                                         \n\t"
+    FILTER_VER_UNALIGN($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18,
+                       $f20, $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9, $14)
+
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gsldlc1    $f24, 0x7(%[pTap])              \n\t"
+    "gsldlc1    $f26, 0xF(%[pTap])              \n\t"
+    "gsldrc1    $f24, 0x0(%[pTap])              \n\t"
+    "gsldrc1    $f26, 0x8(%[pTap])              \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+
+    FILTER_VER_UNALIGN($f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22,
+                       $f24, $f26, $f28, $f30, $f0, $f2, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f28, 0x7($8)                   \n\t"
+    "gsldlc1    $f30, 0xF($8)                   \n\t"
+    "gsldrc1    $f28, 0x0($8)                   \n\t"
+    "gsldrc1    $f30, 0x8($8)                   \n\t"
+
+    FILTER_VER_UNALIGN($f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26,
+                       $f28, $f30, $f0, $f2, $f4, $f6, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gsldlc1    $f0, 0x7(%[pTap])               \n\t"
+    "gsldlc1    $f2, 0xF(%[pTap])               \n\t"
+    "gsldrc1    $f0, 0x0(%[pTap])               \n\t"
+    "gsldrc1    $f2, 0x8(%[pTap])               \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+
+    FILTER_VER_UNALIGN($f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28,
+                       $f30, $f0, $f2, $f4, $f6, $f8, $f10, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f4, 0x7($8)                    \n\t"
+    "gsldlc1    $f6, 0xF($8)                    \n\t"
+    "gsldrc1    $f4, 0x0($8)                    \n\t"
+    "gsldrc1    $f6, 0x8($8)                    \n\t"
+
+    FILTER_VER_UNALIGN($f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2,
+                       $f4, $f6, $f8, $f10, $f12, $f14, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gsldlc1    $f8, 0x7(%[pTap])               \n\t"
+    "gsldlc1    $f10, 0xF(%[pTap])              \n\t"
+    "gsldrc1    $f8, 0x0(%[pTap])               \n\t"
+    "gsldrc1    $f10, 0x8(%[pTap])              \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+
+    FILTER_VER_UNALIGN($f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6,
+                       $f8, $f10, $f12, $f14, $f16, $f18, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f12, 0x7($8)                   \n\t"
+    "gsldlc1    $f14, 0xF($8)                   \n\t"
+    "gsldrc1    $f12, 0x0($8)                   \n\t"
+    "gsldrc1    $f14, 0x8($8)                   \n\t"
+
+    FILTER_VER_UNALIGN($f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10,
+                       $f12, $f14, $f16, $f18, $f20, $f22, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pTap], %[pTap], $13           \n\t"
+    "gsldlc1    $f16, 0x7(%[pTap])              \n\t"
+    "gsldlc1    $f18, 0xF(%[pTap])              \n\t"
+    "gsldrc1    $f16, 0x0(%[pTap])              \n\t"
+    "gsldrc1    $f18, 0x8(%[pTap])              \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+
+    FILTER_VER_UNALIGN($f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14,
+                       $f16, $f18, $f20, $f22, $f24, $f26, %[pDst], $8, $9, $14)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 6f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pTap], %[iTapStride]      \n\t"
+    "gsldlc1    $f20, 0x7($8)                   \n\t"
+    "gsldlc1    $f22, 0xF($8)                   \n\t"
+    "gsldrc1    $f20, 0x0($8)                   \n\t"
+    "gsldrc1    $f22, 0x8($8)                   \n\t"
+    "j          5b                              \n\t"
+
+    "6:                                         \n\t"
+    PTR_ADDIU  "%[iWidth], %[iWidth], -0x1      \n\t"
+    "beqz       %[iWidth], 7f                   \n\t"
+    "move       %[pTap], $10                    \n\t"
+    "move       %[pDst], $11                    \n\t"
+    "move       %[iHeight], $12                 \n\t"
+    PTR_ADDIU  "%[pTap], %[pTap], 0x10          \n\t"
+    PTR_ADDIU  "%[pDst], %[pDst], 0x8           \n\t"
+    "j          4b                              \n\t"
+
+    "7:                                         \n\t"
+    : [pTap]"+&r"((unsigned char *)pTap), [pDst]"+&r"((unsigned char *)pDst),
+      [iWidth]"+&r"((int)iWidth), [iHeight]"+&r"((int)iHeight)
+    : [iTapStride]"r"((int)iTapStride), [iDstStride]"r"((int)iDstStride)
+    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$f0", "$f2",
+      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20",
+      "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+//horizontal and vertical filter to gain half sample, that is (2, 2) location in quarter sample
+static inline void McHorVer22Width5Or9Or17Height5Or9Or17_mmi(const uint8_t* pSrc,
+                   int32_t iSrcStride, uint8_t* pDst, int32_t iDstStride,
+                   int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_2D (int16_t, pTap, 22, 24, 16)
+
+  if (iWidth == 17 || iWidth == 9){
+    int32_t tmp1 = 2 * (iWidth - 8);
+    McHorVer22HorFirst_mmi(pSrc - 2, iSrcStride, (uint8_t*)pTap, 48, iWidth, iHeight + 5);
+
+    McHorVer22Width8VerLastAlign_mmi((uint8_t*)pTap,  48, pDst, iDstStride, iWidth - 1, iHeight);
+
+    McHorVer22Width8VerLastUnAlign_mmi((uint8_t*)pTap + tmp1,  48, pDst + iWidth - 8,
+                                        iDstStride, 8, iHeight);
+  } else {
+    int16_t iTmp[17 + 5];
+    int32_t i, j, k;
+
+    for (i = 0; i < iHeight; i++) {
+      for (j = 0; j < iWidth + 5; j++) {
+        iTmp[j] = FilterInput8bitWithStride_c (pSrc - 2 + j, iSrcStride);
+      }
+      for (k = 0; k < iWidth; k++) {
+        pDst[k] = WelsClip1 ((HorFilterInput16bit_c (&iTmp[k]) + 512) >> 10);
+      }
+      pSrc += iSrcStride;
+      pDst += iDstStride;
+    }
+  }
+}
+
+void McCopyWidthEq4_mmi(const uint8_t *pSrc, int iSrcStride,
+                        uint8_t *pDst, int iDstStride, int iHeight) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "1:                                         \n\t"
+    "lwl        $8, 0x3(%[pSrc])                \n\t"
+    "lwr        $8, 0x0(%[pSrc])                \n\t"
+    "swl        $8, 0x3(%[pDst])                \n\t"
+    "swr        $8, 0x0(%[pDst])                \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -1      \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8"
+  );
+}
+
+void McCopyWidthEq8_mmi(const uint8_t *pSrc, int iSrcStride,
+                        uint8_t *pDst, int iDstStride, int iHeight) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "1:                                         \n\t"
+    "ldl        $8, 0x7(%[pSrc])                \n\t"
+    "ldr        $8, 0x0(%[pSrc])                \n\t"
+    "sdl        $8, 0x7(%[pDst])                \n\t"
+    "sdr        $8, 0x0(%[pDst])                \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -1      \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8"
+  );
+}
+
+void McCopyWidthEq16_mmi(const uint8_t *pSrc, int iSrcStride,
+                         uint8_t *pDst, int iDstStride, int iHeight) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "1:                                         \n\t"
+    "ldl        $8, 0x7(%[pSrc])                \n\t"
+    "ldl        $9, 0xF(%[pSrc])                \n\t"
+    "ldr        $8, 0x0(%[pSrc])                \n\t"
+    "ldr        $9, 0x8(%[pSrc])                \n\t"
+    "sdl        $8, 0x7(%[pDst])                \n\t"
+    "sdl        $9, 0xF(%[pDst])                \n\t"
+    "sdr        $8, 0x0(%[pDst])                \n\t"
+    "sdr        $9, 0x8(%[pDst])                \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -1      \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$9"
+  );
+}
+
+static inline void McCopy_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                              int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  if (iWidth == 16)
+    McCopyWidthEq16_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else if (iWidth == 8)
+    McCopyWidthEq8_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else if (iWidth == 4)
+    McCopyWidthEq4_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else
+    McCopyWidthEq2_c (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+}
+
+void McChromaWidthEq4_mmi(const uint8_t *pSrc, int32_t iSrcStride, uint8_t *pDst,
+                          int32_t iDstStride, const uint8_t *pABCD, int32_t iHeight) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "gsldlc1    $f6, 0x7(%[pABCD])              \n\t"
+    "gsldrc1    $f6, 0x0(%[pABCD])              \n\t"
+    "xor        $f14, $f14, $f14                \n\t"
+    "punpcklbh  $f6, $f6, $f6                   \n\t"
+    "mov.d      $f8, $f6                        \n\t"
+    "punpcklhw  $f6, $f6, $f6                   \n\t"
+    "punpckhhw  $f8, $f8, $f8                   \n\t"
+    "mov.d      $f10, $f6                       \n\t"
+    "punpcklbh  $f6, $f6, $f14                  \n\t"
+    "punpckhbh  $f10, $f10, $f14                \n\t"
+
+    "mov.d      $f12, $f8                       \n\t"
+    "punpcklbh  $f8, $f8, $f14                  \n\t"
+    "punpckhbh  $f12, $f12, $f14                \n\t"
+    PTR_ADDU   "%[pABCD], %[pSrc], %[iSrcStride] \n\t"
+    "dli        $8, 0x6                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f2, 0x8(%[pSrc])               \n\t"
+    "dmtc1      $8, $f16                        \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f2, 0x1(%[pSrc])               \n\t"
+    "dli        $8, 0x0020002000200020          \n\t"
+    "punpcklbh  $f0, $f0, $f14                  \n\t"
+    "punpcklbh  $f2, $f2, $f14                  \n\t"
+
+    "dmtc1      $8, $f18                        \n\t"
+    "1:                                         \n\t"
+    "pmullh     $f0, $f0, $f6                   \n\t"
+    "pmullh     $f2, $f2, $f10                  \n\t"
+    "paddh      $f0, $f0, $f2                   \n\t"
+
+    "gsldlc1    $f2, 0x7(%[pABCD])              \n\t"
+    "gsldrc1    $f2, 0x0(%[pABCD])              \n\t"
+    "punpcklbh  $f2, $f2, $f14                  \n\t"
+    "mov.d      $f4, $f2                        \n\t"
+    "pmullh     $f2, $f2, $f8                   \n\t"
+    "paddh      $f0, $f0, $f2                   \n\t"
+    "gsldlc1    $f2, 0x8(%[pABCD])              \n\t"
+    "gsldrc1    $f2, 0x1(%[pABCD])              \n\t"
+    "punpcklbh  $f2, $f2, $f14                  \n\t"
+    "mov.d      $f14, $f2                       \n\t"
+    "pmullh     $f2, $f2, $f12                  \n\t"
+    "paddh      $f0, $f0, $f2                   \n\t"
+    "mov.d      $f2, $f14                       \n\t"
+    "paddh      $f0, $f0, $f18                  \n\t"
+    "psrlh      $f0, $f0, $f16                  \n\t"
+    "xor        $f14, $f14, $f14                \n\t"
+    "packushb   $f0, $f0, $f14                  \n\t"
+    "gsswlc1    $f0, 0x3(%[pDst])               \n\t"
+    "gsswrc1    $f0, 0x0(%[pDst])               \n\t"
+    "mov.d      $f0, $f4                        \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "%[pABCD], %[pABCD], %[iSrcStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -1      \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"((unsigned char *)pSrc), [pDst]"+&r"((unsigned char *)pDst),
+      [pABCD]"+&r"((unsigned char *)pABCD), [iHeight]"+&r"((int)iHeight)
+    : [iSrcStride]"r"((int)iSrcStride), [iDstStride]"r"((int)iDstStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18"
+  );
+}
+
+void McChromaWidthEq8_mmi(const uint8_t *pSrc, int32_t iSrcStride, uint8_t *pDst,
+                          int32_t iDstStride, const uint8_t *pABCD, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "gsldlc1    $f12, 0x7(%[pABCD])             \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldrc1    $f12, 0x0(%[pABCD])             \n\t"
+    "punpcklbh  $f12, $f12, $f12                \n\t"
+    "punpckhhw  $f14, $f12, $f12                \n\t"
+    "punpcklhw  $f12, $f12, $f12                \n\t"
+
+    "mov.d      $f16, $f14                      \n\t"
+    "punpckhwd  $f14, $f12, $f12                \n\t"
+    "punpcklwd  $f12, $f12, $f12                \n\t"
+    "punpckhwd  $f18, $f16, $f16                \n\t"
+    "punpcklwd  $f16, $f16, $f16                \n\t"
+    "mov.d      $f20, $f14                      \n\t"
+    "mov.d      $f24, $f18                      \n\t"
+
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpckhbh  $f26, $f24, $f28                \n\t"
+    "punpcklbh  $f24, $f24, $f28                \n\t"
+
+    PTR_ADDU   "%[pABCD], %[pSrc], %[iSrcStride] \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0x8(%[pSrc])               \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x1(%[pSrc])               \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "1:                                         \n\t"
+    "dli        $8, 0x20                        \n\t"
+    "dmtc1      $8, $f30                        \n\t"
+
+    "pmullh     $f0, $f0, $f12                  \n\t"
+    "pmullh     $f2, $f2, $f14                  \n\t"
+    "pmullh     $f4, $f4, $f20                  \n\t"
+    "pmullh     $f6, $f6, $f22                  \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+
+    "gsldlc1    $f4, 0x7(%[pABCD])              \n\t"
+    "gsldrc1    $f4, 0x0(%[pABCD])              \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "mov.d      $f8, $f4                        \n\t"
+    "mov.d      $f10, $f6                       \n\t"
+    "pmullh     $f4, $f4, $f16                  \n\t"
+    "pmullh     $f6, $f6, $f18                  \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+
+    "gsldlc1    $f4, 0x8(%[pABCD])              \n\t"
+    "gsldrc1    $f4, 0x1(%[pABCD])              \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "mov.d      $f28, $f4                       \n\t"
+    "mov.d      $f30, $f6                       \n\t"
+    "pmullh     $f4, $f4, $f24                  \n\t"
+    "pmullh     $f6, $f6, $f26                  \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "mov.d      $f4, $f28                       \n\t"
+    "mov.d      $f6, $f30                       \n\t"
+
+    "dli        $8, 0x0020002000200020          \n\t"
+    "dmfc1      $9, $f20                        \n\t"
+    "dmtc1      $8, $f20                        \n\t"
+    "dli        $8, 0x6                         \n\t"
+    "paddh      $f0, $f0, $f20                  \n\t"
+    "paddh      $f2, $f2, $f20                  \n\t"
+    "dmtc1      $8, $f20                        \n\t"
+    "psrlh      $f0, $f0, $f20                  \n\t"
+    "psrlh      $f2, $f2, $f20                  \n\t"
+
+    "xor        $f28, $f28, $f28                \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+
+    "mov.d      $f0, $f8                        \n\t"
+    "mov.d      $f2, $f10                       \n\t"
+    "dmtc1      $9, $f20                        \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "%[pABCD], %[pABCD], %[iSrcStride] \n\t"
+
+    PTR_ADDIU  "%[iHeight], %[iHeight], -1      \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [pABCD]"+&r"(pABCD),
+      [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$9", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void McChroma_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                  int32_t iDstStride, int16_t iMvX, int16_t iMvY,
+                  int32_t iWidth, int32_t iHeight) {
+  static const PMcChromaWidthExtFunc kpMcChromaWidthFuncs[2] = {
+    McChromaWidthEq4_mmi,
+    McChromaWidthEq8_mmi
+  };
+  const int32_t kiD8x = iMvX & 0x07;
+  const int32_t kiD8y = iMvY & 0x07;
+  if (kiD8x == 0 && kiD8y == 0) {
+    McCopy_mmi (pSrc, iSrcStride, pDst, iDstStride, iWidth, iHeight);
+    return;
+  }
+  if (iWidth != 2) {
+    kpMcChromaWidthFuncs[iWidth >> 3] (pSrc, iSrcStride, pDst, iDstStride,
+                                      g_kuiABCD[kiD8y][kiD8x], iHeight);
+  } else
+    McChromaWithFragMv_c (pSrc, iSrcStride, pDst, iDstStride, iMvX, iMvY,
+                          iWidth, iHeight);
+}
+
+void McHorVer20WidthEq8_mmi(const uint8_t *pSrc, int iSrcStride, uint8_t *pDst,
+                            int iDstStride, int iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], -0x2          \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "dli        $8, 0x0010001000100010          \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dmtc1      $8, $f26                        \n\t"
+    "dli        $8, 0x5                         \n\t"
+    "dmtc1      $8, $f30                        \n\t"
+    "1:                                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+    "paddh      $f8, $f8, $f12                  \n\t"
+    "paddh      $f10, $f10, $f14                \n\t"
+    "paddh      $f16, $f16, $f20                \n\t"
+    "paddh      $f18, $f18, $f22                \n\t"
+    "psllh      $f16, $f16, $f26                \n\t"
+    "psllh      $f18, $f18, $f26                \n\t"
+    "psubh      $f16, $f16, $f8                 \n\t"
+    "psubh      $f18, $f18, $f10                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "psllh      $f16, $f16, $f26                \n\t"
+    "psllh      $f18, $f18, $f26                \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f24                  \n\t"
+    "psrah      $f0, $f0, $f30                  \n\t"
+    "psrah      $f2, $f2, $f30                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void McHorVer20WidthEq16_mmi(const uint8_t *pSrc, int iSrcStride, uint8_t *pDst,
+                             int iDstStride, int iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], -0x2          \n\t"
+    "dli        $8, 0x0010001000100010          \n\t"
+    "dmtc1      $8, $f24                        \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dmtc1      $8, $f26                        \n\t"
+    "dli        $8, 0x5                         \n\t"
+    "dmtc1      $8, $f30                        \n\t"
+    "1:                                         \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+    "paddh      $f8, $f8, $f12                  \n\t"
+    "paddh      $f10, $f10, $f14                \n\t"
+    "paddh      $f16, $f16, $f20                \n\t"
+    "paddh      $f18, $f18, $f22                \n\t"
+    "psllh      $f16, $f16, $f26                \n\t"
+    "psllh      $f18, $f18, $f26                \n\t"
+    "psubh      $f16, $f16, $f8                 \n\t"
+    "psubh      $f18, $f18, $f10                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "psllh      $f16, $f16, $f26                \n\t"
+    "psllh      $f18, $f18, $f26                \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f24                  \n\t"
+    "psrah      $f0, $f0, $f30                  \n\t"
+    "psrah      $f2, $f2, $f30                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+    "gsldlc1    $f0, 0xF(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0x14(%[pSrc])              \n\t"
+    "gsldlc1    $f8, 0x10(%[pSrc])              \n\t"
+    "gsldlc1    $f12, 0x13(%[pSrc])             \n\t"
+    "gsldlc1    $f16, 0x11(%[pSrc])             \n\t"
+    "gsldlc1    $f20, 0x12(%[pSrc])             \n\t"
+    "gsldrc1    $f0, 0x8(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0xd(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x9(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0xc(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0xb(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+    "paddh      $f8, $f8, $f12                  \n\t"
+    "paddh      $f10, $f10, $f14                \n\t"
+    "paddh      $f16, $f16, $f20                \n\t"
+    "paddh      $f18, $f18, $f22                \n\t"
+    "psllh      $f16, $f16, $f26                \n\t"
+    "psllh      $f18, $f18, $f26                \n\t"
+    "psubh      $f16, $f16, $f8                 \n\t"
+    "psubh      $f18, $f18, $f10                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "psllh      $f16, $f16, $f26                \n\t"
+    "psllh      $f18, $f18, $f26                \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "paddh      $f0, $f0, $f24                  \n\t"
+    "paddh      $f2, $f2, $f24                  \n\t"
+    "psrah      $f0, $f0, $f30                  \n\t"
+    "psrah      $f2, $f2, $f30                  \n\t"
+    "packushb   $f0, $f0, $f2                   \n\t"
+    "gssdlc1    $f0, 0xF(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x8(%[pDst])               \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void McHorVer20WidthEq4_mmi(const uint8_t *pSrc, int iSrcStride, uint8_t *pDst,
+                            int iDstStride, int iHeight) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "1:                                         \n\t"
+    PTR_ADDIU  "%[pSrc], %[pSrc], -0x2          \n\t"
+    "xor        $f14, $f14, $f14                \n\t"
+    "dli        $8, 0x0010001000100010          \n\t"
+    "dmtc1      $8, $f12                        \n\t"
+    "1:                                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f2, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f6, 0xb(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x9(%[pSrc])               \n\t"
+    "gsldlc1    $f10, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f2, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f6, 0x4(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x2(%[pSrc])               \n\t"
+    "gsldrc1    $f10, 0x3(%[pSrc])              \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "punpcklbh  $f0, $f0, $f14                  \n\t"
+    "punpcklbh  $f2, $f2, $f14                  \n\t"
+    "punpcklbh  $f4, $f4, $f14                  \n\t"
+    "punpcklbh  $f6, $f6, $f14                  \n\t"
+    "punpcklbh  $f8, $f8, $f14                  \n\t"
+    "punpcklbh  $f10, $f10, $f14                \n\t"
+    "dmtc1      $8, $f16                        \n\t"
+    "paddh      $f4, $f4, $f6                   \n\t"
+    "paddh      $f8, $f8, $f10                  \n\t"
+    "psllh      $f8, $f8, $f16                  \n\t"
+    "psubh      $f8, $f8, $f4                   \n\t"
+    "paddh      $f0, $f0, $f2                   \n\t"
+    "paddh      $f0, $f0, $f8                   \n\t"
+    "dli        $8, 0x5                         \n\t"
+    "psllh      $f8, $f8, $f16                  \n\t"
+    "paddh      $f0, $f0, $f8                   \n\t"
+    "paddh      $f0, $f0, $f12                  \n\t"
+    "dmtc1      $8, $f16                        \n\t"
+    "psrah      $f0, $f0, $f16                  \n\t"
+    "packushb   $f0, $f0, $f14                  \n\t"
+    "gsswlc1    $f0, 0x3(%[pDst])               \n\t"
+    "gsswrc1    $f0, 0x0(%[pDst])               \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16"
+  );
+}
+
+static inline void McHorVer20_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  if (iWidth == 16)
+    McHorVer20WidthEq16_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else if (iWidth == 8)
+    McHorVer20WidthEq8_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else
+    McHorVer20WidthEq4_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+}
+
+void McHorVer02WidthEq8_mmi(const uint8_t *pSrc, int iSrcStride, uint8_t *pDst,
+                            int iDstStride, int iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    MMI_LOAD_8P($f0, $f2, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f4, $f6, $f28, $8)
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    MMI_LOAD_8P($f8, $f10, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f12, $f14, $f28, $8)
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    MMI_LOAD_8P($f16, $f18, $f28, %[pSrc])
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f20, $f22, $f28, $8)
+
+    "1:                                         \n\t"
+    FILTER_HV_W8($f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20,
+                 $f22, $f24, $f26, $f28, $f30, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    MMI_LOAD_8P($f24, $f26, $f28, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f4, $f6, $f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24,
+                 $f26, $f28, $f30, $f0, $f2, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f28, $f30, $f0, $8)
+    FILTER_HV_W8($f8, $f10, $f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28,
+                 $f30, $f0, $f2, $f4, $f6, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    MMI_LOAD_8P($f0, $f2, $f4, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f12, $f14, $f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0,
+                 $f2, $f4, $f6, $f8, $f10, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f4, $f6, $f8, $8)
+    FILTER_HV_W8($f16, $f18, $f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4,
+                 $f6, $f8, $f10, $f12, $f14, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    MMI_LOAD_8P($f8, $f10, $f12, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f20, $f22, $f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8,
+                 $f10, $f12, $f14, $f16, $f18, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f12, $f14, $f16, $8)
+    FILTER_HV_W8($f24, $f26, $f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12,
+                 $f14, $f16, $f18, $f20, $f22, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    MMI_LOAD_8P($f16, $f18, $f20, %[pSrc])
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    FILTER_HV_W8($f28, $f30, $f0, $f2, $f4, $f6, $f8, $f10, $f12, $f14, $f16,
+                 $f18, $f20, $f22, $f24, $f26, %[pDst], $8, $9)
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "beqz       %[iHeight], 2f                  \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDU   "$8, %[pSrc], %[iSrcStride]      \n\t"
+    MMI_LOAD_8P($f20, $f22, $f24, $8)
+    "j          1b                              \n\t"
+    "2:                                         \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride), [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$9", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+static inline void McHorVer02WidthEq16_mmi(const uint8_t* pSrc, int32_t iSrcStride,
+                   uint8_t* pDst, int32_t iDstStride, int32_t iHeight) {
+  McHorVer02WidthEq8_mmi (pSrc,     iSrcStride, pDst,     iDstStride, iHeight);
+  McHorVer02WidthEq8_mmi (&pSrc[8], iSrcStride, &pDst[8], iDstStride, iHeight);
+}
+
+static inline void McHorVer02_mmi(const uint8_t* pSrc, int32_t iSrcStride,
+                   uint8_t* pDst, int32_t iDstStride, int32_t iWidth,
+                   int32_t iHeight) {
+  if (iWidth == 16)
+    McHorVer02WidthEq16_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else if (iWidth == 8)
+    McHorVer02WidthEq8_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else
+    McHorVer02_c (pSrc, iSrcStride, pDst, iDstStride, 4, iHeight);
+}
+
+void McHorVer22Width8HorFirst_mmi(const uint8_t *pSrc, int16_t iSrcStride,
+     uint8_t *pDst, int32_t iDstStride, int32_t iHeight) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_SUBU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    "dli        $8, 0x2                         \n\t"
+    "dmtc1      $8, $f30                        \n\t"
+    "1:                                         \n\t"
+    "xor        $f28, $f28, $f28                \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrc])               \n\t"
+    "gsldlc1    $f4, 0xc(%[pSrc])               \n\t"
+    "gsldlc1    $f8, 0x8(%[pSrc])               \n\t"
+    "gsldlc1    $f12, 0xb(%[pSrc])              \n\t"
+    "gsldlc1    $f16, 0x9(%[pSrc])              \n\t"
+    "gsldlc1    $f20, 0xa(%[pSrc])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrc])               \n\t"
+    "gsldrc1    $f4, 0x5(%[pSrc])               \n\t"
+    "gsldrc1    $f8, 0x1(%[pSrc])               \n\t"
+    "gsldrc1    $f12, 0x4(%[pSrc])              \n\t"
+    "gsldrc1    $f16, 0x2(%[pSrc])              \n\t"
+    "gsldrc1    $f20, 0x3(%[pSrc])              \n\t"
+    "punpckhbh  $f2, $f0, $f28                  \n\t"
+    "punpckhbh  $f6, $f4, $f28                  \n\t"
+    "punpckhbh  $f10, $f8, $f28                 \n\t"
+    "punpckhbh  $f14, $f12, $f28                \n\t"
+    "punpckhbh  $f18, $f16, $f28                \n\t"
+    "punpckhbh  $f22, $f20, $f28                \n\t"
+    "punpcklbh  $f0, $f0, $f28                  \n\t"
+    "punpcklbh  $f4, $f4, $f28                  \n\t"
+    "punpcklbh  $f8, $f8, $f28                  \n\t"
+    "punpcklbh  $f12, $f12, $f28                \n\t"
+    "punpcklbh  $f16, $f16, $f28                \n\t"
+    "punpcklbh  $f20, $f20, $f28                \n\t"
+    "paddh      $f8, $f8, $f12                  \n\t"
+    "paddh      $f10, $f10, $f14                \n\t"
+    "paddh      $f16, $f16, $f20                \n\t"
+    "paddh      $f18, $f18, $f22                \n\t"
+    "psllh      $f16, $f16, $f30                \n\t"
+    "psllh      $f18, $f18, $f30                \n\t"
+    "psubh      $f16, $f16, $f8                 \n\t"
+    "psubh      $f18, $f18, $f10                \n\t"
+    "paddh      $f0, $f0, $f4                   \n\t"
+    "paddh      $f2, $f2, $f6                   \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "psllh      $f16, $f16, $f30                \n\t"
+    "psllh      $f18, $f18, $f30                \n\t"
+    "paddh      $f0, $f0, $f16                  \n\t"
+    "paddh      $f2, $f2, $f18                  \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdlc1    $f2, 0xF(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+    "gssdrc1    $f2, 0x8(%[pDst])               \n\t"
+    PTR_ADDU   "%[pSrc], %[pSrc], %[iSrcStride] \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride] \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pSrc]"+&r"(pSrc), [pDst]"+&r"(pDst), [iHeight]"+&r"(iHeight)
+    : [iSrcStride]"r"(iSrcStride),  [iDstStride]"r"(iDstStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+static inline void McHorVer22WidthEq8_mmi(const uint8_t* pSrc, int32_t iSrcStride,
+                   uint8_t* pDst, int32_t iDstStride, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_2D (int16_t, iTap, 21, 8, 16)
+  McHorVer22Width8HorFirst_mmi (pSrc - 2, iSrcStride, (uint8_t*)iTap, 16, iHeight + 5);
+  McHorVer22Width8VerLastAlign_mmi ((uint8_t*)iTap, 16, pDst, iDstStride, 8, iHeight);
+}
+
+static inline void McHorVer22WidthEq16_mmi(const uint8_t* pSrc, int32_t iSrcStride,
+                   uint8_t* pDst, int32_t iDstStride, int32_t iHeight) {
+  McHorVer22WidthEq8_mmi (pSrc,     iSrcStride, pDst,     iDstStride, iHeight);
+  McHorVer22WidthEq8_mmi (&pSrc[8], iSrcStride, &pDst[8], iDstStride, iHeight);
+}
+
+static inline void McHorVer22_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                   int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  if (iWidth == 16)
+    McHorVer22WidthEq16_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else if (iWidth == 8)
+    McHorVer22WidthEq8_mmi (pSrc, iSrcStride, pDst, iDstStride, iHeight);
+  else
+    McHorVer22_c (pSrc, iSrcStride, pDst, iDstStride, 4, iHeight);
+}
+
+void PixelAvgWidthEq4_mmi(uint8_t *pDst,  int iDstStride, const uint8_t *pSrcA,
+     int iSrcAStride, const uint8_t *pSrcB, int iSrcBStride, int iHeight ) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                    \n\t"
+    "1:                                            \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrcB])                 \n\t"
+    "gsldlc1    $f2, 0x7(%[pSrcA])                 \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrcB])                 \n\t"
+    "gsldrc1    $f2, 0x0(%[pSrcA])                 \n\t"
+    "pavgb      $f0, $f0, $f2                      \n\t"
+    "gsswlc1    $f0, 0x3(%[pDst])                  \n\t"
+    "gsswrc1    $f0, 0x0(%[pDst])                  \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x1       \n\t"
+    PTR_ADDU   "%[pDst], %[pDst], %[iDstStride]    \n\t"
+    PTR_ADDU   "%[pSrcA], %[pSrcA], %[iSrcAStride] \n\t"
+    PTR_ADDU   "%[pSrcB], %[pSrcB], %[iSrcBStride] \n\t"
+    "bnez       %[iHeight], 1b                     \n\t"
+    : [pDst]"+&r"((unsigned char *)pDst), [pSrcA]"+&r"((unsigned char *)pSrcA),
+      [pSrcB]"+&r"((unsigned char *)pSrcB), [iHeight]"+&r"((int)iHeight)
+    : [iDstStride]"r"((int)iDstStride), [iSrcAStride]"r"((int)iSrcAStride),
+      [iSrcBStride]"r"((int)iSrcBStride)
+    : "memory", "$8", "$9", "$10", "$f0", "$f2"
+  );
+}
+
+void PixelAvgWidthEq8_mmi(uint8_t *pDst,  int iDstStride, const uint8_t *pSrcA,
+     int iSrcAStride, const uint8_t *pSrcB, int iSrcBStride, int iHeight ) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "1:                                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrcA])              \n\t"
+    "gsldlc1    $f2, 0x7(%[pSrcB])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrcA])              \n\t"
+    "gsldrc1    $f2, 0x0(%[pSrcB])              \n\t"
+    "pavgb      $f0, $f0, $f2                   \n\t"
+    PTR_ADDU   "$8, %[pSrcA], %[iSrcAStride]    \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    PTR_ADDU   "$9, %[pSrcB], %[iSrcBStride]    \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+    "gsldlc1    $f0, 0x7($8)                    \n\t"
+    "gsldlc1    $f2, 0x7($9)                    \n\t"
+    "gsldrc1    $f0, 0x0($8)                    \n\t"
+    "gsldrc1    $f2, 0x0($9)                    \n\t"
+    "pavgb      $f0, $f0, $f2                   \n\t"
+    PTR_ADDU   "$10, %[pDst], %[iDstStride]     \n\t"
+    "gssdlc1    $f0, 0x7($10)                   \n\t"
+    PTR_ADDU   "%[pSrcA], $8, %[iSrcAStride]    \n\t"
+    "gssdrc1    $f0, 0x0($10)                   \n\t"
+    PTR_ADDU   "%[pSrcB], $9, %[iSrcBStride]    \n\t"
+    PTR_ADDU   "%[pDst], $10, %[iDstStride]     \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x2    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pDst]"+&r"((unsigned char *)pDst), [pSrcA]"+&r"((unsigned char *)pSrcA),
+      [pSrcB]"+&r"((unsigned char *)pSrcB), [iHeight]"+&r"((int)iHeight)
+    : [iDstStride]"r"((int)iDstStride), [iSrcAStride]"r"((int)iSrcAStride),
+      [iSrcBStride]"r"((int)iSrcBStride)
+    : "memory", "$8", "$9", "$10", "$f0", "$f2"
+  );
+}
+
+void PixelAvgWidthEq16_mmi(uint8_t *pDst, int iDstStride, const uint8_t *pSrcA,
+     int iSrcAStride, const uint8_t *pSrcB, int iSrcBStride, int iHeight ) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                 \n\t"
+    "1:                                         \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrcA])              \n\t"
+    "gsldlc1    $f2, 0xF(%[pSrcA])              \n\t"
+    "gsldlc1    $f4, 0x7(%[pSrcB])              \n\t"
+    "gsldlc1    $f6, 0xF(%[pSrcB])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrcA])              \n\t"
+    "gsldrc1    $f2, 0x8(%[pSrcA])              \n\t"
+    "gsldrc1    $f4, 0x0(%[pSrcB])              \n\t"
+    "gsldrc1    $f6, 0x8(%[pSrcB])              \n\t"
+    "pavgb      $f0, $f0, $f4                   \n\t"
+    "pavgb      $f2, $f2, $f6                   \n\t"
+    PTR_ADDU   "$8, %[pSrcA], %[iSrcAStride]    \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdlc1    $f2, 0xF(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+    "gssdrc1    $f2, 0x8(%[pDst])               \n\t"
+    PTR_ADDU   "$9, %[pSrcB], %[iSrcBStride]    \n\t"
+    "gsldlc1    $f0, 0x7($8)                    \n\t"
+    "gsldlc1    $f2, 0xF($8)                    \n\t"
+    "gsldrc1    $f0, 0x0($8)                    \n\t"
+    "gsldrc1    $f2, 0x8($8)                    \n\t"
+    PTR_ADDU   "$10, %[pDst], %[iDstStride]     \n\t"
+    "gsldlc1    $f4, 0x7($9)                    \n\t"
+    "gsldlc1    $f6, 0xF($9)                    \n\t"
+    "gsldrc1    $f4, 0x0($9)                    \n\t"
+    "gsldrc1    $f6, 0x8($9)                    \n\t"
+    "pavgb      $f0, $f0, $f4                   \n\t"
+    "pavgb      $f2, $f2, $f6                   \n\t"
+    "gssdlc1    $f0, 0x7($10)                   \n\t"
+    "gssdlc1    $f2, 0xF($10)                   \n\t"
+    "gssdrc1    $f0, 0x0($10)                   \n\t"
+    "gssdrc1    $f2, 0x8($10)                   \n\t"
+
+    PTR_ADDU   "%[pSrcA], $8, %[iSrcAStride]    \n\t"
+    PTR_ADDU   "%[pSrcB], $9, %[iSrcBStride]    \n\t"
+    PTR_ADDU   "%[pDst], $10, %[iDstStride]     \n\t"
+    "gsldlc1    $f0, 0x7(%[pSrcA])              \n\t"
+    "gsldlc1    $f2, 0xF(%[pSrcA])              \n\t"
+    "gsldlc1    $f4, 0x7(%[pSrcB])              \n\t"
+    "gsldlc1    $f6, 0xF(%[pSrcB])              \n\t"
+    "gsldrc1    $f0, 0x0(%[pSrcA])              \n\t"
+    "gsldrc1    $f2, 0x8(%[pSrcA])              \n\t"
+    "gsldrc1    $f4, 0x0(%[pSrcB])              \n\t"
+    "gsldrc1    $f6, 0x8(%[pSrcB])              \n\t"
+    "pavgb      $f0, $f0, $f4                   \n\t"
+    "pavgb      $f2, $f2, $f6                   \n\t"
+    PTR_ADDU   "$8, %[pSrcA], %[iSrcAStride]    \n\t"
+    PTR_ADDU   "$9, %[pSrcB], %[iSrcBStride]    \n\t"
+    "gssdlc1    $f0, 0x7(%[pDst])               \n\t"
+    "gssdlc1    $f2, 0xF(%[pDst])               \n\t"
+    "gssdrc1    $f0, 0x0(%[pDst])               \n\t"
+    "gssdrc1    $f2, 0x8(%[pDst])               \n\t"
+    "gsldlc1    $f0, 0x7($8)                    \n\t"
+    "gsldlc1    $f2, 0xF($8)                    \n\t"
+    "gsldlc1    $f4, 0x7($9)                    \n\t"
+    "gsldlc1    $f6, 0xF($9)                    \n\t"
+    "gsldrc1    $f0, 0x0($8)                    \n\t"
+    "gsldrc1    $f2, 0x8($8)                    \n\t"
+    "gsldrc1    $f4, 0x0($9)                    \n\t"
+    "gsldrc1    $f6, 0x8($9)                    \n\t"
+    PTR_ADDU   "$10, %[pDst], %[iDstStride]     \n\t"
+    "pavgb      $f0, $f0, $f4                   \n\t"
+    "pavgb      $f2, $f2, $f6                   \n\t"
+    "gssdlc1    $f0, 0x7($10)                   \n\t"
+    "gssdlc1    $f2, 0xF($10)                   \n\t"
+    "gssdrc1    $f0, 0x0($10)                   \n\t"
+    "gssdrc1    $f2, 0x8($10)                   \n\t"
+    PTR_ADDU   "%[pSrcA], $8, %[iSrcAStride]    \n\t"
+    PTR_ADDU   "%[pSrcB], $9, %[iSrcBStride]    \n\t"
+    PTR_ADDU   "%[pDst], $10, %[iDstStride]     \n\t"
+    PTR_ADDIU  "%[iHeight], %[iHeight], -0x4    \n\t"
+    "bnez       %[iHeight], 1b                  \n\t"
+    : [pDst]"+&r"((unsigned char *)pDst), [pSrcA]"+&r"((unsigned char *)pSrcA),
+      [pSrcB]"+&r"((unsigned char *)pSrcB), [iHeight]"+&r"((int)iHeight)
+    : [iDstStride]"r"((int)iDstStride), [iSrcAStride]"r"((int)iSrcAStride),
+      [iSrcBStride]"r"((int)iSrcBStride)
+    : "memory", "$8", "$9", "$10", "$f0", "$f2", "$f4", "$f6"
+  );
+}
+
+static inline void McHorVer01_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer02WidthEq16_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pSrc, iSrcStride, pTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer02WidthEq8_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pSrc, iSrcStride, pTmp, 16, iHeight);
+  } else {
+    McHorVer02_c (pSrc, iSrcStride, pTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pSrc, iSrcStride, pTmp, 16, iHeight);
+  }
+}
+
+static inline void McHorVer03_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer02WidthEq16_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pSrc + iSrcStride, iSrcStride, pTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer02WidthEq8_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pSrc + iSrcStride, iSrcStride, pTmp, 16, iHeight);
+  } else {
+    McHorVer02_c (pSrc, iSrcStride, pTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pSrc + iSrcStride, iSrcStride, pTmp, 16, iHeight);
+  }
+}
+
+static inline void McHorVer10_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pSrc, iSrcStride, pTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pSrc, iSrcStride, pTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc, iSrcStride, pTmp, 16, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pSrc, iSrcStride, pTmp, 16, iHeight);
+  }
+}
+
+static inline void McHorVer11_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pVerTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq16_mmi (pSrc, iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq8_mmi (pSrc, iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02_c (pSrc, iSrcStride, pVerTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  }
+}
+
+static inline void McHorVer12_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pVerTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pCtrTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer02WidthEq16_mmi (pSrc, iSrcStride, pVerTmp, 16, iHeight);
+    McHorVer22WidthEq16_mmi (pSrc, iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pVerTmp, 16, pCtrTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer02WidthEq8_mmi (pSrc, iSrcStride, pVerTmp, 16, iHeight);
+    McHorVer22WidthEq8_mmi (pSrc, iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pVerTmp, 16, pCtrTmp, 16, iHeight);
+  } else {
+    McHorVer02_c (pSrc, iSrcStride, pVerTmp, 16, 4, iHeight);
+    McHorVer22_c (pSrc, iSrcStride, pCtrTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pVerTmp, 16, pCtrTmp, 16, iHeight);
+  }
+}
+static inline void McHorVer13_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pVerTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq16_mmi (pSrc,            iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq8_mmi (pSrc,            iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02_c (pSrc,            iSrcStride, pVerTmp, 16, 4 , iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  }
+}
+static inline void McHorVer21_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pCtrTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer22WidthEq16_mmi (pSrc, iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pHorTmp, 16, pCtrTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer22WidthEq8_mmi (pSrc, iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pHorTmp, 16, pCtrTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer22_c (pSrc, iSrcStride, pCtrTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pHorTmp, 16, pCtrTmp, 16, iHeight);
+  }
+}
+
+static inline void McHorVer23_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pCtrTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer22WidthEq16_mmi (pSrc,            iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pHorTmp, 16, pCtrTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer22WidthEq8_mmi (pSrc,            iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pHorTmp, 16, pCtrTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer22_c (pSrc,            iSrcStride, pCtrTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pHorTmp, 16, pCtrTmp, 16, iHeight);
+  }
+}
+static inline void McHorVer30_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pSrc + 1, iSrcStride, pHorTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pSrc + 1, iSrcStride, pHorTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pSrc + 1, iSrcStride, pHorTmp, 16, iHeight);
+  }
+}
+static inline void McHorVer31_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pVerTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc,   iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq16_mmi (pSrc + 1, iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq8_mmi (pSrc + 1, iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02_c (pSrc + 1, iSrcStride, pVerTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  }
+}
+static inline void McHorVer32_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pVerTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pCtrTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer02WidthEq16_mmi (pSrc + 1, iSrcStride, pVerTmp, 16, iHeight);
+    McHorVer22WidthEq16_mmi (pSrc,   iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pVerTmp, 16, pCtrTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer02WidthEq8_mmi (pSrc + 1, iSrcStride, pVerTmp, 16, iHeight);
+    McHorVer22WidthEq8_mmi (pSrc,   iSrcStride, pCtrTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pVerTmp, 16, pCtrTmp, 16, iHeight);
+  } else {
+    McHorVer02_c (pSrc + 1, iSrcStride, pVerTmp, 16, 4, iHeight);
+    McHorVer22_c (pSrc,   iSrcStride, pCtrTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pVerTmp, 16, pCtrTmp, 16, iHeight);
+  }
+}
+static inline void McHorVer33_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst,
+                                  int32_t iDstStride, int32_t iWidth, int32_t iHeight) {
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pHorTmp, 256, 16);
+  ENFORCE_STACK_ALIGN_1D (uint8_t, pVerTmp, 256, 16);
+  if (iWidth == 16) {
+    McHorVer20WidthEq16_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq16_mmi (pSrc + 1,          iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq16_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else if (iWidth == 8) {
+    McHorVer20WidthEq8_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02WidthEq8_mmi (pSrc + 1,          iSrcStride, pVerTmp, 16, iHeight);
+    PixelAvgWidthEq8_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  } else {
+    McHorVer20WidthEq4_mmi (pSrc + iSrcStride, iSrcStride, pHorTmp, 16, iHeight);
+    McHorVer02_c (pSrc + 1,          iSrcStride, pVerTmp, 16, 4, iHeight);
+    PixelAvgWidthEq4_mmi (pDst, iDstStride, pHorTmp, 16, pVerTmp, 16, iHeight);
+  }
+}
+
+void McLuma_mmi(const uint8_t* pSrc, int32_t iSrcStride, uint8_t* pDst, int32_t iDstStride,
+                int16_t iMvX, int16_t iMvY, int32_t iWidth, int32_t iHeight) {
+  static const PWelsMcWidthHeightFunc pWelsMcFunc[4][4] = { //[x][y]
+    {McCopy_mmi,     McHorVer01_mmi, McHorVer02_mmi, McHorVer03_mmi},
+    {McHorVer10_mmi, McHorVer11_mmi, McHorVer12_mmi, McHorVer13_mmi},
+    {McHorVer20_mmi, McHorVer21_mmi, McHorVer22_mmi, McHorVer23_mmi},
+    {McHorVer30_mmi, McHorVer31_mmi, McHorVer32_mmi, McHorVer33_mmi},
+  };
+
+  pWelsMcFunc[iMvX & 0x03][iMvY & 0x03] (pSrc, iSrcStride, pDst, iDstStride, iWidth, iHeight);
+}
+
+void PixelAvg_mmi(uint8_t* pDst, int32_t iDstStride, const uint8_t* pSrcA, int32_t iSrcAStride,
+                  const uint8_t* pSrcB, int32_t iSrcBStride, int32_t iWidth, int32_t iHeight) {
+  static const PWelsSampleWidthAveragingFunc kpfFuncs[2] = {
+    PixelAvgWidthEq8_mmi,
+    PixelAvgWidthEq16_mmi
+  };
+  kpfFuncs[iWidth >> 4] (pDst, iDstStride, pSrcA, iSrcAStride, pSrcB, iSrcBStride, iHeight);
+}
+#endif//HAVE_MMI
 } // anon ns.
 
 void WelsCommon::InitMcFunc (SMcFunc* pMcFuncs, uint32_t uiCpuFlag) {
@@ -1716,4 +4252,15 @@
     pMcFuncs->pfLumaHalfpelCen  = McHorVer22Width5Or9Or17Height5Or9Or17_AArch64_neon;//iWidth+1/heigh+1
   }
 #endif
+
+#if defined(HAVE_MMI)
+  if (uiCpuFlag & WELS_CPU_MMI) {
+    pMcFuncs->pfLumaHalfpelHor  = McHorVer20Width5Or9Or17_mmi;
+    pMcFuncs->pfLumaHalfpelVer  = McHorVer02Height5Or9Or17_mmi;
+    pMcFuncs->pfLumaHalfpelCen  = McHorVer22Width5Or9Or17Height5Or9Or17_mmi;
+    pMcFuncs->pfSampleAveraging = PixelAvg_mmi;
+    pMcFuncs->pMcChromaFunc     = McChroma_mmi;
+    pMcFuncs->pMcLumaFunc       = McLuma_mmi;
+  }
+#endif//HAVE_MMI
 }
--- a/codec/decoder/core/inc/decode_mb_aux.h
+++ b/codec/decoder/core/inc/decode_mb_aux.h
@@ -63,6 +63,10 @@
 #endif
 
 
+#if defined(HAVE_MMI)
+void IdctResAddPred_mmi (uint8_t* pPred, const int32_t kiStride, int16_t* pRs);
+#endif//HAVE_MMI
+
 #if defined(__cplusplus)
 }
 #endif//__cplusplus
--- a/codec/decoder/core/inc/get_intra_predictor.h
+++ b/codec/decoder/core/inc/get_intra_predictor.h
@@ -166,6 +166,20 @@
 void WelsDecoderIChromaPredPlane_AArch64_neon (uint8_t* pPred, const int32_t kiStride);
 void WelsDecoderIChromaPredDcTop_AArch64_neon (uint8_t* pPred, const int32_t kiStride);
 #endif//HAVE_NEON_AARCH64
+
+#if defined(HAVE_MMI)
+void WelsDecoderI16x16LumaPredDc_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderI16x16LumaPredPlane_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderI16x16LumaPredH_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderI16x16LumaPredV_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderI16x16LumaPredDcTop_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderI16x16LumaPredDcNA_mmi (uint8_t* pPred, const int32_t kiStride);
+
+void WelsDecoderIChromaPredDcTop_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderIChromaPredPlane_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderIChromaPredDc_mmi (uint8_t* pPred, const int32_t kiStride);
+void WelsDecoderI4x4LumaPredH_mmi (uint8_t* pPred, const int32_t kiStride);
+#endif//HAVE_MMI
 #if defined(__cplusplus)
 }
 #endif//__cplusplus
--- /dev/null
+++ b/codec/decoder/core/mips/dct_mmi.c
@@ -1,0 +1,786 @@
+/*!
+ * \copy
+ *     Copyright (c)  2009-2018, Cisco Systems
+ *     All rights reserved.
+ *
+ *     Redistribution and use in source and binary forms, with or without
+ *     modification, are permitted provided that the following conditions
+ *     are met:
+ *
+ *        * Redistributions of source code must retain the above copyright
+ *          notice, this list of conditions and the following disclaimer.
+ *
+ *        * Redistributions in binary form must reproduce the above copyright
+ *          notice, this list of conditions and the following disclaimer in
+ *          the documentation and/or other materials provided with the
+ *          distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *     POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * \file    dct_mmi.c
+ *
+ * \brief   Loongson optimization
+ *
+ * \date    17/07/2018 Created
+ *
+ *************************************************************************************
+ */
+#include <stdint.h>
+#include "asmdefs_mmi.h"
+
+#define LOAD_2_LEFT_AND_ADD                                   \
+  PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t" \
+  "lbu        $9, -0x1(%[pPred])                        \n\t" \
+  PTR_ADDU   "$8, $8, $9                                \n\t" \
+  PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t" \
+  "lbu        $9, -0x1(%[pPred])                        \n\t" \
+  PTR_ADDU   "$8, $8, $9                                \n\t"
+
+unsigned char mmi_dc_0x80[16] __attribute__((aligned(16))) = {
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
+
+short mmi_wd_0x02[8] __attribute__((aligned(16))) = {2, 2, 2, 2, 2, 2, 2, 2};
+short mmi_plane_inc_minus[8]__attribute__((aligned(16))) = {-7, -6, -5, -4, -3, -2, -1, 0};
+short mmi_plane_inc[8]__attribute__((aligned(16))) = {1, 2, 3, 4, 5, 6, 7, 8};
+short mmi_plane_dec[8]__attribute__((aligned(16))) = {8, 7, 6, 5, 4, 3, 2, 1};
+
+short mmi_plane_inc_c[4]__attribute__((aligned(16))) = {1, 2, 3, 4};
+short mmi_plane_dec_c[4]__attribute__((aligned(16))) = {4, 3, 2, 1};
+short mmi_plane_mul_b_c[8]__attribute__((aligned(16))) = {-3, -2, -1, 0, 1, 2, 3, 4};
+
+unsigned char mmi_01bytes[16]__attribute__((aligned(16))) = {1, 1, 1, 1, 1, 1, 1, 1,
+                                                             1, 1, 1, 1, 1, 1, 1, 1};
+
+void IdctResAddPred_mmi(uint8_t *pPred, const int32_t kiStride, int16_t *pRs) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "dli        $8, 0x1                                   \n\t"
+    "gsldxc1    $f0, 0x0(%[pRs], $0)                      \n\t"
+    "gsldxc1    $f2, 0x8(%[pRs], $0)                      \n\t"
+    "gsldxc1    $f4, 0x10(%[pRs], $0)                     \n\t"
+    "gsldxc1    $f6, 0x18(%[pRs], $0)                     \n\t"
+    "dmtc1      $8, $f14                                  \n\t"
+
+    MMI_Trans4x4H_SINGLE($f0, $f2, $f4, $f6, $f8)
+    MMI_IDCT_SINGLE($f2, $f4, $f6, $f8, $f0, $f12, $f14)
+    MMI_Trans4x4H_SINGLE($f2, $f6, $f0, $f8, $f4)
+    MMI_IDCT_SINGLE($f6, $f0, $f8, $f4, $f2, $f12, $f14)
+
+    "dli        $8, 0x20                                  \n\t"
+    "xor        $f14, $f14, $f14                          \n\t"
+    "dmtc1      $8, $f12                                  \n\t"
+    "pshufh     $f12, $f12, $f14                          \n\t"
+    "dli        $8, 0x6                                   \n\t"
+    "dmtc1      $8, $f16                                  \n\t"
+
+    MMI_StoreDiff4P_SINGLE($f6, $f0, $f12, $f14, %[pPred], %[pPred], $f16)
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    MMI_StoreDiff4P_SINGLE($f8, $f0, $f12, $f14, %[pPred], %[pPred], $f16)
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    MMI_StoreDiff4P_SINGLE($f2, $f0, $f12, $f14, %[pPred], %[pPred], $f16)
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    MMI_StoreDiff4P_SINGLE($f4, $f0, $f12, $f14, %[pPred], %[pPred], $f16)
+    : [pPred]"+&r"((unsigned char *)pPred)
+    : [pRs]"r"((unsigned char *)pRs), [kiStride]"r"((int)kiStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", "$f12",
+      "$f14", "$f16"
+  );
+}
+
+void WelsDecoderI16x16LumaPredDc_mmi(uint8_t *pPred, const int32_t kiStride) {
+  __asm__ volatile(
+    ".set       arch=loongson3a                           \n\t"
+    "dli        $8, 0x5                                   \n\t"
+    "gsldxc1    $f10, 0x0(%[mmi_01bytes], $0)             \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+
+    "move       $10, %[pPred]                             \n\t"
+    PTR_SUBU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gslqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    "xor        $f4, $f4, $f4                             \n\t"
+    "pasubub    $f0, $f0, $f4                             \n\t"
+    "pasubub    $f2, $f2, $f4                             \n\t"
+    "biadd      $f0, $f0                                  \n\t"
+    "biadd      $f2, $f2                                  \n\t"
+    "paddh      $f0, $f0, $f2                             \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $8, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+
+    LOAD_2_LEFT_AND_ADD
+    LOAD_2_LEFT_AND_ADD
+    LOAD_2_LEFT_AND_ADD
+    LOAD_2_LEFT_AND_ADD
+    LOAD_2_LEFT_AND_ADD
+    LOAD_2_LEFT_AND_ADD
+    LOAD_2_LEFT_AND_ADD
+
+    PTR_ADDIU  "$8, $8, 0x10                              \n\t"
+    "dmtc1      $8, $f4                                   \n\t"
+    "paddh      $f0, $f0, $f4                             \n\t"
+    "psrlw      $f0, $f0, $f8                             \n\t"
+    "pmuluw     $f0, $f0, $f10                            \n\t"
+    "punpcklwd  $f0, $f0, $f0                             \n\t"
+    "mov.d      $f2, $f0                                  \n\t"
+
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssqc1     $f2, $f0, 0x0($10)                        \n\t"
+    : [pPred] "+&r"((unsigned char *)pPred)
+    : [kiStride] "r"((int)kiStride),
+      [mmi_01bytes] "r"((unsigned char *)mmi_01bytes)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10"
+  );
+}
+
+void WelsDecoderI16x16LumaPredPlane_mmi(uint8_t *pPred, const int32_t kiStride) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "move       $10, %[pPred]                             \n\t"
+    PTR_ADDIU  "%[pPred], %[pPred], -0x1                  \n\t"
+    PTR_SUBU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+
+    "gsldlc1    $f0, 0x7(%[pPred])                        \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "gsldrc1    $f0, 0x0(%[pPred])                        \n\t"
+    "gslqc1     $f22, $f20, 0x0(%[mmi_plane_dec])         \n\t"
+    "punpckhbh  $f2, $f0, $f28                            \n\t"
+    "punpcklbh  $f0, $f0, $f28                            \n\t"
+    "pmullh     $f0, $f0, $f20                            \n\t"
+    "gsldlc1    $f4, 0x10(%[pPred])                       \n\t"
+    "pmullh     $f2, $f2, $f22                            \n\t"
+    "gsldrc1    $f4, 0x9(%[pPred])                        \n\t"
+    "gslqc1     $f26, $f24, 0x0(%[mmi_plane_inc])         \n\t"
+    "punpckhbh  $f6, $f4, $f28                            \n\t"
+    "punpcklbh  $f4, $f4, $f28                            \n\t"
+    "pmullh     $f4, $f4, $f24                            \n\t"
+    "pmullh     $f6, $f6, $f26                            \n\t"
+    "psubh      $f4, $f4, $f0                             \n\t"
+    "psubh      $f6, $f6, $f2                             \n\t"
+
+    SUMH_HORIZON($f4, $f6, $f0, $f2, $f8)
+    "dmfc1      $8, $f4                                   \n\t"
+    "seh        $8, $8                                    \n\t"
+    "mul        $8, $8, 0x5                               \n\t"
+    PTR_ADDIU  "$8, $8, 0x20                              \n\t"
+    "sra        $8, $8, 0x6                               \n\t"
+    MMI_Copy8Times($f4, $f6, $f28, $8)
+
+    "lbu        $9, 0x10(%[pPred])                        \n\t"
+    PTR_ADDIU  "%[pPred], %[pPred], -0x3                  \n\t"
+    LOAD_COLUMN($f0, $f2, $f8, $f10, $f12, $f14, $f16, $f18, %[pPred],
+                %[kiStride], $11)
+
+    PTR_ADDIU  "%[pPred], %[pPred], 0x3                   \n\t"
+    "dsll       $11, %[kiStride], 0x3                     \n\t"
+    PTR_ADDU   "$11, $11, %[pPred]                        \n\t"
+    "lbu        $8, 0x0($11)                              \n\t"
+    PTR_ADDU   "$9, $9, $8                                \n\t"
+    "dsll       $9, $9, 0x4                               \n\t"
+
+    PTR_ADDIU  "%[pPred], %[pPred], -0x3                  \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    LOAD_COLUMN($f28, $f30, $f8, $f10, $f12, $f14, $f16, $f18, %[pPred],
+                %[kiStride], $11)
+
+    "xor        $f16, $f16, $f16                          \n\t"
+    "punpcklbh  $f0, $f2, $f16                            \n\t"
+    "punpckhbh  $f2, $f2, $f16                            \n\t"
+    "pmullh     $f0, $f0, $f20                            \n\t"
+    "pmullh     $f2, $f2, $f22                            \n\t"
+    "punpcklbh  $f28, $f30, $f16                          \n\t"
+    "punpckhbh  $f30, $f30, $f16                          \n\t"
+    "pmullh     $f28, $f28, $f24                          \n\t"
+    "pmullh     $f30, $f30, $f26                          \n\t"
+    "psubh      $f28, $f28, $f0                           \n\t"
+    "psubh      $f30, $f30, $f2                           \n\t"
+
+    "xor        $f8, $f8, $f8                             \n\t"
+
+    SUMH_HORIZON($f28, $f30, $f0, $f2, $f8)
+    "dmfc1      $8, $f28                                  \n\t"
+    "seh        $8, $8                                    \n\t"
+
+    "mul        $8, $8, 0x5                               \n\t"
+    PTR_ADDIU  "$8, $8, 0x20                              \n\t"
+    "sra        $8, $8, 0x6                               \n\t"
+    MMI_Copy8Times($f16, $f18, $f8, $8)
+
+    "move       %[pPred], $10                             \n\t"
+    PTR_ADDIU  "$9, $9, 0x10                              \n\t"
+    "mul        $8, $8, -0x7                              \n\t"
+    PTR_ADDU   "$9, $9, $8                                \n\t"
+    MMI_Copy8Times($f0, $f2, $f8, $9)
+
+    "xor        $8, $8, $8                                \n\t"
+    "gslqc1     $f22, $f20, 0x0(%[mmi_plane_inc_minus])   \n\t"
+
+    "dli        $11, 0x5                                  \n\t"
+    "dmtc1      $11, $f30                                 \n\t"
+    "1:                                                   \n\t"
+    "pmullh     $f8, $f4, $f20                            \n\t"
+    "pmullh     $f10, $f6, $f22                           \n\t"
+    "paddh      $f8, $f8, $f0                             \n\t"
+    "paddh      $f10, $f10, $f2                           \n\t"
+    "psrah      $f8, $f8, $f30                            \n\t"
+    "psrah      $f10, $f10, $f30                          \n\t"
+    "pmullh     $f12, $f4, $f24                           \n\t"
+    "pmullh     $f14, $f6, $f26                           \n\t"
+    "paddh      $f12, $f12, $f0                           \n\t"
+    "paddh      $f14, $f14, $f2                           \n\t"
+    "psrah      $f12, $f12, $f30                          \n\t"
+    "psrah      $f14, $f14, $f30                          \n\t"
+    "packushb   $f8, $f8, $f10                            \n\t"
+    "packushb   $f10, $f12, $f14                          \n\t"
+    "gssqc1     $f10, $f8, 0x0(%[pPred])                  \n\t"
+    "paddh      $f0, $f0, $f16                            \n\t"
+    "paddh      $f2, $f2, $f18                            \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    PTR_ADDIU  "$8, $8, 0x1                               \n\t"
+    PTR_ADDIU  "$11, $8, -0x10                            \n\t"
+    "bnez       $11, 1b                                   \n\t"
+    "nop                                                  \n\t"
+    : [pPred]"+&r"((unsigned char *)pPred)
+    : [kiStride]"r"((int)kiStride), [mmi_plane_inc_minus]"r"(mmi_plane_inc_minus),
+      [mmi_plane_inc]"r"(mmi_plane_inc), [mmi_plane_dec]"r"(mmi_plane_dec)
+    : "memory", "$8", "$9", "$10", "$11", "$f0", "$f2", "$f4", "$f6", "$f8",
+      "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26",
+      "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+#define COPY_16_TIMES(r0, f0, f2, f4, f6, f8)                 \
+  "gslqc1     "#f2", "#f0", -0x10("#r0")                \n\t" \
+  "dsrl       "#f0", "#f2", "#f4"                       \n\t" \
+  "pmuluw     "#f0", "#f0", "#f6"                       \n\t" \
+  "punpcklwd  "#f0", "#f0", "#f0"                       \n\t" \
+  "mov.d      "#f2", "#f0"                              \n\t"
+
+#define MMI_PRED_H_16X16_TWO_LINE_DEC                         \
+  PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t" \
+  COPY_16_TIMES(%[pPred], $f0, $f2, $f4, $f6, $f8)            \
+  "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t" \
+  PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t" \
+  COPY_16_TIMES(%[pPred], $f0, $f2, $f4, $f6, $f8)            \
+  "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+
+void WelsDecoderI16x16LumaPredH_mmi(uint8_t *pPred, const int32_t kiStride) {
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "dli        $8, 56                                    \n\t"
+    "dmtc1      $8, $f4                                   \n\t"
+    "gsldxc1    $f6, 0x0(%[mmi_01bytes], $0)              \n\t"
+    "xor        $f8, $f8, $f8                             \n\t"
+
+    COPY_16_TIMES(%[pPred], $f0, $f2, $f4, $f6, $f8)
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    COPY_16_TIMES(%[pPred], $f0, $f2, $f4, $f6, $f8)
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    MMI_PRED_H_16X16_TWO_LINE_DEC
+    : [pPred]"+&r"((unsigned char *)pPred)
+    : [kiStride]"r"((int)kiStride),
+      [mmi_01bytes]"r"((unsigned char *)mmi_01bytes)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6", "$f8"
+  );
+}
+
+void WelsDecoderI16x16LumaPredV_mmi(uint8_t *pPred, const int32_t kiStride) {
+  __asm__ volatile(
+    ".set       arch=loongson3a                           \n\t"
+    PTR_SUBU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gslqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    : [pPred] "+&r"((unsigned char *)pPred)
+    : [kiStride] "r"((int)kiStride)
+    : "memory", "$f0", "$f2"
+  );
+}
+
+void WelsDecoderI16x16LumaPredDcTop_mmi(uint8_t *pPred, const int32_t kiStride) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    PTR_SUBU   "$8, %[pPred], %[kiStride]                 \n\t"
+    "gslqc1     $f2, $f0, 0x0($8)                         \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "pasubub    $f0, $f0, $f28                            \n\t"
+    "pasubub    $f2, $f2, $f28                            \n\t"
+    "biadd      $f0, $f0                                  \n\t"
+    "biadd      $f2, $f2                                  \n\t"
+    "paddh      $f0, $f0, $f2                             \n\t"
+    "dmfc1      $8, $f0                                   \n\t"
+
+    PTR_ADDIU  "$8, $8, 0x8                               \n\t"
+    "dsra       $8, $8, 0x4                               \n\t"
+    MMI_Copy16Times($f4, $f6, $f28, $8)
+    "mov.d      $f0, $f4                                  \n\t"
+    "mov.d      $f2, $f6                                  \n\t"
+
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    : [pPred]"+&r"((unsigned char *)pPred)
+    : [kiStride]"r"((int)kiStride)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6"
+  );
+  RECOVER_REG;
+}
+
+void WelsDecoderI16x16LumaPredDcNA_mmi(uint8_t *pPred, const int32_t kiStride) {
+  __asm__ volatile(
+    ".set       arch=loongson3a                           \n\t"
+    "gslqc1     $f2, $f0, 0x0(%[mmi_dc_0x80])             \n\t"
+    "mov.d      $f4, $f0                                  \n\t"
+    "mov.d      $f6, $f2                                  \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f2, $f0, 0x0(%[pPred])                   \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[pPred])                   \n\t"
+    : [pPred] "+&r"((unsigned char *)pPred)
+    : [kiStride] "r"((int)kiStride), [mmi_dc_0x80] "r"(mmi_dc_0x80)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6"
+  );
+}
+
+void WelsDecoderIChromaPredPlane_mmi(uint8_t *pPred, const int32_t kiStride) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "move       $10, %[pPred]                             \n\t"
+    PTR_ADDIU  "%[pPred], %[pPred], -0x1                  \n\t"
+    PTR_SUBU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+
+    "gsldlc1    $f0, 0x7(%[pPred])                        \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "gsldrc1    $f0, 0x0(%[pPred])                        \n\t"
+    "gsldxc1    $f20, 0x0(%[mmi_plane_dec_c], $0)         \n\t"
+    "punpcklbh  $f0, $f0, $f28                            \n\t"
+    "gsldlc1    $f4, 0xc(%[pPred])                        \n\t"
+    "pmullh     $f0, $f0, $f20                            \n\t"
+    "gsldrc1    $f4, 0x5(%[pPred])                        \n\t"
+    "gsldxc1    $f24, 0x0(%[mmi_plane_inc_c], $0)         \n\t"
+    "punpcklbh  $f4, $f4, $f28                            \n\t"
+    "pmullh     $f4, $f4, $f24                            \n\t"
+    "psubh      $f4, $f4, $f0                             \n\t"
+
+    "xor        $f6, $f6, $f6                             \n\t"
+    "xor        $f8, $f8, $f8                             \n\t"
+    SUMH_HORIZON($f4, $f6, $f0, $f2, $f8)
+    "dmfc1      $8, $f4                                   \n\t"
+    "seh        $8, $8                                    \n\t"
+    "mul        $8, $8, 0x11                              \n\t"
+    PTR_ADDIU  "$8, $8, 0x10                              \n\t"
+    "sra        $8, $8, 0x5                               \n\t"
+    MMI_Copy8Times($f4, $f6, $f8, $8)
+
+    "lbu        $9, 0x8(%[pPred])                         \n\t"
+    PTR_ADDIU  "%[pPred], %[pPred], -0x3                  \n\t"
+    LOAD_COLUMN_C($f0, $f8, $f12, $f16, %[pPred], %[kiStride], $11)
+
+    PTR_ADDIU  "%[pPred], %[pPred], 0x3                   \n\t"
+    "dsll       $11, %[kiStride], 0x2                     \n\t"
+    PTR_ADDU   "$11, $11, %[pPred]                        \n\t"
+    "lbu        $8, 0x0($11)                              \n\t"
+    PTR_ADDU   "$9, $9, $8                                \n\t"
+    "dsll       $9, $9, 0x4                               \n\t"
+
+    PTR_ADDIU  "%[pPred], %[pPred], -0x3                  \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    LOAD_COLUMN_C($f28, $f8, $f12, $f16, %[pPred], %[kiStride], $11)
+    "xor        $f16, $f16, $f16                          \n\t"
+    "punpckhbh  $f0, $f0, $f16                            \n\t"
+    "pmullh     $f0, $f0, $f20                            \n\t"
+    "punpckhbh  $f28, $f28, $f16                          \n\t"
+    "pmullh     $f28, $f28, $f24                          \n\t"
+    "psubh      $f28, $f28, $f0                           \n\t"
+
+    "xor        $f30, $f30, $f30                          \n\t"
+    "xor        $f8, $f8, $f8                             \n\t"
+    SUMH_HORIZON($f28, $f30, $f0, $f2, $f8)
+    "dmfc1      $8, $f28                                  \n\t"
+    "seh        $8, $8                                    \n\t"
+
+    "mul        $8, $8, 0x11                              \n\t"
+    PTR_ADDIU  "$8, $8, 0x10                              \n\t"
+    "sra        $8, $8, 0x5                               \n\t"
+    MMI_Copy8Times($f16, $f18, $f8, $8)
+
+    "move       %[pPred], $10                             \n\t"
+    PTR_ADDIU  "$9, $9, 0x10                              \n\t"
+    "mul        $8, $8, -0x3                              \n\t"
+    PTR_ADDU   "$9, $9, $8                                \n\t"
+    MMI_Copy8Times($f0, $f2, $f8, $9)
+
+    "xor        $8, $8, $8                                \n\t"
+    "gslqc1     $f22, $f20, 0x0(%[mmi_plane_mul_b_c])     \n\t"
+
+    "dli        $11, 0x5                                  \n\t"
+    "dmtc1      $11, $f30                                 \n\t"
+    "1:                                                   \n\t"
+    "pmullh     $f8, $f4, $f20                            \n\t"
+    "pmullh     $f10, $f6, $f22                           \n\t"
+    "paddh      $f8, $f8, $f0                             \n\t"
+    "paddh      $f10, $f10, $f2                           \n\t"
+    "psrah      $f8, $f8, $f30                            \n\t"
+    "psrah      $f10, $f10, $f30                          \n\t"
+    "packushb   $f8, $f8, $f10                            \n\t"
+    "gssdxc1    $f8, 0x0(%[pPred], $0)                    \n\t"
+    "paddh      $f0, $f0, $f16                            \n\t"
+    "paddh      $f2, $f2, $f18                            \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    PTR_ADDIU  "$8, $8, 0x1                               \n\t"
+    PTR_ADDIU  "$11, $8, -0x8                             \n\t"
+    "bnez       $11, 1b                                   \n\t"
+    "nop                                                  \n\t"
+    : [pPred]"+&r"((unsigned char *)pPred)
+    : [kiStride]"r"((int)kiStride), [mmi_plane_mul_b_c]"r"(mmi_plane_mul_b_c),
+      [mmi_plane_inc_c]"r"(mmi_plane_inc_c), [mmi_plane_dec_c]"r"(mmi_plane_dec_c)
+    : "memory", "$8", "$9", "$10", "$11", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10",
+      "$f12", "$f14", "$f16", "$f18", "$f20", "$f22", "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void WelsDecoderIChromaPredDc_mmi(uint8_t *pPred, const int32_t kiStride) {
+  __asm__ volatile(
+    ".set       arch=loongson3a                           \n\t"
+    "move       $10, %[pPred]                             \n\t"
+
+    PTR_SUBU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gsldxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $8, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+    "dmtc1      $8, $f2                                   \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $8, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "lbu        $9, -0x1(%[pPred])                        \n\t"
+    PTR_ADDU   "$8, $8, $9                                \n\t"
+    "dmtc1      $8, $f4                                   \n\t"
+
+    "xor        $f8, $f8, $f8                             \n\t"
+    "punpcklwd  $f6, $f0, $f8                             \n\t"
+    "punpckhwd  $f0, $f0, $f8                             \n\t"
+    "pasubub    $f0, $f0, $f8                             \n\t"
+    "pasubub    $f6, $f6, $f8                             \n\t"
+    "biadd      $f0, $f0                                  \n\t"
+    "biadd      $f6, $f6                                  \n\t"
+
+    "paddd      $f6, $f6, $f2                             \n\t"
+    "paddd      $f2, $f4, $f0                             \n\t"
+
+    "dli        $8, 0x2                                   \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+    "gsldxc1    $f12, 0x0(%[mmi_01bytes], $0)             \n\t"
+    "dli        $8, 0x3                                   \n\t"
+    "dmtc1      $8, $f10                                  \n\t"
+
+    "paddd      $f0, $f0, $f8                             \n\t"
+    "dsrl       $f0, $f0, $f8                             \n\t"
+
+    "paddd      $f4, $f4, $f8                             \n\t"
+    "dsrl       $f4, $f4, $f8                             \n\t"
+
+    "paddd      $f6, $f6, $f8                             \n\t"
+    "paddd      $f6, $f6, $f8                             \n\t"
+    "dsrl       $f6, $f6, $f10                            \n\t"
+
+    "paddd      $f2, $f2, $f8                             \n\t"
+    "paddd      $f2, $f2, $f8                             \n\t"
+    "dsrl       $f2, $f2, $f10                            \n\t"
+
+    "dli        $8, 0x20                                  \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+    "pmuluw     $f0, $f0, $f12                            \n\t"
+    "pmuluw     $f6, $f6, $f12                            \n\t"
+    "dsll       $f0, $f0, $f8                             \n\t"
+    "xor        $f0, $f0, $f6                             \n\t"
+
+    "pmuluw     $f4, $f4, $f12                            \n\t"
+    "pmuluw     $f2, $f2, $f12                            \n\t"
+    "dsll       $f2, $f2, $f8                             \n\t"
+    "xor        $f2, $f2, $f4                             \n\t"
+
+    "gssdxc1    $f0, 0x0($10, $0)                         \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f0, 0x0($10, $0)                         \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f0, 0x0($10, $0)                         \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f0, 0x0($10, $0)                         \n\t"
+
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f2, 0x0($10, $0)                         \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f2, 0x0($10, $0)                         \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f2, 0x0($10, $0)                         \n\t"
+    PTR_ADDU   "$10, $10, %[kiStride]                     \n\t"
+    "gssdxc1    $f2, 0x0($10, $0)                         \n\t"
+    : [pPred] "+&r"((unsigned char *)pPred)
+    : [kiStride] "r"((int)kiStride),
+      [mmi_01bytes] "r"((unsigned char *)mmi_01bytes)
+    : "memory", "$8", "$9", "$10", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10",
+      "$f12"
+  );
+}
+
+void WelsDecoderIChromaPredDcTop_mmi(uint8_t *pPred, const int32_t kiStride) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "dli        $8, 0x4e                                  \n\t"
+    "dmtc1      $8, $f16                                  \n\t"
+    "dli        $8, 0xb1                                  \n\t"
+    "dmtc1      $8, $f18                                  \n\t"
+    "dli        $8, 0x2                                   \n\t"
+    "dmtc1      $8, $f20                                  \n\t"
+    PTR_SUBU   "$8, %[pPred], %[kiStride]                 \n\t"
+    "gsldxc1    $f0, 0x0($8, $0)                          \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "punpckhbh  $f2, $f0, $f28                            \n\t"
+    "punpcklbh  $f0, $f0, $f28                            \n\t"
+    "pshufh     $f4, $f0, $f16                            \n\t"
+    "pshufh     $f6, $f2, $f16                            \n\t"
+    "paddh      $f0, $f0, $f4                             \n\t"
+    "paddh      $f2, $f2, $f6                             \n\t"
+
+    "pshufh     $f8, $f0, $f18                            \n\t"
+    "pshufh     $f14, $f2, $f18                           \n\t"
+    "paddh      $f2, $f2, $f14                            \n\t"
+    "paddh      $f0, $f0, $f8                             \n\t"
+
+    "gslqc1     $f26, $f24, 0x0(%[mmi_wd_0x02])           \n\t"
+    "paddh      $f0, $f0, $f24                            \n\t"
+    "paddh      $f2, $f2, $f26                            \n\t"
+    "psrah      $f0, $f0, $f20                            \n\t"
+    "psrah      $f2, $f2, $f20                            \n\t"
+    "packushb   $f0, $f0, $f2                             \n\t"
+
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    PTR_ADDU   "%[pPred], %[pPred], %[kiStride]           \n\t"
+    "gssdxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    : [pPred] "+&r"((unsigned char *)pPred)
+    : [kiStride] "r"((int)kiStride), [mmi_wd_0x02] "r"((short *)mmi_wd_0x02)
+    : "memory", "$8", "$f0", "$f2", "$f4", "$f6"
+  );
+  RECOVER_REG;
+}
+
+void WelsDecoderI4x4LumaPredH_mmi(uint8_t *pPred, const int32_t kiStride) {
+  __asm__ volatile(
+    ".set       arch=loongson3a                           \n\t"
+    "gsldxc1    $f8, 0x0(%[mmi_01bytes], $0)              \n\t"
+    "lbu        $8, -0x1(%[pPred])                        \n\t"
+    "dmtc1      $8, $f0                                   \n\t"
+    "pmuluw     $f0, $f0, $f8                             \n\t"
+
+    PTR_ADDU   "$9, %[pPred], %[kiStride]                 \n\t"
+    "lbu        $8, -0x1($9)                              \n\t"
+    "dmtc1      $8, $f2                                   \n\t"
+    "pmuluw     $f2, $f2, $f8                             \n\t"
+
+    PTR_ADDU   "$10, $9, %[kiStride]                      \n\t"
+    "lbu        $8, -0x1($10)                             \n\t"
+    "dmtc1      $8, $f4                                   \n\t"
+    "pmuluw     $f4, $f4, $f8                             \n\t"
+
+    PTR_ADDU   "$11, $10, %[kiStride]                     \n\t"
+    "lbu        $8, -0x1($11)                             \n\t"
+    "dmtc1      $8, $f6                                   \n\t"
+    "pmuluw     $f6, $f6, $f8                             \n\t"
+
+    "gsswxc1    $f0, 0x0(%[pPred], $0)                    \n\t"
+    "gsswxc1    $f2, 0x0($9, $0)                          \n\t"
+    "gsswxc1    $f4, 0x0($10, $0)                         \n\t"
+    "gsswxc1    $f6, 0x0($11, $0)                         \n\t"
+    : [pPred] "+&r"((unsigned char *)pPred)
+    : [kiStride] "r"((int)kiStride),
+      [mmi_01bytes] "r"((unsigned char *)mmi_01bytes)
+    : "memory", "$8", "$9", "$10", "$11", "$f0", "$f2", "$f4", "$f6", "$f8"
+  );
+}
--- a/codec/decoder/core/src/decoder.cpp
+++ b/codec/decoder/core/src/decoder.cpp
@@ -1023,6 +1023,23 @@
 #endif
 
 #endif
+
+#if defined(HAVE_MMI)
+  if (uiCpuFlag & WELS_CPU_MMI) {
+    pCtx->pIdctResAddPredFunc   = IdctResAddPred_mmi;
+
+    pCtx->pGetI16x16LumaPredFunc[I16_PRED_DC] = WelsDecoderI16x16LumaPredDc_mmi;
+    pCtx->pGetI16x16LumaPredFunc[I16_PRED_P]  = WelsDecoderI16x16LumaPredPlane_mmi;
+    pCtx->pGetI16x16LumaPredFunc[I16_PRED_H]  = WelsDecoderI16x16LumaPredH_mmi;
+    pCtx->pGetI16x16LumaPredFunc[I16_PRED_V]  = WelsDecoderI16x16LumaPredV_mmi;
+    pCtx->pGetI16x16LumaPredFunc[I16_PRED_DC_T  ] = WelsDecoderI16x16LumaPredDcTop_mmi;
+    pCtx->pGetI16x16LumaPredFunc[I16_PRED_DC_128] = WelsDecoderI16x16LumaPredDcNA_mmi;
+    pCtx->pGetIChromaPredFunc[C_PRED_P ]      = WelsDecoderIChromaPredPlane_mmi;
+    pCtx->pGetIChromaPredFunc[C_PRED_DC]      = WelsDecoderIChromaPredDc_mmi;
+    pCtx->pGetIChromaPredFunc[C_PRED_DC_T]    = WelsDecoderIChromaPredDcTop_mmi;
+    pCtx->pGetI4x4LumaPredFunc[I4_PRED_H]     = WelsDecoderI4x4LumaPredH_mmi;
+  }
+#endif//HAVE_MMI
 }
 
 //reset decoder number related statistics info
--- a/codec/decoder/targets.mk
+++ b/codec/decoder/targets.mk
@@ -53,10 +53,22 @@
 endif
 OBJS += $(DECODER_OBJSARM64)
 
+DECODER_ASM_MIPS_SRCS=\
+	$(DECODER_SRCDIR)/core/mips/dct_mmi.c\
+
+DECODER_OBJSMIPS += $(DECODER_ASM_MIPS_SRCS:.c=.$(OBJ))
+ifeq ($(ASM_ARCH), mips)
+DECODER_OBJS += $(DECODER_OBJSMIPS)
+endif
+OBJS += $(DECODER_OBJSMIPS)
+
 OBJS += $(DECODER_OBJS)
 
 $(DECODER_SRCDIR)/%.$(OBJ): $(DECODER_SRCDIR)/%.cpp
 	$(QUIET_CXX)$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDES) $(DECODER_CFLAGS) $(DECODER_INCLUDES) -c $(CXX_O) $<
+
+$(DECODER_SRCDIR)/%.$(OBJ): $(DECODER_SRCDIR)/%.c
+	$(QUIET_CC)$(CC) $(CFLAGS) $(INCLUDES) $(DECODER_CFLAGS) $(DECODER_INCLUDES) -c $(CXX_O) $<
 
 $(DECODER_SRCDIR)/%.$(OBJ): $(DECODER_SRCDIR)/%.asm
 	$(QUIET_ASM)$(ASM) $(ASMFLAGS) $(ASM_INCLUDES) $(DECODER_ASMFLAGS) $(DECODER_ASM_INCLUDES) -o $@ $<
--- /dev/null
+++ b/codec/processing/src/mips/vaa_mmi.c
@@ -1,0 +1,892 @@
+/*!
+ * \copy
+ *     Copyright (c)  2009-2018, Cisco Systems
+ *     All rights reserved.
+ *
+ *     Redistribution and use in source and binary forms, with or without
+ *     modification, are permitted provided that the following conditions
+ *     are met:
+ *
+ *        * Redistributions of source code must retain the above copyright
+ *          notice, this list of conditions and the following disclaimer.
+ *
+ *        * Redistributions in binary form must reproduce the above copyright
+ *          notice, this list of conditions and the following disclaimer in
+ *          the documentation and/or other materials provided with the
+ *          distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *     POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * \file    vaa_mmi.c
+ *
+ * \brief   Loongson optimization
+ *
+ * \date    23/07/2018 Created
+ *
+ *************************************************************************************
+ */
+#include <stdint.h>
+#include "asmdefs_mmi.h"
+
+//f4 is 0x1, f6 is 0x8
+#define WELS_MAX_REG_MMI(f0, f2, f4, f6) \
+  "punpckhwd  $f4, "#f0", "#f0"    \n\t" \
+  "punpckhwd  $f6, "#f2", "#f2"    \n\t" \
+  "pmaxub     "#f0", "#f0", $f4    \n\t" \
+  "pmaxub     "#f2", "#f2", $f6    \n\t" \
+  "pshufh     $f4, "#f0", "#f4"    \n\t" \
+  "pshufh     $f6, "#f2", "#f4"    \n\t" \
+  "pmaxub     "#f0", "#f0", $f4    \n\t" \
+  "pmaxub     "#f2", "#f2", $f6    \n\t" \
+  "dsrl       $f4, "#f0", "#f6"    \n\t" \
+  "dsrl       $f6, "#f2", "#f6"    \n\t" \
+  "pmaxub     "#f0", "#f0", $f4    \n\t" \
+  "pmaxub     "#f2", "#f2", $f6    \n\t"
+
+#define WELS_SAD_SD_MAD_16x1_MMI(f0, f2, f4, f6, f8, f10, f12, f14, r0, r1, r2) \
+  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
+  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
+  "pasubub    $f12, $f4, $f0                      \n\t" \
+  "pasubub    $f14, $f6, $f2                      \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      "#f4", "#f4", $f12                  \n\t" \
+  "paddw      "#f6", "#f6", $f14                  \n\t" \
+  "pasubub    $f12, $f8, $f0                      \n\t" \
+  "pasubub    $f14, $f10, $f2                     \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      "#f8", "#f8", $f12                  \n\t" \
+  "paddw      "#f10", "#f10", $f14                \n\t" \
+  "pasubub    $f12, $f4, $f8                      \n\t" \
+  "pasubub    $f14, $f6, $f10                     \n\t" \
+  "pmaxub     "#f12", "#f12", $f12                \n\t" \
+  "pmaxub     "#f14", "#f14", $f14                \n\t" \
+  "pasubub    $f12, $f12, $f0                     \n\t" \
+  "pasubub    $f14, $f14, $f2                     \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      "#f0", "#f0", $f12                  \n\t" \
+  "paddw      "#f2", "#f2", $f14                  \n\t" \
+  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
+  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"
+
+#define WELS_SAD_16x2_MMI(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, r1, r2, r3) \
+  "gslqc1     "#f1",  "#f2",  0x00("#r1")         \n\t" \
+  "gslqc1     "#f3",  "#f4",  0x00("#r2")         \n\t" \
+  PTR_ADDU    ""#r1", "#r1",  "#r3"               \n\t" \
+  "gslqc1     "#f5",  "#f6",  0x00("#r1")         \n\t" \
+  PTR_ADDU    ""#r2", "#r2",  "#r3"               \n\t" \
+  "gslqc1     "#f7",  "#f8",  0x00("#r2")         \n\t" \
+  "pasubub    "#f1",  "#f1",  "#f3"               \n\t" \
+  "pasubub    "#f2",  "#f2",  "#f4"               \n\t" \
+  "biadd      "#f1",  "#f1"                       \n\t" \
+  "biadd      "#f2",  "#f2"                       \n\t" \
+  "pasubub    "#f5",  "#f5",  "#f7"               \n\t" \
+  "pasubub    "#f6",  "#f6",  "#f8"               \n\t" \
+  "biadd      "#f5",  "#f5"                       \n\t" \
+  "biadd      "#f6",  "#f6"                       \n\t" \
+  "paddw      "#f9",  "#f9",  "#f1"               \n\t" \
+  "paddw      "#f9",  "#f9",  "#f5"               \n\t" \
+  "paddw      "#f10", "#f10", "#f2"               \n\t" \
+  "paddw      "#f10", "#f10", "#f6"               \n\t" \
+  PTR_ADDU    ""#r1", "#r1",  "#r3"               \n\t" \
+  PTR_ADDU    ""#r2", "#r2",  "#r3"               \n\t"
+
+#define WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI(r0, r1, r2) \
+  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
+  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
+  "pasubub    $f12, $f4, $f8                      \n\t" \
+  "pasubub    $f14, $f6, $f10                     \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      $f28, $f28, $f12                    \n\t" \
+  "paddw      $f30, $f30, $f14                    \n\t" \
+  "pasubub    $f12, $f4, $f8                      \n\t" \
+  "pasubub    $f14, $f6, $f10                     \n\t" \
+  "pasubub    $f8, $f4, $f0                       \n\t" \
+  "pasubub    $f10, $f6, $f2                      \n\t" \
+  "biadd      $f8, $f8                            \n\t" \
+  "biadd      $f10, $f10                          \n\t" \
+  "paddw      $f24, $f24, $f8                     \n\t" \
+  "paddw      $f26, $f26, $f10                    \n\t" \
+  "punpcklbh  $f8, $f6, $f2                       \n\t" \
+  "punpckhbh  $f10, $f6, $f2                      \n\t" \
+  "punpckhbh  $f6, $f4, $f0                       \n\t" \
+  "punpcklbh  $f4, $f4, $f0                       \n\t" \
+  "pmaddhw    $f4, $f4, $f4                       \n\t" \
+  "pmaddhw    $f6, $f6, $f6                       \n\t" \
+  "pmaddhw    $f8, $f8, $f8                       \n\t" \
+  "pmaddhw    $f10, $f10, $f10                    \n\t" \
+  "paddw      $f20, $f20, $f4                     \n\t" \
+  "paddw      $f22, $f22, $f6                     \n\t" \
+  "paddw      $f20, $f20, $f8                     \n\t" \
+  "paddw      $f22, $f22, $f10                    \n\t" \
+  "punpcklbh  $f4, $f12, $f0                      \n\t" \
+  "punpckhbh  $f6, $f12, $f0                      \n\t" \
+	"punpcklbh  $f12, $f14, $f2                     \n\t" \
+	"punpckhbh  $f14, $f14, $f2                     \n\t" \
+  "pmaddhw    $f4, $f4, $f4                       \n\t" \
+  "pmaddhw    $f6, $f6, $f6                       \n\t" \
+  "pmaddhw    $f12, $f12, $f12                    \n\t" \
+  "pmaddhw    $f14, $f14, $f14                    \n\t" \
+  "paddw      $f16, $f16, $f4                     \n\t" \
+  "paddw      $f18, $f18, $f6                     \n\t" \
+  "paddw      $f16, $f16, $f12                    \n\t" \
+  "paddw      $f18, $f18, $f14                    \n\t" \
+  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
+  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"
+
+#define WELS_SAD_BGD_SQDIFF_16x1_MMI(f0, f2, f4, f6, f8, f10, f12, f14, r0, r1, r2) \
+  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
+  "punpcklbh  $f8, $f4, $f0                       \n\t" \
+  "punpckhbh  $f10, $f4, $f0                      \n\t" \
+  "punpcklbh  $f12, $f6, $f2                      \n\t" \
+  "punpckhbh  $f14, $f6, $f2                      \n\t" \
+  "pmaddhw    $f8, $f8, $f8                       \n\t" \
+  "pmaddhw    $f10, $f10, $f10                    \n\t" \
+  "pmaddhw    $f12, $f12, $f12                    \n\t" \
+  "pmaddhw    $f14, $f14, $f14                    \n\t" \
+  "paddw      $f8, $f8, $f12                      \n\t" \
+  "paddw      $f10, $f10, $f14                    \n\t" \
+  "punpckhwd  $f12, $f0, $f8                      \n\t" \
+  "punpckhwd  $f14, $f0, $f10                     \n\t" \
+  "punpcklwd  $f8, $f0, $f8                       \n\t" \
+  "punpcklwd  $f10, $f0, $f10                     \n\t" \
+  "paddw      $f8, $f8, $f12                      \n\t" \
+  "paddw      $f10, $f10, $f14                    \n\t" \
+  "paddw      "#f0", "#f0", $f8                   \n\t" \
+  "paddw      "#f2", "#f2", $f10                  \n\t" \
+  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
+  "pasubub    $f12, $f4, $f0                      \n\t" \
+  "pasubub    $f14, $f6, $f2                      \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      "#f4", "#f4", $f12                  \n\t" \
+  "paddw      "#f6", "#f6", $f14                  \n\t" \
+  "pasubub    $f12, $f8, $f0                      \n\t" \
+  "pasubub    $f14, $f10, $f2                     \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "punpcklwd  $f14, $f14, $f14                    \n\t" \
+  "punpckhwd  $f14, $f12, $f14                    \n\t" \
+  "punpcklwd  $f12, $f0, $f12                     \n\t" \
+  "paddw      "#f4", "#f4", $f12                  \n\t" \
+  "paddw      "#f6", "#f6", $f14                  \n\t" \
+  "pasubub    $f12, $f4, $f8                      \n\t" \
+  "pasubub    $f14, $f6, $f10                     \n\t" \
+  "pmaxub     "#f8", "#f8", $f12                  \n\t" \
+  "pmaxub     "#f10", "#f10", $f14                \n\t" \
+  "paddw      $f4, $f0, $f12                      \n\t" \
+  "paddw      $f6, $f0, $f14                      \n\t" \
+  "pasubub    $f12, $f12, $f0                     \n\t" \
+  "pasubub    $f14, $f14, $f2                     \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      "#f0", "#f0", $f12                  \n\t" \
+  "paddw      "#f2", "#f2", $f14                  \n\t" \
+  "paddw      $f12, $f0, $f4                      \n\t" \
+  "paddw      $f14, $f0, $f6                      \n\t" \
+  "punpcklbh  $f4, $f12, $f0                      \n\t" \
+  "punpckhbh  $f6, $f12, $f0                      \n\t" \
+  "punpcklbh  $f12, $f14, $f2                     \n\t" \
+  "punpckhbh  $f14, $f14, $f2                     \n\t" \
+  "pmaddhw    $f4, $f4, $f4                       \n\t" \
+  "pmaddhw    $f6, $f6, $f6                       \n\t" \
+  "pmaddhw    $f12, $f12, $f12                    \n\t" \
+  "pmaddhw    $f14, $f14, $f14                    \n\t" \
+  "paddw      "#f12", "#f12", $f4                 \n\t" \
+  "paddw      "#f14", "#f14", $f6                 \n\t" \
+  "paddw      "#f12", "#f12", $f12                \n\t" \
+  "paddw      "#f14", "#f14", $f14                \n\t" \
+  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
+  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"
+
+#define WELS_SAD_SUM_SQSUM_16x1_MMI(r0, r1, r2) \
+  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
+  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
+  "pasubub    $f12, $f4, $f8                      \n\t" \
+  "pasubub    $f14, $f6, $f10                     \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      $f24, $f24, $f12                    \n\t" \
+  "paddw      $f26, $f26, $f14                    \n\t" \
+  "pasubub    $f12, $f4, $f0                      \n\t" \
+  "pasubub    $f14, $f6, $f2                      \n\t" \
+  "biadd      $f12, $f12                          \n\t" \
+  "biadd      $f14, $f14                          \n\t" \
+  "paddw      $f20, $f20, $f12                    \n\t" \
+  "paddw      $f22, $f22, $f14                    \n\t" \
+  "punpcklbh  $f8, $f6, $f2                       \n\t" \
+  "punpckhbh  $f10, $f6, $f2                      \n\t" \
+  "punpckhbh  $f6, $f4, $f0                       \n\t" \
+  "punpcklbh  $f4, $f4, $f0                       \n\t" \
+  "pmaddhw    $f4, $f4, $f4                       \n\t" \
+  "pmaddhw    $f6, $f6, $f6                       \n\t" \
+  "pmaddhw    $f8, $f8, $f8                       \n\t" \
+  "pmaddhw    $f10, $f10, $f10                    \n\t" \
+  "paddw      $f16, $f16, $f4                     \n\t" \
+  "paddw      $f18, $f18, $f6                     \n\t" \
+  "paddw      $f16, $f16, $f8                     \n\t" \
+  "paddw      $f18, $f18, $f10                    \n\t" \
+  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
+  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"
+
+void VAACalcSad_mmi(const uint8_t* pCurData, const uint8_t* pRefData,
+                    int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
+                    int32_t* pFrameSad, int32_t* pSad8x8) {
+  double ftmp[13];
+  uint64_t tmp[2];
+  mips_reg addr[3];
+
+  __asm__ volatile (
+    ".set       arch=loongson3a                                     \n\t"
+    PTR_SRL    "%[iPicWidth],   %[iPicWidth],   0x04                \n\t"
+    PTR_SRL    "%[iPicHeight],  %[iPicHeight],  0x04                \n\t"
+    "move       %[addr2],       %[iPicStride]                       \n\t"
+    PTR_SLL    "%[iPicStride],  %[iPicStride],  0x04                \n\t"
+    "xor        %[ftmp0],       %[ftmp0],       %[ftmp0]            \n\t"
+    "xor        %[ftmp11],      %[ftmp11],      %[ftmp11]           \n\t"
+    "xor        %[ftmp12],      %[ftmp12],      %[ftmp12]           \n\t"
+    "1:                                                             \n\t"
+    "move       %[addr0],       %[pCurData]                         \n\t"
+    "move       %[addr1],       %[pRefData]                         \n\t"
+    "move       %[tmp0],        %[iPicWidth]                        \n\t"
+    "2:                                                             \n\t"
+    "xor        %[ftmp9],       %[ftmp9],       %[ftmp9]            \n\t"
+    "xor        %[ftmp10],      %[ftmp10],      %[ftmp10]           \n\t"
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    "paddw      %[ftmp11],      %[ftmp11],      %[ftmp9]            \n\t"
+    "paddw      %[ftmp12],      %[ftmp12],      %[ftmp10]           \n\t"
+    "swc1       %[ftmp10],      0x00(%[pSad8x8])                    \n\t"
+    "swc1       %[ftmp9],       0x04(%[pSad8x8])                    \n\t"
+
+    "xor        %[ftmp9],       %[ftmp9],       %[ftmp9]            \n\t"
+    "xor        %[ftmp10],      %[ftmp10],      %[ftmp10]           \n\t"
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
+                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
+                      %[addr0], %[addr1], %[addr2])
+    "paddw      %[ftmp11],      %[ftmp11],      %[ftmp9]            \n\t"
+    "paddw      %[ftmp12],      %[ftmp12],      %[ftmp10]           \n\t"
+    "swc1       %[ftmp10],      0x08(%[pSad8x8])                    \n\t"
+    "swc1       %[ftmp9],       0x0c(%[pSad8x8])                    \n\t"
+
+    PTR_ADDU   "%[pSad8x8],     %[pSad8x8],     0x10                \n\t"
+    PTR_SUBU   "%[addr0],       %[addr0],       %[iPicStride]       \n\t"
+    PTR_SUBU   "%[addr1],       %[addr1],       %[iPicStride]       \n\t"
+    PTR_ADDI   "%[tmp0],        %[tmp0],        -0x01               \n\t"
+    PTR_ADDU   "%[addr0],       %[addr0],       0x10                \n\t"
+    PTR_ADDU   "%[addr1],       %[addr1],       0x10                \n\t"
+    "bnez       %[tmp0],        2b                                  \n\t"
+
+    PTR_ADDI   "%[iPicHeight],  %[iPicHeight],  -0x01               \n\t"
+    PTR_ADDU   "%[pCurData],    %[pCurData],    %[iPicStride]       \n\t"
+    PTR_ADDU   "%[pRefData],    %[pRefData],    %[iPicStride]       \n\t"
+    "bnez       %[iPicHeight],  1b                                  \n\t"
+
+    "paddw      %[ftmp11],      %[ftmp11],      %[ftmp12]           \n\t"
+    "swc1       %[ftmp11],      0x00(%[pFrameSad])                  \n\t"
+    : [ftmp0]"=&f"(ftmp[0]),            [ftmp1]"=&f"(ftmp[1]),
+      [ftmp2]"=&f"(ftmp[2]),            [ftmp3]"=&f"(ftmp[3]),
+      [ftmp4]"=&f"(ftmp[4]),            [ftmp5]"=&f"(ftmp[5]),
+      [ftmp6]"=&f"(ftmp[6]),            [ftmp7]"=&f"(ftmp[7]),
+      [ftmp8]"=&f"(ftmp[8]),            [ftmp9]"=&f"(ftmp[9]),
+      [ftmp10]"=&f"(ftmp[10]),          [ftmp11]"=&f"(ftmp[11]),
+      [ftmp12]"=&f"(ftmp[12]),          [tmp0]"=&r"(tmp[0]),
+      [addr0]"=&r"(addr[0]),            [addr1]"=&r"(addr[1]),
+      [pCurData]"+&r"(pCurData),        [pRefData]"+&r"(pRefData),
+      [iPicHeight]"+&r"(iPicHeight),    [iPicWidth]"+&r"(iPicWidth),
+      [pSad8x8]"+&r"(pSad8x8),          [iPicStride]"+&r"(iPicStride),
+      [addr2]"=&r"(addr[2])
+    : [pFrameSad]"r"(pFrameSad)
+    : "memory"
+  );
+}
+
+void VAACalcSadBgd_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
+                       int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
+                       int32_t *psadframe, int32_t *psad8x8, int32_t *p_sd8x8,
+                       uint8_t *p_mad8x8) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "move       $15, %[cur_data]                          \n\t"
+    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
+    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
+    "dsll       $13, %[iPicStride], 0x4                   \n\t"
+    "xor        $f0, $f0, $f0                             \n\t"
+    "xor        $f2, $f2, $f2                             \n\t"
+    "xor        $14, $14, $14                             \n\t"
+    "1:                                                   \n\t"
+    "move       $9, %[iPicWidth]                          \n\t"
+    "move       $10, $15                                  \n\t"
+    "move       $11, %[ref_data]                          \n\t"
+    "2:                                                   \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "xor        $f30, $f30, $f30                          \n\t"
+    "xor        $f24, $f24, $f24                          \n\t"
+    "xor        $f26, $f26, $f26                          \n\t"
+    "xor        $f20, $f20, $f20                          \n\t"
+    "xor        $f22, $f22, $f22                          \n\t"
+    "xor        $f16, $f16, $f16                          \n\t"
+    "xor        $f18, $f18, $f18                          \n\t"
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+
+    "dli        $8, 0x1                                   \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+    "dli        $8, 0x8                                   \n\t"
+    "dmtc1      $8, $f10                                  \n\t"
+    WELS_MAX_REG_MMI($f16, $f18, $f8, $f10)
+
+    "dmfc1      $8, $f16                                  \n\t"
+    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
+    "dmfc1      $8, $f18                                  \n\t"
+    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
+    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"
+
+    "xor        $f16, $f16, $f16                          \n\t"
+    "xor        $f18, $f18, $f18                          \n\t"
+    "punpcklwd  $f30, $f30, $f30                          \n\t"
+    "punpcklwd  $f26, $f26, $f26                          \n\t"
+    "punpcklwd  $f22, $f22, $f22                          \n\t"
+
+    "punpckhwd  $f30, $f28, $f30                          \n\t"
+    "punpckhwd  $f26, $f24, $f26                          \n\t"
+    "punpckhwd  $f22, $f20, $f22                          \n\t"
+
+    "punpcklwd  $f28, $f16, $f28                          \n\t"
+    "punpcklwd  $f24, $f16, $f24                          \n\t"
+    "punpcklwd  $f20, $f16, $f20                          \n\t"
+
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
+                             $15, %[ref_data], %[iPicStride])
+
+    "dli        $8, 0x1                                   \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+    "dli        $8, 0x8                                   \n\t"
+    "dmtc1      $8, $f10                                  \n\t"
+    WELS_MAX_REG_MMI($f16, $f18, $f8, $f10)
+
+    "dmfc1      $8, $f16                                  \n\t"
+    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
+    "dmfc1      $8, $f18                                  \n\t"
+    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
+    "punpckhwd  $f4, $f28, $f30                           \n\t"
+    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"
+
+    "punpcklwd  $f6, $f28, $f30                           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[psad8x8])                 \n\t"
+    PTR_ADDIU  "%[psad8x8], %[psad8x8], 0x10              \n\t"
+
+    "paddw      $f6, $f6, $f30                            \n\t"
+    "paddw      $f4, $f4, $f28                            \n\t"
+    "punpckhwd  $f8, $f6, $f6                             \n\t"
+    "paddw      $f4, $f4, $f8                             \n\t"
+    "dmtc1      $14, $f6                                  \n\t"
+    "paddw      $f6, $f6, $f4                             \n\t"
+    "dmfc1      $14, $f6                                  \n\t"
+
+    "psubw      $f24, $f24, $f20                          \n\t"
+    "psubw      $f26, $f26, $f22                          \n\t"
+    "punpckhwd  $f4, $f24, $f26                           \n\t"
+    "punpcklwd  $f6, $f24, $f26                           \n\t"
+    "gssqc1     $f6, $f4, 0x0(%[p_sd8x8])                 \n\t"
+    PTR_ADDIU  "%[p_sd8x8], %[p_sd8x8], 0x10              \n\t"
+
+    PTR_SUBU   "$15, $15, $13                             \n\t"
+    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
+    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
+    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"
+
+    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
+    "bnez       %[iPicWidth], 2b                          \n\t"
+    "move       %[iPicWidth], $9                          \n\t"
+    "move       $15, $10                                  \n\t"
+    "move       %[ref_data], $11                          \n\t"
+    PTR_ADDU   "$15, $15, $13                             \n\t"
+    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"
+
+    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
+    "bnez       %[iPicHeight], 1b                         \n\t"
+
+    "swl        $14, 0x3(%[psadframe])                    \n\t"
+    "swr        $14, 0x0(%[psadframe])                    \n\t"
+    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
+      [iPicHeight]"+&r"((int)iPicHeight), [psad8x8]"+&r"((int *)psad8x8),
+      [p_sd8x8]"+&r"((int *)p_sd8x8), [p_mad8x8]"+&r"((unsigned char *)p_mad8x8)
+    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
+      [psadframe]"r"((int *)psadframe)
+    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
+      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
+      "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void VAACalcSadSsd_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
+                       int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
+                       int32_t *psadframe, int32_t *psad8x8, int32_t *psum16x16,
+                       int32_t *psqsum16x16, int32_t *psqdiff16x16) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "move       $15, %[cur_data]                          \n\t"
+    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
+    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
+    "dsll       $13, %[iPicStride], 0x4                   \n\t"
+    "xor        $f0, $f0, $f0                             \n\t"
+    "xor        $f2, $f2, $f2                             \n\t"
+    "xor        $12, $12, $12                             \n\t"
+    "xor        $14, $14, $14                             \n\t"
+    "1:                                                   \n\t"
+    "move       $9, %[iPicWidth]                          \n\t"
+    "move       $10, $15                                  \n\t"
+    "move       $11, %[ref_data]                          \n\t"
+    "2:                                                   \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "xor        $f30, $f30, $f30                          \n\t"
+    "xor        $f24, $f24, $f24                          \n\t"
+    "xor        $f26, $f26, $f26                          \n\t"
+    "xor        $f20, $f20, $f20                          \n\t"
+    "xor        $f22, $f22, $f22                          \n\t"
+    "xor        $f16, $f16, $f16                          \n\t"
+    "xor        $f18, $f18, $f18                          \n\t"
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    "dmfc1      $8, $f28                                  \n\t"
+    "sw         $8, 0x0(%[psad8x8])                       \n\t"
+    "dmfc1      $8, $f30                                  \n\t"
+    "sw         $8, 0x4(%[psad8x8])                       \n\t"
+    "paddw      $f4, $f28, $f30                           \n\t"
+    "dmfc1      $12, $f4                                  \n\t"
+	  PTR_ADDU   "$14, $14, $12                             \n\t"
+
+    "xor        $f28, $f28, $f28                          \n\t"
+    "xor        $f30, $f30, $f30                          \n\t"
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
+    "dmfc1      $8, $f28                                  \n\t"
+    "sw         $8, 0x8(%[psad8x8])                       \n\t"
+    "dmfc1      $8, $f30                                  \n\t"
+    "paddw      $f4, $f28, $f30                           \n\t"
+    "sw         $8, 0xc(%[psad8x8])                       \n\t"
+    "dmfc1      $12, $f4                                  \n\t"
+	  PTR_ADDU   "$14, $14, $12                             \n\t"
+    PTR_ADDIU  "%[psad8x8],   %[psad8x8],   0x10          \n\t"
+
+    "paddw      $f24, $f24, $f26                          \n\t"
+    "dmfc1      $8, $f24                                  \n\t"
+    "sw         $8, 0x0(%[psum16x16])                     \n\t"
+    PTR_ADDIU  "%[psum16x16], %[psum16x16], 0x4           \n\t"
+    "paddw      $f24, $f20, $f22                          \n\t"
+	  "punpcklwd  $f20, $f24, $f24                          \n\t"
+	  "punpckhwd  $f22, $f24, $f24                          \n\t"
+    "paddw      $f20, $f20, $f22                          \n\t"
+    "dmfc1      $8, $f20                                  \n\t"
+    "sw         $8, 0x0(%[psqsum16x16])                   \n\t"
+    PTR_ADDIU  "%[psqsum16x16], %[psqsum16x16], 0x4       \n\t"
+
+    "paddw      $f20, $f16, $f18                          \n\t"
+	  "punpcklwd  $f16, $f20, $f20                          \n\t"
+	  "punpckhwd  $f18, $f20, $f20                          \n\t"
+    "paddw      $f16, $f16, $f18                          \n\t"
+    "dmfc1      $8, $f16                                  \n\t"
+    "sw         $8, 0x0(%[psqdiff16x16])                  \n\t"
+    PTR_ADDIU  "%[psqdiff16x16], %[psqdiff16x16], 0x4     \n\t"
+
+    PTR_SUBU   "$15, $15, $13                             \n\t"
+    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
+    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
+    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"
+
+    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
+    "bnez       %[iPicWidth], 2b                          \n\t"
+    "nop                                                  \n\t"
+    "move       %[iPicWidth], $9                          \n\t"
+    "move       $15, $10                                  \n\t"
+    "move       %[ref_data], $11                          \n\t"
+    PTR_ADDU   "$15, $15, $13                             \n\t"
+    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"
+
+    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
+    "bnez       %[iPicHeight], 1b                         \n\t"
+    "nop                                                  \n\t"
+
+    "sw         $14, 0x0(%[psadframe])                    \n\t"
+    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
+      [iPicHeight]"+&r"((int)iPicHeight), [psum16x16]"+&r"((int *)psum16x16),
+      [psqsum16x16]"+&r"((int *)psqsum16x16), [psqdiff16x16]"+&r"((int *)psqdiff16x16)
+    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
+      [psadframe]"r"((int *)psadframe), [psad8x8]"r"((int *)psad8x8)
+    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
+      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
+      "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void VAACalcSadSsdBgd_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
+                          int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
+                          int32_t *psadframe, int32_t *psad8x8, int32_t *psum16x16,
+                          int32_t *psqsum16x16, int32_t *psqdiff16x16, int32_t *p_sd8x8,
+                          uint8_t *p_mad8x8) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "move       $15, %[cur_data]                          \n\t"
+    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
+    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
+    "dsll       $13, %[iPicStride], 0x4                   \n\t"
+    "xor        $f0, $f0, $f0                             \n\t"
+    "xor        $f2, $f2, $f2                             \n\t"
+    "xor        $12, $12, $12                             \n\t"
+    "xor        $14, $14, $14                             \n\t"
+    "1:                                                   \n\t"
+    "move       $9, %[iPicWidth]                          \n\t"
+    "move       $10, $15                                  \n\t"
+    "move       $11, %[ref_data]                          \n\t"
+    "2:                                                   \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "xor        $f30, $f30, $f30                          \n\t"
+    "xor        $f24, $f24, $f24                          \n\t"
+    "xor        $f26, $f26, $f26                          \n\t"
+    "xor        $f20, $f20, $f20                          \n\t"
+    "xor        $f22, $f22, $f22                          \n\t"
+    "xor        $f16, $f16, $f16                          \n\t"
+    "xor        $f18, $f18, $f18                          \n\t"
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+
+    "dmfc1      $8, $f28                                  \n\t"
+    "sw         $8, 0x0(%[psad8x8])                       \n\t"
+    "dmfc1      $8, $f30                                  \n\t"
+    "sw         $8, 0x4(%[psad8x8])                       \n\t"
+    PTR_ADDIU  "%[psad8x8], %[psad8x8], 0x8               \n\t"
+
+    "paddw      $f4, $f28, $f30                           \n\t"
+    "dmfc1      $12, $f4                                  \n\t"
+    PTR_ADDU   "$14, $14,  $12                            \n\t"
+
+    "paddw      $f4, $f24, $f26                           \n\t"
+    "dmfc1      $8, $f4                                   \n\t"
+    "sw         $8, 0x0(%[psum16x16])                     \n\t"
+
+    "punpckhwd  $f4, $f24, $f26                           \n\t"
+    "punpcklwd  $f6, $f24, $f26                           \n\t"
+    "psubw      $f6, $f6, $f4                             \n\t"
+    "dmfc1      $8, $f6                                   \n\t"
+    PTR_S      "$8, 0x0(%[p_sd8x8])                       \n\t"
+    PTR_ADDIU  "%[p_sd8x8], %[p_sd8x8], 0x8               \n\t"
+
+    "dli        $8, 0x1                                   \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+    "dli        $8, 0x8                                   \n\t"
+    "dmtc1      $8, $f10                                  \n\t"
+    WELS_MAX_REG_MMI($f20, $f22, $f8, $f10)
+
+    "dmfc1      $8, $f20                                  \n\t"
+    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
+    "dmfc1      $8, $f22                                  \n\t"
+    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
+    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"
+
+    "xor        $f20, $f20, $f20                          \n\t"
+    "xor        $f22, $f22, $f22                          \n\t"
+    "punpckhwd  $f28, $f20, $f28                          \n\t"
+    "xor        $f24, $f24, $f24                          \n\t"
+    "xor        $f26, $f26, $f26                          \n\t"
+    "punpckhwd  $f30, $f20, $f30                          \n\t"
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
+                                 $f18, $15, %[ref_data], %[iPicStride])
+
+    "dmfc1      $8, $f28                                  \n\t"
+    "sw         $8, 0x0(%[psad8x8])                       \n\t"
+    "dmfc1      $8, $f30                                  \n\t"
+    "sw         $8, 0x4(%[psad8x8])                       \n\t"
+    PTR_ADDIU  "%[psad8x8], %[psad8x8], 0x8               \n\t"
+
+    "paddw      $f4, $f28, $f30                           \n\t"
+    "dmfc1      $12, $f4                                  \n\t"
+    PTR_ADDU   "$14, $14, $12                             \n\t"
+
+    "paddw      $f4, $f24, $f26                           \n\t"
+    "dmfc1      $8, $f4                                   \n\t"
+    "lw         $12, 0x0(%[psum16x16])                    \n\t"
+    PTR_ADDU   "$8, $8, $12                               \n\t"
+    "sw         $8, 0x0(%[psum16x16])                     \n\t"
+    "xor        $f8, $f8, $f8                             \n\t"
+    PTR_ADDIU  "%[psum16x16], %[psum16x16], 0x4           \n\t"
+
+    "punpckhwd  $f30, $f30, $f8                           \n\t"
+    "punpckhwd  $f28, $f28, $f8                           \n\t"
+    "paddw      $f8, $f28, $f30                           \n\t"
+    "dmfc1      $8, $f8                                   \n\t"
+    "sw         $8, 0x0(%[psqsum16x16])                   \n\t"
+    PTR_ADDIU  "%[psqsum16x16], %[psqsum16x16], 0x4       \n\t"
+
+    "punpckhwd  $f4, $f24, $f26                           \n\t"
+    "punpcklwd  $f6, $f24, $f26                           \n\t"
+    "psubw      $f6, $f6, $f4                             \n\t"
+    "dmfc1      $8, $f6                                   \n\t"
+    PTR_S      "$8, 0x0(%[p_sd8x8])                       \n\t"
+    PTR_ADDIU  "%[p_sd8x8], %[p_sd8x8], 0x8               \n\t"
+
+    "dli        $8, 0x1                                   \n\t"
+    "dmtc1      $8, $f8                                   \n\t"
+    "dli        $8, 0x8                                   \n\t"
+    "dmtc1      $8, $f10                                  \n\t"
+    WELS_MAX_REG_MMI($f20, $f22, $f8, $f10)
+
+    "dmfc1      $8, $f20                                  \n\t"
+    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
+    "dmfc1      $8, $f22                                  \n\t"
+    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
+    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"
+
+    "paddw      $f20, $f16, $f18                          \n\t"
+	  "punpcklwd  $f16, $f20, $f20                          \n\t"
+	  "punpckhwd  $f18, $f20, $f20                          \n\t"
+    "paddw      $f16, $f16, $f18                          \n\t"
+    "dmfc1      $8, $f16                                  \n\t"
+    "sw         $8, 0x0(%[psqdiff16x16])                  \n\t"
+    PTR_ADDIU  "%[psqdiff16x16], %[psqdiff16x16], 0x4     \n\t"
+
+    PTR_SUBU   "$15, $15, $13                             \n\t"
+    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
+    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
+    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"
+
+    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
+    "bnez       %[iPicWidth], 2b                          \n\t"
+    "nop                                                  \n\t"
+    "move       %[iPicWidth], $9                          \n\t"
+    "move       $15, $10                                  \n\t"
+    "move       %[ref_data], $11                          \n\t"
+    PTR_ADDU   "$15, $15, $13                             \n\t"
+    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"
+
+    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
+    "bnez       %[iPicHeight], 1b                         \n\t"
+    "nop                                                  \n\t"
+
+    "sw         $14, 0x0(%[psadframe])                    \n\t"
+    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
+      [iPicHeight]"+&r"((int)iPicHeight), [psad8x8]"+&r"((int *)psad8x8),
+      [psum16x16]"+&r"((int *)psum16x16), [psqsum16x16]"+&r"((int *)psqsum16x16),
+	    [psqdiff16x16]"+&r"((int *)psqdiff16x16), [p_sd8x8]"+&r"((int *)p_sd8x8),
+      [p_mad8x8]"+&r"((unsigned char *)p_mad8x8)
+    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
+      [psadframe]"r"((int *)psadframe)
+    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
+      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
+      "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
+
+void VAACalcSadVar_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
+                       int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
+                       int32_t *psadframe, int32_t *psad8x8, int32_t *psum16x16,
+                       int32_t *psqsum16x16) {
+  BACKUP_REG;
+  __asm__ volatile (
+    ".set       arch=loongson3a                           \n\t"
+    "move       $15, %[cur_data]                          \n\t"
+    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
+    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
+    "dsll       $13, %[iPicStride], 0x4                   \n\t"
+    "xor        $f0, $f0, $f0                             \n\t"
+    "xor        $f2, $f2, $f2                             \n\t"
+    "xor        $f28, $f28, $f28                          \n\t"
+    "xor        $f30, $f30, $f30                          \n\t"
+    "xor        $14, $14, $14                             \n\t"
+    "1:                                                   \n\t"
+    "move       $9, %[iPicWidth]                          \n\t"
+    "move       $10, $15                                  \n\t"
+    "move       $11, %[ref_data]                          \n\t"
+    "2:                                                   \n\t"
+    "xor        $f24, $f24, $f24                          \n\t"
+    "xor        $f26, $f26, $f26                          \n\t"
+    "xor        $f20, $f20, $f20                          \n\t"
+    "xor        $f22, $f22, $f22                          \n\t"
+    "xor        $f16, $f16, $f16                          \n\t"
+    "xor        $f18, $f18, $f18                          \n\t"
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    "paddw      $f28, $f24, $f28                          \n\t"
+    "paddw      $f30, $f26, $f30                          \n\t"
+    "dmfc1      $8, $f24                                  \n\t"
+    "sw         $8, 0x0(%[psad8x8])                       \n\t"
+    "dmfc1      $8, $f26                                  \n\t"
+    "sw         $8, 0x4(%[psad8x8])                       \n\t"
+
+    "xor        $f24, $f24, $f24                          \n\t"
+    "xor        $f26, $f26, $f26                          \n\t"
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
+    "paddw      $f28, $f24, $f28                          \n\t"
+    "paddw      $f30, $f26, $f30                          \n\t"
+    "dmfc1      $8, $f24                                  \n\t"
+    "sw         $8, 0x8(%[psad8x8])                       \n\t"
+    "dmfc1      $8, $f26                                  \n\t"
+    "sw         $8, 0xc(%[psad8x8])                       \n\t"
+    PTR_ADDIU  "%[psad8x8],   %[psad8x8],   0x10          \n\t"
+
+    "paddw      $f20, $f20, $f22                          \n\t"
+    "dmfc1      $8, $f20                                  \n\t"
+    "sw         $8, 0x0(%[psum16x16])                     \n\t"
+    PTR_ADDIU  "%[psum16x16], %[psum16x16], 0x4           \n\t"
+
+    "paddw      $f20, $f16, $f18                          \n\t"
+	  "punpcklwd  $f16, $f20, $f20                          \n\t"
+	  "punpckhwd  $f18, $f20, $f20                          \n\t"
+    "paddw      $f16, $f16, $f18                          \n\t"
+    "dmfc1      $8, $f16                                  \n\t"
+    "sw         $8, 0x0(%[psqsum16x16])                   \n\t"
+    PTR_ADDIU  "%[psqsum16x16], %[psqsum16x16], 0x4       \n\t"
+
+    PTR_SUBU   "$15, $15, $13                             \n\t"
+    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
+    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
+    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"
+
+    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
+    "bnez       %[iPicWidth], 2b                          \n\t"
+    "nop                                                  \n\t"
+    "move       %[iPicWidth], $9                          \n\t"
+    "move       $15, $10                                  \n\t"
+    "move       %[ref_data], $11                          \n\t"
+    PTR_ADDU   "$15, $15, $13                             \n\t"
+    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"
+
+    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
+    "bnez       %[iPicHeight], 1b                         \n\t"
+    "nop                                                  \n\t"
+
+    "paddw      $f28, $f28, $f30                          \n\t"
+    "dmfc1      $8, $f28                                  \n\t"
+    "sw         $8, 0x0(%[psadframe])                     \n\t"
+    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
+      [iPicHeight]"+&r"((int)iPicHeight), [psum16x16]"+&r"((int *)psum16x16),
+      [psqsum16x16]"+&r"((int *)psqsum16x16)
+    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
+      [psadframe]"r"((int *)psadframe), [psad8x8]"r"((int *)psad8x8)
+    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
+      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
+      "$f24", "$f26", "$f28", "$f30"
+  );
+  RECOVER_REG;
+}
--- a/codec/processing/src/vaacalc/vaacalculation.cpp
+++ b/codec/processing/src/vaacalc/vaacalculation.cpp
@@ -93,6 +93,16 @@
     sVaaFuncs.pfVAACalcSadVar    = VAACalcSadVar_AArch64_neon;
   }
 #endif//HAVE_NEON_AARCH64
+
+#ifdef HAVE_MMI
+  if ((iCpuFlag & WELS_CPU_MMI) == WELS_CPU_MMI) {
+    sVaaFuncs.pfVAACalcSad       = VAACalcSad_mmi;
+    sVaaFuncs.pfVAACalcSadBgd    = VAACalcSadBgd_mmi;
+    sVaaFuncs.pfVAACalcSadSsd    = VAACalcSadSsd_mmi;
+    sVaaFuncs.pfVAACalcSadSsdBgd = VAACalcSadSsdBgd_mmi;
+    sVaaFuncs.pfVAACalcSadVar    = VAACalcSadVar_mmi;
+  }
+#endif//HAVE_MMI
 }
 
 EResult CVAACalculation::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
--- a/codec/processing/src/vaacalc/vaacalculation.h
+++ b/codec/processing/src/vaacalc/vaacalculation.h
@@ -132,6 +132,16 @@
 WELSVP_EXTERN_C_END
 #endif
 
+#ifdef HAVE_MMI
+WELSVP_EXTERN_C_BEGIN
+VAACalcSadBgdFunc       VAACalcSadBgd_mmi;
+VAACalcSadSsdBgdFunc    VAACalcSadSsdBgd_mmi;
+VAACalcSadFunc          VAACalcSad_mmi;
+VAACalcSadVarFunc       VAACalcSadVar_mmi;
+VAACalcSadSsdFunc       VAACalcSadSsd_mmi;
+WELSVP_EXTERN_C_END
+#endif
+
 class CVAACalculation : public IStrategy {
  public:
   CVAACalculation (int32_t iCpuFlag);
--- a/codec/processing/targets.mk
+++ b/codec/processing/targets.mk
@@ -55,10 +55,22 @@
 endif
 OBJS += $(PROCESSING_OBJSARM64)
 
+PROCESSING_ASM_MIPS_SRCS=\
+	$(PROCESSING_SRCDIR)/src/mips/vaa_mmi.c\
+
+PROCESSING_OBJSMIPS += $(PROCESSING_ASM_MIPS_SRCS:.c=.$(OBJ))
+ifeq ($(ASM_ARCH), mips)
+PROCESSING_OBJS += $(PROCESSING_OBJSMIPS)
+endif
+OBJS += $(PROCESSING_OBJSMIPS)
+
 OBJS += $(PROCESSING_OBJS)
 
 $(PROCESSING_SRCDIR)/%.$(OBJ): $(PROCESSING_SRCDIR)/%.cpp
 	$(QUIET_CXX)$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDES) $(PROCESSING_CFLAGS) $(PROCESSING_INCLUDES) -c $(CXX_O) $<
+
+$(PROCESSING_SRCDIR)/%.$(OBJ): $(PROCESSING_SRCDIR)/%.c
+	$(QUIET_CC)$(CC) $(CFLAGS) $(INCLUDES) $(PROCESSING_CFLAGS) $(PROCESSING_INCLUDES) -c $(CXX_O) $<
 
 $(PROCESSING_SRCDIR)/%.$(OBJ): $(PROCESSING_SRCDIR)/%.asm
 	$(QUIET_ASM)$(ASM) $(ASMFLAGS) $(ASM_INCLUDES) $(PROCESSING_ASMFLAGS) $(PROCESSING_ASM_INCLUDES) -o $@ $<
--- a/test/decoder/DecUT_IdctResAddPred.cpp
+++ b/test/decoder/DecUT_IdctResAddPred.cpp
@@ -154,6 +154,10 @@
 GENERATE_IDCTRESADDPRED (IdctResAddPred_AArch64_neon, WELS_CPU_NEON)
 #endif
 
+#if defined(HAVE_MMI)
+GENERATE_IDCTRESADDPRED (IdctResAddPred_mmi, WELS_CPU_MMI)
+#endif
+
 #define GENERATE_SETNONZEROCOUNT(method, flag) \
 TEST(DecoderDecodeMbAux, method) \
 {\
--- a/test/decoder/DecUT_IntraPrediction.cpp
+++ b/test/decoder/DecUT_IntraPrediction.cpp
@@ -649,3 +649,16 @@
 GENERATE_8x8_UT (WelsDecoderIChromaPredPlane_AArch64_neon, WelsIChromaPredPlane_ref, 1, WELS_CPU_NEON)
 GENERATE_8x8_UT (WelsDecoderIChromaPredDcTop_AArch64_neon, WelsIChromaPredDcTop_ref, 1, WELS_CPU_NEON)
 #endif
+
+#if defined(HAVE_MMI)
+GENERATE_4x4_UT (WelsDecoderI4x4LumaPredH_mmi, LumaI4x4PredH, 1, WELS_CPU_MMI)
+GENERATE_8x8_UT (WelsDecoderIChromaPredDcTop_mmi, WelsIChromaPredDcTop_ref, 1, WELS_CPU_MMI)
+GENERATE_8x8_UT (WelsDecoderIChromaPredDc_mmi, WelsIChromaPredDc_ref, 1, WELS_CPU_MMI)
+GENERATE_8x8_UT (WelsDecoderIChromaPredPlane_mmi, WelsIChromaPredPlane_ref, 1, WELS_CPU_MMI)
+GENERATE_16x16_UT (WelsDecoderI16x16LumaPredPlane_mmi, WelsI16x16LumaPredPlane_ref, 1, WELS_CPU_MMI)
+GENERATE_16x16_UT (WelsDecoderI16x16LumaPredH_mmi, LumaI16x16PredH, 1, WELS_CPU_MMI)
+GENERATE_16x16_UT (WelsDecoderI16x16LumaPredV_mmi, LumaI16x16PredV, 1, WELS_CPU_MMI)
+GENERATE_16x16_UT (WelsDecoderI16x16LumaPredDc_mmi, LumaI16x16PredDC, 1, WELS_CPU_MMI)
+GENERATE_16x16_UT (WelsDecoderI16x16LumaPredDcTop_mmi, LumaI16x16PredDCTop, 1, WELS_CPU_MMI)
+GENERATE_16x16_UT (WelsDecoderI16x16LumaPredDcNA_mmi, LumaI16x16PredDCNone, 1, WELS_CPU_MMI)
+#endif
--- a/test/encoder/EncUT_EncoderMbAux.cpp
+++ b/test/encoder/EncUT_EncoderMbAux.cpp
@@ -74,6 +74,39 @@
   FREE_MEMORY (iDct);
 }
 #endif
+#ifdef HAVE_MMI
+TEST (EncodeMbAuxTest, WelsScan4x4Ac_mmi) {
+  CMemoryAlign cMemoryAlign (0);
+  ALLOC_MEMORY (int16_t, iLevelA, 16);
+  ALLOC_MEMORY (int16_t, iLevelB, 16);
+  ALLOC_MEMORY (int16_t, iDct, 16);
+  for (int i = 0; i < 16; i++) {
+    iDct[i] = rand() % 256 + 1;
+  }
+  WelsScan4x4Ac_c (iLevelA, iDct);
+  WelsScan4x4Ac_mmi (iLevelB, iDct);
+  for (int j = 0; j < 16; j++)
+    EXPECT_EQ (iLevelA[j], iLevelB[j]);
+  FREE_MEMORY (iLevelA);
+  FREE_MEMORY (iLevelB);
+  FREE_MEMORY (iDct);
+}
+TEST (EncodeMbAuxTest, WelsScan4x4DcAc_mmi) {
+  CMemoryAlign cMemoryAlign (0);
+  ALLOC_MEMORY (int16_t, iLevelA, 32);
+  ALLOC_MEMORY (int16_t, iLevelB, 32);
+  ALLOC_MEMORY (int16_t, iDct, 32);
+  for (int i = 0; i < 32; i++)
+    iDct[i] = (rand() & 32767) - 16384;
+  WelsScan4x4DcAc_mmi (iLevelA, iDct);
+  WelsScan4x4DcAc_c (iLevelB, iDct);
+  for (int i = 0; i < 16; i++)
+    EXPECT_EQ (iLevelA[i], iLevelB[i]);
+  FREE_MEMORY (iLevelA);
+  FREE_MEMORY (iLevelB);
+  FREE_MEMORY (iDct);
+}
+#endif
 TEST (EncodeMbAuxTest, TestScan_4x4_dcc) {
   CMemoryAlign cMemoryAlign (0);
   ALLOC_MEMORY (int16_t, iLevel, 16);
@@ -230,6 +263,29 @@
     iDctC[i] = iDctS[i] = (rand() & 65535) - 32768;
   WelsCalculateSingleCtr4x4_c (iDctC);
   WelsCalculateSingleCtr4x4_sse2 (iDctS);
+  for (int i = 0; i < 16; i++)
+    EXPECT_EQ (iDctC[i], iDctS[i]);
+  FREE_MEMORY (iDctC);
+  FREE_MEMORY (iDctS);
+}
+#endif
+#ifdef HAVE_MMI
+TEST (EncodeMbAuxTest, WelsDctT4_mmi) {
+  TestDctT4 (WelsDctT4_mmi);
+}
+
+TEST (EncodeMbAuxTest, WelsDctFourT4_mmi) {
+  TestDctFourT4 (WelsDctFourT4_mmi);
+}
+
+TEST (EncodeMbAuxTest, WelsCalculateSingleCtr4x4_mmi) {
+  CMemoryAlign cMemoryAlign (0);
+  ALLOC_MEMORY (int16_t, iDctC, 16);
+  ALLOC_MEMORY (int16_t, iDctS, 16);
+  for (int i = 0; i < 16; i++)
+    iDctC[i] = iDctS[i] = (rand() & 65535) - 32768;
+  WelsCalculateSingleCtr4x4_c (iDctC);
+  WelsCalculateSingleCtr4x4_mmi (iDctS);
   for (int i = 0; i < 16; i++)
     EXPECT_EQ (iDctC[i], iDctS[i]);
   FREE_MEMORY (iDctC);
--- a/test/processing/ProcessUT_VaaCalc.cpp
+++ b/test/processing/ProcessUT_VaaCalc.cpp
@@ -863,3 +863,11 @@
 GENERATE_VAACalcSadSsd_UT (VAACalcSadSsd_AArch64_neon, 1, WELS_CPU_NEON)
 GENERATE_VAACalcSadVar_UT (VAACalcSadVar_AArch64_neon, 1, WELS_CPU_NEON)
 #endif
+
+#if defined(HAVE_MMI)
+GENERATE_VAACalcSad_UT (VAACalcSad_mmi, 1, WELS_CPU_MMI)
+GENERATE_VAACalcSadBgd_UT (VAACalcSadBgd_mmi, 1, WELS_CPU_MMI)
+GENERATE_VAACalcSadSsdBgd_UT (VAACalcSadSsdBgd_mmi, 1, WELS_CPU_MMI)
+GENERATE_VAACalcSadSsd_UT (VAACalcSadSsd_mmi, 1, WELS_CPU_MMI)
+GENERATE_VAACalcSadVar_UT (VAACalcSadVar_mmi, 1, WELS_CPU_MMI)
+#endif