Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / libwebp / dsp / lossless_mips32.c
blob1308580790294f06d83194c158671a436262ea42
1 // Copyright 2014 Google Inc. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 // -----------------------------------------------------------------------------
9 //
10 // MIPS version of lossless functions
12 // Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
13 // Jovan Zelincevic (jovan.zelincevic@imgtec.com)
15 #include "./dsp.h"
16 #include "./lossless.h"
18 #if defined(WEBP_USE_MIPS32)
20 #include <assert.h>
21 #include <math.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #define APPROX_LOG_WITH_CORRECTION_MAX 65536
26 #define APPROX_LOG_MAX 4096
27 #define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
29 static float FastSLog2Slow(uint32_t v) {
30 assert(v >= LOG_LOOKUP_IDX_MAX);
31 if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
32 uint32_t log_cnt, y, correction;
33 const int c24 = 24;
34 const float v_f = (float)v;
35 uint32_t temp;
37 // Xf = 256 = 2^8
38 // log_cnt is index of leading one in upper 24 bits
39 __asm__ volatile(
40 "clz %[log_cnt], %[v] \n\t"
41 "addiu %[y], $zero, 1 \n\t"
42 "subu %[log_cnt], %[c24], %[log_cnt] \n\t"
43 "sllv %[y], %[y], %[log_cnt] \n\t"
44 "srlv %[temp], %[v], %[log_cnt] \n\t"
45 : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y),
46 [temp]"=r"(temp)
47 : [c24]"r"(c24), [v]"r"(v)
50 // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
51 // Xf = floor(Xf) * (1 + (v % y) / v)
52 // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
53 // The correction factor: log(1 + d) ~ d; for very small d values, so
54 // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v
55 // LOG_2_RECIPROCAL ~ 23/16
57 // (v % y) = (v % 2^log_cnt) = v & (2^log_cnt - 1)
58 correction = (23 * (v & (y - 1))) >> 4;
59 return v_f * (kLog2Table[temp] + log_cnt) + correction;
60 } else {
61 return (float)(LOG_2_RECIPROCAL * v * log((double)v));
65 static float FastLog2Slow(uint32_t v) {
66 assert(v >= LOG_LOOKUP_IDX_MAX);
67 if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
68 uint32_t log_cnt, y;
69 const int c24 = 24;
70 double log_2;
71 uint32_t temp;
73 __asm__ volatile(
74 "clz %[log_cnt], %[v] \n\t"
75 "addiu %[y], $zero, 1 \n\t"
76 "subu %[log_cnt], %[c24], %[log_cnt] \n\t"
77 "sllv %[y], %[y], %[log_cnt] \n\t"
78 "srlv %[temp], %[v], %[log_cnt] \n\t"
79 : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y),
80 [temp]"=r"(temp)
81 : [c24]"r"(c24), [v]"r"(v)
84 log_2 = kLog2Table[temp] + log_cnt;
85 if (v >= APPROX_LOG_MAX) {
86 // Since the division is still expensive, add this correction factor only
87 // for large values of 'v'.
89 const uint32_t correction = (23 * (v & (y - 1))) >> 4;
90 log_2 += (double)correction / v;
92 return (float)log_2;
93 } else {
94 return (float)(LOG_2_RECIPROCAL * log((double)v));
98 // C version of this function:
99 // int i = 0;
100 // int64_t cost = 0;
101 // const uint32_t* pop = &population[4];
102 // const uint32_t* LoopEnd = &population[length];
103 // while (pop != LoopEnd) {
104 // ++i;
105 // cost += i * *pop;
106 // cost += i * *(pop + 1);
107 // pop += 2;
108 // }
109 // return (double)cost;
110 static double ExtraCost(const uint32_t* const population, int length) {
111 int i, temp0, temp1;
112 const uint32_t* pop = &population[4];
113 const uint32_t* const LoopEnd = &population[length];
115 __asm__ volatile(
116 "mult $zero, $zero \n\t"
117 "xor %[i], %[i], %[i] \n\t"
118 "beq %[pop], %[LoopEnd], 2f \n\t"
119 "1: \n\t"
120 "lw %[temp0], 0(%[pop]) \n\t"
121 "lw %[temp1], 4(%[pop]) \n\t"
122 "addiu %[i], %[i], 1 \n\t"
123 "addiu %[pop], %[pop], 8 \n\t"
124 "madd %[i], %[temp0] \n\t"
125 "madd %[i], %[temp1] \n\t"
126 "bne %[pop], %[LoopEnd], 1b \n\t"
127 "2: \n\t"
128 "mfhi %[temp0] \n\t"
129 "mflo %[temp1] \n\t"
130 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
131 [i]"=&r"(i), [pop]"+r"(pop)
132 : [LoopEnd]"r"(LoopEnd)
133 : "memory", "hi", "lo"
136 return (double)((int64_t)temp0 << 32 | temp1);
139 // C version of this function:
140 // int i = 0;
141 // int64_t cost = 0;
142 // const uint32_t* pX = &X[4];
143 // const uint32_t* pY = &Y[4];
144 // const uint32_t* LoopEnd = &X[length];
145 // while (pX != LoopEnd) {
146 // const uint32_t xy0 = *pX + *pY;
147 // const uint32_t xy1 = *(pX + 1) + *(pY + 1);
148 // ++i;
149 // cost += i * xy0;
150 // cost += i * xy1;
151 // pX += 2;
152 // pY += 2;
153 // }
154 // return (double)cost;
155 static double ExtraCostCombined(const uint32_t* const X,
156 const uint32_t* const Y, int length) {
157 int i, temp0, temp1, temp2, temp3;
158 const uint32_t* pX = &X[4];
159 const uint32_t* pY = &Y[4];
160 const uint32_t* const LoopEnd = &X[length];
162 __asm__ volatile(
163 "mult $zero, $zero \n\t"
164 "xor %[i], %[i], %[i] \n\t"
165 "beq %[pX], %[LoopEnd], 2f \n\t"
166 "1: \n\t"
167 "lw %[temp0], 0(%[pX]) \n\t"
168 "lw %[temp1], 0(%[pY]) \n\t"
169 "lw %[temp2], 4(%[pX]) \n\t"
170 "lw %[temp3], 4(%[pY]) \n\t"
171 "addiu %[i], %[i], 1 \n\t"
172 "addu %[temp0], %[temp0], %[temp1] \n\t"
173 "addu %[temp2], %[temp2], %[temp3] \n\t"
174 "addiu %[pX], %[pX], 8 \n\t"
175 "addiu %[pY], %[pY], 8 \n\t"
176 "madd %[i], %[temp0] \n\t"
177 "madd %[i], %[temp2] \n\t"
178 "bne %[pX], %[LoopEnd], 1b \n\t"
179 "2: \n\t"
180 "mfhi %[temp0] \n\t"
181 "mflo %[temp1] \n\t"
182 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
183 [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
184 [i]"=&r"(i), [pX]"+r"(pX), [pY]"+r"(pY)
185 : [LoopEnd]"r"(LoopEnd)
186 : "memory", "hi", "lo"
189 return (double)((int64_t)temp0 << 32 | temp1);
192 #define HUFFMAN_COST_PASS \
193 __asm__ volatile( \
194 "sll %[temp1], %[temp0], 3 \n\t" \
195 "addiu %[temp3], %[streak], -3 \n\t" \
196 "addu %[temp2], %[pstreaks], %[temp1] \n\t" \
197 "blez %[temp3], 1f \n\t" \
198 "srl %[temp1], %[temp1], 1 \n\t" \
199 "addu %[temp3], %[pcnts], %[temp1] \n\t" \
200 "lw %[temp0], 4(%[temp2]) \n\t" \
201 "lw %[temp1], 0(%[temp3]) \n\t" \
202 "addu %[temp0], %[temp0], %[streak] \n\t" \
203 "addiu %[temp1], %[temp1], 1 \n\t" \
204 "sw %[temp0], 4(%[temp2]) \n\t" \
205 "sw %[temp1], 0(%[temp3]) \n\t" \
206 "b 2f \n\t" \
207 "1: \n\t" \
208 "lw %[temp0], 0(%[temp2]) \n\t" \
209 "addu %[temp0], %[temp0], %[streak] \n\t" \
210 "sw %[temp0], 0(%[temp2]) \n\t" \
211 "2: \n\t" \
212 : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \
213 [temp3]"=&r"(temp3), [temp0]"+r"(temp0) \
214 : [pstreaks]"r"(pstreaks), [pcnts]"r"(pcnts), \
215 [streak]"r"(streak) \
216 : "memory" \
219 // Returns the various RLE counts
220 static VP8LStreaks HuffmanCostCount(const uint32_t* population, int length) {
221 int i;
222 int streak = 0;
223 VP8LStreaks stats;
224 int* const pstreaks = &stats.streaks[0][0];
225 int* const pcnts = &stats.counts[0];
226 int temp0, temp1, temp2, temp3;
227 memset(&stats, 0, sizeof(stats));
228 for (i = 0; i < length - 1; ++i) {
229 ++streak;
230 if (population[i] == population[i + 1]) {
231 continue;
233 temp0 = (population[i] != 0);
234 HUFFMAN_COST_PASS
235 streak = 0;
237 ++streak;
238 temp0 = (population[i] != 0);
239 HUFFMAN_COST_PASS
241 return stats;
244 static VP8LStreaks HuffmanCostCombinedCount(const uint32_t* X,
245 const uint32_t* Y, int length) {
246 int i;
247 int streak = 0;
248 VP8LStreaks stats;
249 int* const pstreaks = &stats.streaks[0][0];
250 int* const pcnts = &stats.counts[0];
251 int temp0, temp1, temp2, temp3;
252 memset(&stats, 0, sizeof(stats));
253 for (i = 0; i < length - 1; ++i) {
254 const uint32_t xy = X[i] + Y[i];
255 const uint32_t xy_next = X[i + 1] + Y[i + 1];
256 ++streak;
257 if (xy == xy_next) {
258 continue;
260 temp0 = (xy != 0);
261 HUFFMAN_COST_PASS
262 streak = 0;
265 const uint32_t xy = X[i] + Y[i];
266 ++streak;
267 temp0 = (xy != 0);
268 HUFFMAN_COST_PASS
271 return stats;
274 #define ASM_START \
275 __asm__ volatile( \
276 ".set push \n\t" \
277 ".set at \n\t" \
278 ".set macro \n\t" \
279 "1: \n\t"
281 // P2 = P0 + P1
282 // A..D - offsets
283 // E - temp variable to tell macro
284 // if pointer should be incremented
285 // literal_ and successive histograms could be unaligned
286 // so we must use ulw and usw
287 #define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \
288 "ulw %[temp0], "#A"(%["#P0"]) \n\t" \
289 "ulw %[temp1], "#B"(%["#P0"]) \n\t" \
290 "ulw %[temp2], "#C"(%["#P0"]) \n\t" \
291 "ulw %[temp3], "#D"(%["#P0"]) \n\t" \
292 "ulw %[temp4], "#A"(%["#P1"]) \n\t" \
293 "ulw %[temp5], "#B"(%["#P1"]) \n\t" \
294 "ulw %[temp6], "#C"(%["#P1"]) \n\t" \
295 "ulw %[temp7], "#D"(%["#P1"]) \n\t" \
296 "addu %[temp4], %[temp4], %[temp0] \n\t" \
297 "addu %[temp5], %[temp5], %[temp1] \n\t" \
298 "addu %[temp6], %[temp6], %[temp2] \n\t" \
299 "addu %[temp7], %[temp7], %[temp3] \n\t" \
300 "addiu %["#P0"], %["#P0"], 16 \n\t" \
301 ".if "#E" == 1 \n\t" \
302 "addiu %["#P1"], %["#P1"], 16 \n\t" \
303 ".endif \n\t" \
304 "usw %[temp4], "#A"(%["#P2"]) \n\t" \
305 "usw %[temp5], "#B"(%["#P2"]) \n\t" \
306 "usw %[temp6], "#C"(%["#P2"]) \n\t" \
307 "usw %[temp7], "#D"(%["#P2"]) \n\t" \
308 "addiu %["#P2"], %["#P2"], 16 \n\t" \
309 "bne %["#P0"], %[LoopEnd], 1b \n\t" \
310 ".set pop \n\t" \
312 #define ASM_END_COMMON_0 \
313 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \
314 [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \
315 [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \
316 [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), \
317 [pa]"+r"(pa), [pout]"+r"(pout)
319 #define ASM_END_COMMON_1 \
320 : [LoopEnd]"r"(LoopEnd) \
321 : "memory", "at" \
324 #define ASM_END_0 \
325 ASM_END_COMMON_0 \
326 , [pb]"+r"(pb) \
327 ASM_END_COMMON_1
329 #define ASM_END_1 \
330 ASM_END_COMMON_0 \
331 ASM_END_COMMON_1
333 #define ADD_VECTOR(A, B, OUT, SIZE, EXTRA_SIZE) do { \
334 const uint32_t* pa = (const uint32_t*)(A); \
335 const uint32_t* pb = (const uint32_t*)(B); \
336 uint32_t* pout = (uint32_t*)(OUT); \
337 const uint32_t* const LoopEnd = pa + (SIZE); \
338 assert((SIZE) % 4 == 0); \
339 ASM_START \
340 ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) \
341 ASM_END_0 \
342 if ((EXTRA_SIZE) > 0) { \
343 const int last = (EXTRA_SIZE); \
344 int i; \
345 for (i = 0; i < last; ++i) pout[i] = pa[i] + pb[i]; \
347 } while (0)
349 #define ADD_VECTOR_EQ(A, OUT, SIZE, EXTRA_SIZE) do { \
350 const uint32_t* pa = (const uint32_t*)(A); \
351 uint32_t* pout = (uint32_t*)(OUT); \
352 const uint32_t* const LoopEnd = pa + (SIZE); \
353 assert((SIZE) % 4 == 0); \
354 ASM_START \
355 ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) \
356 ASM_END_1 \
357 if ((EXTRA_SIZE) > 0) { \
358 const int last = (EXTRA_SIZE); \
359 int i; \
360 for (i = 0; i < last; ++i) pout[i] += pa[i]; \
362 } while (0)
364 static void HistogramAdd(const VP8LHistogram* const a,
365 const VP8LHistogram* const b,
366 VP8LHistogram* const out) {
367 uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
368 const int extra_cache_size = VP8LHistogramNumCodes(a->palette_code_bits_)
369 - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
370 assert(a->palette_code_bits_ == b->palette_code_bits_);
372 if (b != out) {
373 ADD_VECTOR(a->literal_, b->literal_, out->literal_,
374 NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
375 ADD_VECTOR(a->distance_, b->distance_, out->distance_,
376 NUM_DISTANCE_CODES, 0);
377 ADD_VECTOR(a->red_, b->red_, out->red_, NUM_LITERAL_CODES, 0);
378 ADD_VECTOR(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES, 0);
379 ADD_VECTOR(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
380 } else {
381 ADD_VECTOR_EQ(a->literal_, out->literal_,
382 NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
383 ADD_VECTOR_EQ(a->distance_, out->distance_, NUM_DISTANCE_CODES, 0);
384 ADD_VECTOR_EQ(a->red_, out->red_, NUM_LITERAL_CODES, 0);
385 ADD_VECTOR_EQ(a->blue_, out->blue_, NUM_LITERAL_CODES, 0);
386 ADD_VECTOR_EQ(a->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
390 #undef ADD_VECTOR_EQ
391 #undef ADD_VECTOR
392 #undef ASM_END_1
393 #undef ASM_END_0
394 #undef ASM_END_COMMON_1
395 #undef ASM_END_COMMON_0
396 #undef ADD_TO_OUT
397 #undef ASM_START
399 #endif // WEBP_USE_MIPS32
401 //------------------------------------------------------------------------------
402 // Entry point
404 extern void VP8LDspInitMIPS32(void);
406 void VP8LDspInitMIPS32(void) {
407 #if defined(WEBP_USE_MIPS32)
408 VP8LFastSLog2Slow = FastSLog2Slow;
409 VP8LFastLog2Slow = FastLog2Slow;
410 VP8LExtraCost = ExtraCost;
411 VP8LExtraCostCombined = ExtraCostCombined;
412 VP8LHuffmanCostCount = HuffmanCostCount;
413 VP8LHuffmanCostCombinedCount = HuffmanCostCombinedCount;
414 VP8LHistogramAdd = HistogramAdd;
415 #endif // WEBP_USE_MIPS32