libwebp/src/dsp/lossless_mips_dsp_r2.c
Pascal Massimino 8ea81561d2 change VP8LPredictorFunc signature to avoid reading 'left'
... when it's not available. Even if the value was discarded and
never used, some msan config were complaining about reading it
and passing it around.

Change-Id: Iab8d24676c5bb58e607a829121e36c2862da397c
2021-11-05 16:22:31 +01:00

702 lines
38 KiB
C

// Copyright 2014 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Image transforms and color space conversion methods for lossless decoder.
//
// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
#include "src/dsp/dsp.h"
#if defined(WEBP_USE_MIPS_DSP_R2)
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
#define MAP_COLOR_FUNCS(FUNC_NAME, TYPE, GET_INDEX, GET_VALUE) \
static void FUNC_NAME(const TYPE* src, \
const uint32_t* const color_map, \
TYPE* dst, int y_start, int y_end, \
int width) { \
int y; \
for (y = y_start; y < y_end; ++y) { \
int x; \
for (x = 0; x < (width >> 2); ++x) { \
int tmp1, tmp2, tmp3, tmp4; \
__asm__ volatile ( \
".ifc " #TYPE ", uint8_t \n\t" \
"lbu %[tmp1], 0(%[src]) \n\t" \
"lbu %[tmp2], 1(%[src]) \n\t" \
"lbu %[tmp3], 2(%[src]) \n\t" \
"lbu %[tmp4], 3(%[src]) \n\t" \
"addiu %[src], %[src], 4 \n\t" \
".endif \n\t" \
".ifc " #TYPE ", uint32_t \n\t" \
"lw %[tmp1], 0(%[src]) \n\t" \
"lw %[tmp2], 4(%[src]) \n\t" \
"lw %[tmp3], 8(%[src]) \n\t" \
"lw %[tmp4], 12(%[src]) \n\t" \
"ext %[tmp1], %[tmp1], 8, 8 \n\t" \
"ext %[tmp2], %[tmp2], 8, 8 \n\t" \
"ext %[tmp3], %[tmp3], 8, 8 \n\t" \
"ext %[tmp4], %[tmp4], 8, 8 \n\t" \
"addiu %[src], %[src], 16 \n\t" \
".endif \n\t" \
"sll %[tmp1], %[tmp1], 2 \n\t" \
"sll %[tmp2], %[tmp2], 2 \n\t" \
"sll %[tmp3], %[tmp3], 2 \n\t" \
"sll %[tmp4], %[tmp4], 2 \n\t" \
"lwx %[tmp1], %[tmp1](%[color_map]) \n\t" \
"lwx %[tmp2], %[tmp2](%[color_map]) \n\t" \
"lwx %[tmp3], %[tmp3](%[color_map]) \n\t" \
"lwx %[tmp4], %[tmp4](%[color_map]) \n\t" \
".ifc " #TYPE ", uint8_t \n\t" \
"ext %[tmp1], %[tmp1], 8, 8 \n\t" \
"ext %[tmp2], %[tmp2], 8, 8 \n\t" \
"ext %[tmp3], %[tmp3], 8, 8 \n\t" \
"ext %[tmp4], %[tmp4], 8, 8 \n\t" \
"sb %[tmp1], 0(%[dst]) \n\t" \
"sb %[tmp2], 1(%[dst]) \n\t" \
"sb %[tmp3], 2(%[dst]) \n\t" \
"sb %[tmp4], 3(%[dst]) \n\t" \
"addiu %[dst], %[dst], 4 \n\t" \
".endif \n\t" \
".ifc " #TYPE ", uint32_t \n\t" \
"sw %[tmp1], 0(%[dst]) \n\t" \
"sw %[tmp2], 4(%[dst]) \n\t" \
"sw %[tmp3], 8(%[dst]) \n\t" \
"sw %[tmp4], 12(%[dst]) \n\t" \
"addiu %[dst], %[dst], 16 \n\t" \
".endif \n\t" \
: [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [tmp3]"=&r"(tmp3), \
[tmp4]"=&r"(tmp4), [src]"+&r"(src), [dst]"+r"(dst) \
: [color_map]"r"(color_map) \
: "memory" \
); \
} \
for (x = 0; x < (width & 3); ++x) { \
*dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]); \
} \
} \
}
MAP_COLOR_FUNCS(MapARGB_MIPSdspR2, uint32_t, VP8GetARGBIndex, VP8GetARGBValue)
MAP_COLOR_FUNCS(MapAlpha_MIPSdspR2, uint8_t, VP8GetAlphaIndex, VP8GetAlphaValue)
#undef MAP_COLOR_FUNCS
static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
uint32_t c2) {
int temp0, temp1, temp2, temp3, temp4, temp5;
__asm__ volatile (
"preceu.ph.qbr %[temp1], %[c0] \n\t"
"preceu.ph.qbl %[temp2], %[c0] \n\t"
"preceu.ph.qbr %[temp3], %[c1] \n\t"
"preceu.ph.qbl %[temp4], %[c1] \n\t"
"preceu.ph.qbr %[temp5], %[c2] \n\t"
"preceu.ph.qbl %[temp0], %[c2] \n\t"
"subq.ph %[temp3], %[temp3], %[temp5] \n\t"
"subq.ph %[temp4], %[temp4], %[temp0] \n\t"
"addq.ph %[temp1], %[temp1], %[temp3] \n\t"
"addq.ph %[temp2], %[temp2], %[temp4] \n\t"
"shll_s.ph %[temp1], %[temp1], 7 \n\t"
"shll_s.ph %[temp2], %[temp2], 7 \n\t"
"precrqu_s.qb.ph %[temp2], %[temp2], %[temp1] \n\t"
: [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5)
: [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2)
: "memory"
);
return temp2;
}
static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
uint32_t c2) {
int temp0, temp1, temp2, temp3, temp4, temp5;
__asm__ volatile (
"adduh.qb %[temp5], %[c0], %[c1] \n\t"
"preceu.ph.qbr %[temp3], %[c2] \n\t"
"preceu.ph.qbr %[temp1], %[temp5] \n\t"
"preceu.ph.qbl %[temp2], %[temp5] \n\t"
"preceu.ph.qbl %[temp4], %[c2] \n\t"
"subq.ph %[temp3], %[temp1], %[temp3] \n\t"
"subq.ph %[temp4], %[temp2], %[temp4] \n\t"
"shrl.ph %[temp5], %[temp3], 15 \n\t"
"shrl.ph %[temp0], %[temp4], 15 \n\t"
"addq.ph %[temp3], %[temp3], %[temp5] \n\t"
"addq.ph %[temp4], %[temp0], %[temp4] \n\t"
"shra.ph %[temp3], %[temp3], 1 \n\t"
"shra.ph %[temp4], %[temp4], 1 \n\t"
"addq.ph %[temp1], %[temp1], %[temp3] \n\t"
"addq.ph %[temp2], %[temp2], %[temp4] \n\t"
"shll_s.ph %[temp1], %[temp1], 7 \n\t"
"shll_s.ph %[temp2], %[temp2], 7 \n\t"
"precrqu_s.qb.ph %[temp1], %[temp2], %[temp1] \n\t"
: [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [temp4]"=r"(temp4), [temp5]"=&r"(temp5)
: [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2)
: "memory"
);
return temp1;
}
static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
int temp0, temp1, temp2, temp3, temp4, temp5;
__asm__ volatile (
"cmpgdu.lt.qb %[temp1], %[c], %[b] \n\t"
"pick.qb %[temp1], %[b], %[c] \n\t"
"pick.qb %[temp2], %[c], %[b] \n\t"
"cmpgdu.lt.qb %[temp4], %[c], %[a] \n\t"
"pick.qb %[temp4], %[a], %[c] \n\t"
"pick.qb %[temp5], %[c], %[a] \n\t"
"subu.qb %[temp3], %[temp1], %[temp2] \n\t"
"subu.qb %[temp0], %[temp4], %[temp5] \n\t"
"raddu.w.qb %[temp3], %[temp3] \n\t"
"raddu.w.qb %[temp0], %[temp0] \n\t"
"subu %[temp3], %[temp3], %[temp0] \n\t"
"slti %[temp0], %[temp3], 0x1 \n\t"
"movz %[a], %[b], %[temp0] \n\t"
: [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
[temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp0]"=&r"(temp0),
[a]"+&r"(a)
: [b]"r"(b), [c]"r"(c)
);
return a;
}
static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
__asm__ volatile (
"adduh.qb %[a0], %[a0], %[a1] \n\t"
: [a0]"+r"(a0)
: [a1]"r"(a1)
);
return a0;
}
static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
return Average2(Average2(a0, a2), a1);
}
static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
uint32_t a2, uint32_t a3) {
return Average2(Average2(a0, a1), Average2(a2, a3));
}
static uint32_t Predictor5_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return Average3(*left, top[0], top[1]);
}
static uint32_t Predictor6_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return Average2(*left, top[-1]);
}
static uint32_t Predictor7_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return Average2(*left, top[0]);
}
static uint32_t Predictor8_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
(void)left;
return Average2(top[-1], top[0]);
}
static uint32_t Predictor9_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
(void)left;
return Average2(top[0], top[1]);
}
static uint32_t Predictor10_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return Average4(*left, top[-1], top[0], top[1]);
}
static uint32_t Predictor11_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return Select(top[0], *left, top[-1]);
}
static uint32_t Predictor12_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return ClampedAddSubtractFull(*left, top[0], top[-1]);
}
static uint32_t Predictor13_MIPSdspR2(const uint32_t* const left,
const uint32_t* const top) {
return ClampedAddSubtractHalf(*left, top[0], top[-1]);
}
// Add green to blue and red channels (i.e. perform the inverse transform of
// 'subtract green').
static void AddGreenToBlueAndRed_MIPSdspR2(const uint32_t* src, int num_pixels,
uint32_t* dst) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
const uint32_t* const p_loop2_end = src + num_pixels;
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop1_end], 3f \n\t"
" nop \n\t"
"0: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"lw %[temp1], 4(%[src]) \n\t"
"lw %[temp2], 8(%[src]) \n\t"
"lw %[temp3], 12(%[src]) \n\t"
"ext %[temp4], %[temp0], 8, 8 \n\t"
"ext %[temp5], %[temp1], 8, 8 \n\t"
"ext %[temp6], %[temp2], 8, 8 \n\t"
"ext %[temp7], %[temp3], 8, 8 \n\t"
"addiu %[src], %[src], 16 \n\t"
"addiu %[dst], %[dst], 16 \n\t"
"replv.ph %[temp4], %[temp4] \n\t"
"replv.ph %[temp5], %[temp5] \n\t"
"replv.ph %[temp6], %[temp6] \n\t"
"replv.ph %[temp7], %[temp7] \n\t"
"addu.qb %[temp0], %[temp0], %[temp4] \n\t"
"addu.qb %[temp1], %[temp1], %[temp5] \n\t"
"addu.qb %[temp2], %[temp2], %[temp6] \n\t"
"addu.qb %[temp3], %[temp3], %[temp7] \n\t"
"sw %[temp0], -16(%[dst]) \n\t"
"sw %[temp1], -12(%[dst]) \n\t"
"sw %[temp2], -8(%[dst]) \n\t"
"bne %[src], %[p_loop1_end], 0b \n\t"
" sw %[temp3], -4(%[dst]) \n\t"
"3: \n\t"
"beq %[src], %[p_loop2_end], 2f \n\t"
" nop \n\t"
"1: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"addiu %[src], %[src], 4 \n\t"
"addiu %[dst], %[dst], 4 \n\t"
"ext %[temp4], %[temp0], 8, 8 \n\t"
"replv.ph %[temp4], %[temp4] \n\t"
"addu.qb %[temp0], %[temp0], %[temp4] \n\t"
"bne %[src], %[p_loop2_end], 1b \n\t"
" sw %[temp0], -4(%[dst]) \n\t"
"2: \n\t"
".set pop \n\t"
: [dst]"+&r"(dst), [src]"+&r"(src), [temp0]"=&r"(temp0),
[temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
[temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6),
[temp7]"=&r"(temp7)
: [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
: "memory"
);
}
static void TransformColorInverse_MIPSdspR2(const VP8LMultipliers* const m,
const uint32_t* src, int num_pixels,
uint32_t* dst) {
int temp0, temp1, temp2, temp3, temp4, temp5;
uint32_t argb, argb1, new_red;
const uint32_t G_to_R = m->green_to_red_;
const uint32_t G_to_B = m->green_to_blue_;
const uint32_t R_to_B = m->red_to_blue_;
const uint32_t* const p_loop_end = src + (num_pixels & ~1);
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop_end], 1f \n\t"
" nop \n\t"
"replv.ph %[temp0], %[G_to_R] \n\t"
"replv.ph %[temp1], %[G_to_B] \n\t"
"replv.ph %[temp2], %[R_to_B] \n\t"
"shll.ph %[temp0], %[temp0], 8 \n\t"
"shll.ph %[temp1], %[temp1], 8 \n\t"
"shll.ph %[temp2], %[temp2], 8 \n\t"
"shra.ph %[temp0], %[temp0], 8 \n\t"
"shra.ph %[temp1], %[temp1], 8 \n\t"
"shra.ph %[temp2], %[temp2], 8 \n\t"
"0: \n\t"
"lw %[argb], 0(%[src]) \n\t"
"lw %[argb1], 4(%[src]) \n\t"
"sw %[argb], 0(%[dst]) \n\t"
"sw %[argb1], 4(%[dst]) \n\t"
"addiu %[src], %[src], 8 \n\t"
"addiu %[dst], %[dst], 8 \n\t"
"precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t"
"preceu.ph.qbra %[temp3], %[temp3] \n\t"
"shll.ph %[temp3], %[temp3], 8 \n\t"
"shra.ph %[temp3], %[temp3], 8 \n\t"
"mul.ph %[temp5], %[temp3], %[temp0] \n\t"
"mul.ph %[temp3], %[temp3], %[temp1] \n\t"
"precrq.ph.w %[new_red], %[argb], %[argb1] \n\t"
"ins %[argb1], %[argb], 16, 16 \n\t"
"shra.ph %[temp5], %[temp5], 5 \n\t"
"shra.ph %[temp3], %[temp3], 5 \n\t"
"addu.ph %[new_red], %[new_red], %[temp5] \n\t"
"addu.ph %[argb1], %[argb1], %[temp3] \n\t"
"preceu.ph.qbra %[temp5], %[new_red] \n\t"
"shll.ph %[temp4], %[temp5], 8 \n\t"
"shra.ph %[temp4], %[temp4], 8 \n\t"
"mul.ph %[temp4], %[temp4], %[temp2] \n\t"
"sb %[temp5], -2(%[dst]) \n\t"
"sra %[temp5], %[temp5], 16 \n\t"
"shra.ph %[temp4], %[temp4], 5 \n\t"
"addu.ph %[argb1], %[argb1], %[temp4] \n\t"
"preceu.ph.qbra %[temp3], %[argb1] \n\t"
"sb %[temp5], -6(%[dst]) \n\t"
"sb %[temp3], -4(%[dst]) \n\t"
"sra %[temp3], %[temp3], 16 \n\t"
"bne %[src], %[p_loop_end], 0b \n\t"
" sb %[temp3], -8(%[dst]) \n\t"
"1: \n\t"
".set pop \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
[new_red]"=&r"(new_red), [argb]"=&r"(argb),
[argb1]"=&r"(argb1), [dst]"+&r"(dst), [src]"+&r"(src)
: [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B),
[G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end)
: "memory", "hi", "lo"
);
// Fall-back to C-version for left-overs.
if (num_pixels & 1) VP8LTransformColorInverse_C(m, src, 1, dst);
}
static void ConvertBGRAToRGB_MIPSdspR2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
int temp0, temp1, temp2, temp3;
const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
const uint32_t* const p_loop2_end = src + num_pixels;
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop1_end], 3f \n\t"
" nop \n\t"
"0: \n\t"
"lw %[temp3], 12(%[src]) \n\t"
"lw %[temp2], 8(%[src]) \n\t"
"lw %[temp1], 4(%[src]) \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"ins %[temp3], %[temp2], 24, 8 \n\t"
"sll %[temp2], %[temp2], 8 \n\t"
"rotr %[temp3], %[temp3], 16 \n\t"
"ins %[temp2], %[temp1], 0, 16 \n\t"
"sll %[temp1], %[temp1], 8 \n\t"
"wsbh %[temp3], %[temp3] \n\t"
"balign %[temp0], %[temp1], 1 \n\t"
"wsbh %[temp2], %[temp2] \n\t"
"wsbh %[temp0], %[temp0] \n\t"
"usw %[temp3], 8(%[dst]) \n\t"
"rotr %[temp0], %[temp0], 16 \n\t"
"usw %[temp2], 4(%[dst]) \n\t"
"addiu %[src], %[src], 16 \n\t"
"usw %[temp0], 0(%[dst]) \n\t"
"bne %[src], %[p_loop1_end], 0b \n\t"
" addiu %[dst], %[dst], 12 \n\t"
"3: \n\t"
"beq %[src], %[p_loop2_end], 2f \n\t"
" nop \n\t"
"1: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"addiu %[src], %[src], 4 \n\t"
"wsbh %[temp1], %[temp0] \n\t"
"addiu %[dst], %[dst], 3 \n\t"
"ush %[temp1], -2(%[dst]) \n\t"
"sra %[temp0], %[temp0], 16 \n\t"
"bne %[src], %[p_loop2_end], 1b \n\t"
" sb %[temp0], -3(%[dst]) \n\t"
"2: \n\t"
".set pop \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
: [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
: "memory"
);
}
static void ConvertBGRAToRGBA_MIPSdspR2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
int temp0, temp1, temp2, temp3;
const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
const uint32_t* const p_loop2_end = src + num_pixels;
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop1_end], 3f \n\t"
" nop \n\t"
"0: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"lw %[temp1], 4(%[src]) \n\t"
"lw %[temp2], 8(%[src]) \n\t"
"lw %[temp3], 12(%[src]) \n\t"
"wsbh %[temp0], %[temp0] \n\t"
"wsbh %[temp1], %[temp1] \n\t"
"wsbh %[temp2], %[temp2] \n\t"
"wsbh %[temp3], %[temp3] \n\t"
"addiu %[src], %[src], 16 \n\t"
"balign %[temp0], %[temp0], 1 \n\t"
"balign %[temp1], %[temp1], 1 \n\t"
"balign %[temp2], %[temp2], 1 \n\t"
"balign %[temp3], %[temp3], 1 \n\t"
"usw %[temp0], 0(%[dst]) \n\t"
"usw %[temp1], 4(%[dst]) \n\t"
"usw %[temp2], 8(%[dst]) \n\t"
"usw %[temp3], 12(%[dst]) \n\t"
"bne %[src], %[p_loop1_end], 0b \n\t"
" addiu %[dst], %[dst], 16 \n\t"
"3: \n\t"
"beq %[src], %[p_loop2_end], 2f \n\t"
" nop \n\t"
"1: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"wsbh %[temp0], %[temp0] \n\t"
"addiu %[src], %[src], 4 \n\t"
"balign %[temp0], %[temp0], 1 \n\t"
"usw %[temp0], 0(%[dst]) \n\t"
"bne %[src], %[p_loop2_end], 1b \n\t"
" addiu %[dst], %[dst], 4 \n\t"
"2: \n\t"
".set pop \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
: [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
: "memory"
);
}
static void ConvertBGRAToRGBA4444_MIPSdspR2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
int temp0, temp1, temp2, temp3, temp4, temp5;
const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
const uint32_t* const p_loop2_end = src + num_pixels;
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop1_end], 3f \n\t"
" nop \n\t"
"0: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"lw %[temp1], 4(%[src]) \n\t"
"lw %[temp2], 8(%[src]) \n\t"
"lw %[temp3], 12(%[src]) \n\t"
"ext %[temp4], %[temp0], 28, 4 \n\t"
"ext %[temp5], %[temp0], 12, 4 \n\t"
"ins %[temp0], %[temp4], 0, 4 \n\t"
"ext %[temp4], %[temp1], 28, 4 \n\t"
"ins %[temp0], %[temp5], 16, 4 \n\t"
"ext %[temp5], %[temp1], 12, 4 \n\t"
"ins %[temp1], %[temp4], 0, 4 \n\t"
"ext %[temp4], %[temp2], 28, 4 \n\t"
"ins %[temp1], %[temp5], 16, 4 \n\t"
"ext %[temp5], %[temp2], 12, 4 \n\t"
"ins %[temp2], %[temp4], 0, 4 \n\t"
"ext %[temp4], %[temp3], 28, 4 \n\t"
"ins %[temp2], %[temp5], 16, 4 \n\t"
"ext %[temp5], %[temp3], 12, 4 \n\t"
"ins %[temp3], %[temp4], 0, 4 \n\t"
"precr.qb.ph %[temp1], %[temp1], %[temp0] \n\t"
"ins %[temp3], %[temp5], 16, 4 \n\t"
"addiu %[src], %[src], 16 \n\t"
"precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t"
#if (WEBP_SWAP_16BIT_CSP == 1)
"usw %[temp1], 0(%[dst]) \n\t"
"usw %[temp3], 4(%[dst]) \n\t"
#else
"wsbh %[temp1], %[temp1] \n\t"
"wsbh %[temp3], %[temp3] \n\t"
"usw %[temp1], 0(%[dst]) \n\t"
"usw %[temp3], 4(%[dst]) \n\t"
#endif
"bne %[src], %[p_loop1_end], 0b \n\t"
" addiu %[dst], %[dst], 8 \n\t"
"3: \n\t"
"beq %[src], %[p_loop2_end], 2f \n\t"
" nop \n\t"
"1: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"ext %[temp4], %[temp0], 28, 4 \n\t"
"ext %[temp5], %[temp0], 12, 4 \n\t"
"ins %[temp0], %[temp4], 0, 4 \n\t"
"ins %[temp0], %[temp5], 16, 4 \n\t"
"addiu %[src], %[src], 4 \n\t"
"precr.qb.ph %[temp0], %[temp0], %[temp0] \n\t"
#if (WEBP_SWAP_16BIT_CSP == 1)
"ush %[temp0], 0(%[dst]) \n\t"
#else
"wsbh %[temp0], %[temp0] \n\t"
"ush %[temp0], 0(%[dst]) \n\t"
#endif
"bne %[src], %[p_loop2_end], 1b \n\t"
" addiu %[dst], %[dst], 2 \n\t"
"2: \n\t"
".set pop \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
[dst]"+&r"(dst), [src]"+&r"(src)
: [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
: "memory"
);
}
static void ConvertBGRAToRGB565_MIPSdspR2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
int temp0, temp1, temp2, temp3, temp4, temp5;
const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
const uint32_t* const p_loop2_end = src + num_pixels;
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop1_end], 3f \n\t"
" nop \n\t"
"0: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"lw %[temp1], 4(%[src]) \n\t"
"lw %[temp2], 8(%[src]) \n\t"
"lw %[temp3], 12(%[src]) \n\t"
"ext %[temp4], %[temp0], 8, 16 \n\t"
"ext %[temp5], %[temp0], 5, 11 \n\t"
"ext %[temp0], %[temp0], 3, 5 \n\t"
"ins %[temp4], %[temp5], 0, 11 \n\t"
"ext %[temp5], %[temp1], 5, 11 \n\t"
"ins %[temp4], %[temp0], 0, 5 \n\t"
"ext %[temp0], %[temp1], 8, 16 \n\t"
"ext %[temp1], %[temp1], 3, 5 \n\t"
"ins %[temp0], %[temp5], 0, 11 \n\t"
"ext %[temp5], %[temp2], 5, 11 \n\t"
"ins %[temp0], %[temp1], 0, 5 \n\t"
"ext %[temp1], %[temp2], 8, 16 \n\t"
"ext %[temp2], %[temp2], 3, 5 \n\t"
"ins %[temp1], %[temp5], 0, 11 \n\t"
"ext %[temp5], %[temp3], 5, 11 \n\t"
"ins %[temp1], %[temp2], 0, 5 \n\t"
"ext %[temp2], %[temp3], 8, 16 \n\t"
"ext %[temp3], %[temp3], 3, 5 \n\t"
"ins %[temp2], %[temp5], 0, 11 \n\t"
"append %[temp0], %[temp4], 16 \n\t"
"ins %[temp2], %[temp3], 0, 5 \n\t"
"addiu %[src], %[src], 16 \n\t"
"append %[temp2], %[temp1], 16 \n\t"
#if (WEBP_SWAP_16BIT_CSP == 1)
"usw %[temp0], 0(%[dst]) \n\t"
"usw %[temp2], 4(%[dst]) \n\t"
#else
"wsbh %[temp0], %[temp0] \n\t"
"wsbh %[temp2], %[temp2] \n\t"
"usw %[temp0], 0(%[dst]) \n\t"
"usw %[temp2], 4(%[dst]) \n\t"
#endif
"bne %[src], %[p_loop1_end], 0b \n\t"
" addiu %[dst], %[dst], 8 \n\t"
"3: \n\t"
"beq %[src], %[p_loop2_end], 2f \n\t"
" nop \n\t"
"1: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"ext %[temp4], %[temp0], 8, 16 \n\t"
"ext %[temp5], %[temp0], 5, 11 \n\t"
"ext %[temp0], %[temp0], 3, 5 \n\t"
"ins %[temp4], %[temp5], 0, 11 \n\t"
"addiu %[src], %[src], 4 \n\t"
"ins %[temp4], %[temp0], 0, 5 \n\t"
#if (WEBP_SWAP_16BIT_CSP == 1)
"ush %[temp4], 0(%[dst]) \n\t"
#else
"wsbh %[temp4], %[temp4] \n\t"
"ush %[temp4], 0(%[dst]) \n\t"
#endif
"bne %[src], %[p_loop2_end], 1b \n\t"
" addiu %[dst], %[dst], 2 \n\t"
"2: \n\t"
".set pop \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
[dst]"+&r"(dst), [src]"+&r"(src)
: [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
: "memory"
);
}
static void ConvertBGRAToBGR_MIPSdspR2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
int temp0, temp1, temp2, temp3;
const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
const uint32_t* const p_loop2_end = src + num_pixels;
__asm__ volatile (
".set push \n\t"
".set noreorder \n\t"
"beq %[src], %[p_loop1_end], 3f \n\t"
" nop \n\t"
"0: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"lw %[temp1], 4(%[src]) \n\t"
"lw %[temp2], 8(%[src]) \n\t"
"lw %[temp3], 12(%[src]) \n\t"
"ins %[temp0], %[temp1], 24, 8 \n\t"
"sra %[temp1], %[temp1], 8 \n\t"
"ins %[temp1], %[temp2], 16, 16 \n\t"
"sll %[temp2], %[temp2], 8 \n\t"
"balign %[temp3], %[temp2], 1 \n\t"
"addiu %[src], %[src], 16 \n\t"
"usw %[temp0], 0(%[dst]) \n\t"
"usw %[temp1], 4(%[dst]) \n\t"
"usw %[temp3], 8(%[dst]) \n\t"
"bne %[src], %[p_loop1_end], 0b \n\t"
" addiu %[dst], %[dst], 12 \n\t"
"3: \n\t"
"beq %[src], %[p_loop2_end], 2f \n\t"
" nop \n\t"
"1: \n\t"
"lw %[temp0], 0(%[src]) \n\t"
"addiu %[src], %[src], 4 \n\t"
"addiu %[dst], %[dst], 3 \n\t"
"ush %[temp0], -3(%[dst]) \n\t"
"sra %[temp0], %[temp0], 16 \n\t"
"bne %[src], %[p_loop2_end], 1b \n\t"
" sb %[temp0], -1(%[dst]) \n\t"
"2: \n\t"
".set pop \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
: [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
: "memory"
);
}
//------------------------------------------------------------------------------
// Entry point
extern void VP8LDspInitMIPSdspR2(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitMIPSdspR2(void) {
VP8LMapColor32b = MapARGB_MIPSdspR2;
VP8LMapColor8b = MapAlpha_MIPSdspR2;
VP8LPredictors[5] = Predictor5_MIPSdspR2;
VP8LPredictors[6] = Predictor6_MIPSdspR2;
VP8LPredictors[7] = Predictor7_MIPSdspR2;
VP8LPredictors[8] = Predictor8_MIPSdspR2;
VP8LPredictors[9] = Predictor9_MIPSdspR2;
VP8LPredictors[10] = Predictor10_MIPSdspR2;
VP8LPredictors[11] = Predictor11_MIPSdspR2;
VP8LPredictors[12] = Predictor12_MIPSdspR2;
VP8LPredictors[13] = Predictor13_MIPSdspR2;
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_MIPSdspR2;
VP8LTransformColorInverse = TransformColorInverse_MIPSdspR2;
VP8LConvertBGRAToRGB = ConvertBGRAToRGB_MIPSdspR2;
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_MIPSdspR2;
VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_MIPSdspR2;
VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_MIPSdspR2;
VP8LConvertBGRAToBGR = ConvertBGRAToBGR_MIPSdspR2;
}
#else // !WEBP_USE_MIPS_DSP_R2
WEBP_DSP_INIT_STUB(VP8LDspInitMIPSdspR2)
#endif // WEBP_USE_MIPS_DSP_R2