0a1adf4c35dd300dfb587962797441be1eca1ba7
[opus.git] / celt / fixed_debug.h
1 /* Copyright (C) 2003-2008 Jean-Marc Valin
2    Copyright (C) 2007-2009 Xiph.Org Foundation */
3 /**
4    @file fixed_debug.h
5    @brief Fixed-point operations with debugging
6 */
7 /*
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions
10    are met:
11
12    - Redistributions of source code must retain the above copyright
13    notice, this list of conditions and the following disclaimer.
14
15    - Redistributions in binary form must reproduce the above copyright
16    notice, this list of conditions and the following disclaimer in the
17    documentation and/or other materials provided with the distribution.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef FIXED_DEBUG_H
33 #define FIXED_DEBUG_H
34
35 #include <stdio.h>
36
37 #ifdef CELT_C
38 #include "opus_defines.h"
39 OPUS_EXPORT long long celt_mips=0;
40 #else
41 extern long long celt_mips;
42 #endif
43
44 #define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
45 #define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15))
46
47 /** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
48 #define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16))
49
50 #define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
51 #define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
52
53 #define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
54 #define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
55 #define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1))
56
57 #define SHR(a,b) SHR32(a,b)
58 #define PSHR(a,b) PSHR32(a,b)
59
60 static inline short NEG16(int x)
61 {
62    int res;
63    if (!VERIFY_SHORT(x))
64    {
65       fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
66    }
67    res = -x;
68    if (!VERIFY_SHORT(res))
69       fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
70    celt_mips++;
71    return res;
72 }
73 static inline int NEG32(long long x)
74 {
75    long long res;
76    if (!VERIFY_INT(x))
77    {
78       fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
79    }
80    res = -x;
81    if (!VERIFY_INT(res))
82       fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
83    celt_mips+=2;
84    return res;
85 }
86
87 #define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__)
88 static inline short EXTRACT16_(int x, char *file, int line)
89 {
90    int res;
91    if (!VERIFY_SHORT(x))
92    {
93       fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
94    }
95    res = x;
96    celt_mips++;
97    return res;
98 }
99
100 #define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__)
101 static inline int EXTEND32_(int x, char *file, int line)
102 {
103    int res;
104    if (!VERIFY_SHORT(x))
105    {
106       fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
107    }
108    res = x;
109    celt_mips++;
110    return res;
111 }
112
113 #define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__)
114 static inline short SHR16_(int a, int shift, char *file, int line)
115 {
116    int res;
117    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
118    {
119       fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
120    }
121    res = a>>shift;
122    if (!VERIFY_SHORT(res))
123       fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
124    celt_mips++;
125    return res;
126 }
127 #define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__)
128 static inline short SHL16_(int a, int shift, char *file, int line)
129 {
130    int res;
131    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
132    {
133       fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
134    }
135    res = a<<shift;
136    if (!VERIFY_SHORT(res))
137       fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
138    celt_mips++;
139    return res;
140 }
141
142 static inline int SHR32(long long a, int shift)
143 {
144    long long  res;
145    if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
146    {
147       fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
148    }
149    res = a>>shift;
150    if (!VERIFY_INT(res))
151    {
152       fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
153    }
154    celt_mips+=2;
155    return res;
156 }
157 static inline int SHL32(long long a, int shift)
158 {
159    long long  res;
160    if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
161    {
162       fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift);
163    }
164    res = a<<shift;
165    if (!VERIFY_INT(res))
166    {
167       fprintf (stderr, "SHL32: output is not int: %d\n", (int)res);
168    }
169    celt_mips+=2;
170    return res;
171 }
172
173 #define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((opus_val32)(1)<<((shift))>>1))),shift))
174 #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
175
176 #define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
177 #define HALF16(x)  (SHR16(x,1))
178 #define HALF32(x)  (SHR32(x,1))
179
180 //#define SHR(a,shift) ((a) >> (shift))
181 //#define SHL(a,shift) ((a) << (shift))
182
183 #define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__)
184 static inline short ADD16_(int a, int b, char *file, int line)
185 {
186    int res;
187    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
188    {
189       fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
190    }
191    res = a+b;
192    if (!VERIFY_SHORT(res))
193    {
194       fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
195    }
196    celt_mips++;
197    return res;
198 }
199
200 #define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__)
201 static inline short SUB16_(int a, int b, char *file, int line)
202 {
203    int res;
204    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
205    {
206       fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
207    }
208    res = a-b;
209    if (!VERIFY_SHORT(res))
210       fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
211    celt_mips++;
212    return res;
213 }
214
215 #define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__)
216 static inline int ADD32_(long long a, long long b, char *file, int line)
217 {
218    long long res;
219    if (!VERIFY_INT(a) || !VERIFY_INT(b))
220    {
221       fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
222    }
223    res = a+b;
224    if (!VERIFY_INT(res))
225    {
226       fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
227    }
228    celt_mips+=2;
229    return res;
230 }
231
232 #define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__)
233 static inline int SUB32_(long long a, long long b, char *file, int line)
234 {
235    long long res;
236    if (!VERIFY_INT(a) || !VERIFY_INT(b))
237    {
238       fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
239    }
240    res = a-b;
241    if (!VERIFY_INT(res))
242       fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line);
243    celt_mips+=2;
244    return res;
245 }
246
247 #undef UADD32
248 #define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__)
249 static inline unsigned int UADD32_(unsigned long long a, unsigned long long b, char *file, int line)
250 {
251    unsigned long long res;
252    if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
253    {
254       fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
255    }
256    res = a+b;
257    if (!VERIFY_UINT(res))
258    {
259       fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line);
260    }
261    celt_mips+=2;
262    return res;
263 }
264
265 #undef USUB32
266 #define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__)
267 static inline unsigned int USUB32_(unsigned long long a, unsigned long long b, char *file, int line)
268 {
269    unsigned long long res;
270    if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
271    {
272       fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
273    }
274    if (a<b)
275    {
276       fprintf (stderr, "USUB32: inputs underflow: %llu < %llu in %s: line %d\n", a, b, file, line);
277    }
278    res = a-b;
279    if (!VERIFY_UINT(res))
280    {
281       fprintf (stderr, "USUB32: output is not uint32: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);
282    }
283    celt_mips+=2;
284    return res;
285 }
286
287 /* result fits in 16 bits */
288 static inline short MULT16_16_16(int a, int b)
289 {
290    int res;
291    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
292    {
293       fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
294    }
295    res = a*b;
296    if (!VERIFY_SHORT(res))
297       fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
298    celt_mips++;
299    return res;
300 }
301
302 #define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__)
303 static inline int MULT16_16_(int a, int b, char *file, int line)
304 {
305    long long res;
306    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
307    {
308       fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
309    }
310    res = ((long long)a)*b;
311    if (!VERIFY_INT(res))
312       fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
313    celt_mips++;
314    return res;
315 }
316
317 #define MAC16_16(c,a,b)     (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
318
319 #define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__)
320 static inline int MULT16_32_QX_(int a, long long b, int Q, char *file, int line)
321 {
322    long long res;
323    if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
324    {
325       fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
326    }
327    if (ABS32(b)>=((opus_val32)(1)<<(15+Q)))
328       fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
329    res = (((long long)a)*(long long)b) >> Q;
330    if (!VERIFY_INT(res))
331       fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
332    if (Q==15)
333       celt_mips+=3;
334    else
335       celt_mips+=4;
336    return res;
337 }
338
339 #define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
340 #define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b))))
341
342 static inline int SATURATE(int a, int b)
343 {
344    if (a>b)
345       a=b;
346    if (a<-b)
347       a = -b;
348    celt_mips+=3;
349    return a;
350 }
351
352 static inline int MULT16_16_Q11_32(int a, int b)
353 {
354    long long res;
355    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
356    {
357       fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
358    }
359    res = ((long long)a)*b;
360    res >>= 11;
361    if (!VERIFY_INT(res))
362       fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
363    celt_mips+=3;
364    return res;
365 }
366 static inline short MULT16_16_Q13(int a, int b)
367 {
368    long long res;
369    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
370    {
371       fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
372    }
373    res = ((long long)a)*b;
374    res >>= 13;
375    if (!VERIFY_SHORT(res))
376       fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
377    celt_mips+=3;
378    return res;
379 }
380 static inline short MULT16_16_Q14(int a, int b)
381 {
382    long long res;
383    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
384    {
385       fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
386    }
387    res = ((long long)a)*b;
388    res >>= 14;
389    if (!VERIFY_SHORT(res))
390       fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
391    celt_mips+=3;
392    return res;
393 }
394
395 #define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__)
396 static inline short MULT16_16_Q15_(int a, int b, char *file, int line)
397 {
398    long long res;
399    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
400    {
401       fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
402    }
403    res = ((long long)a)*b;
404    res >>= 15;
405    if (!VERIFY_SHORT(res))
406    {
407       fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line);
408    }
409    celt_mips+=1;
410    return res;
411 }
412
413 static inline short MULT16_16_P13(int a, int b)
414 {
415    long long res;
416    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
417    {
418       fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
419    }
420    res = ((long long)a)*b;
421    res += 4096;
422    if (!VERIFY_INT(res))
423       fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
424    res >>= 13;
425    if (!VERIFY_SHORT(res))
426       fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
427    celt_mips+=4;
428    return res;
429 }
430 static inline short MULT16_16_P14(int a, int b)
431 {
432    long long res;
433    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
434    {
435       fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
436    }
437    res = ((long long)a)*b;
438    res += 8192;
439    if (!VERIFY_INT(res))
440       fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
441    res >>= 14;
442    if (!VERIFY_SHORT(res))
443       fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
444    celt_mips+=4;
445    return res;
446 }
447 static inline short MULT16_16_P15(int a, int b)
448 {
449    long long res;
450    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
451    {
452       fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
453    }
454    res = ((long long)a)*b;
455    res += 16384;
456    if (!VERIFY_INT(res))
457       fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
458    res >>= 15;
459    if (!VERIFY_SHORT(res))
460       fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
461    celt_mips+=2;
462    return res;
463 }
464
465 #define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__)
466
467 static inline int DIV32_16_(long long a, long long b, char *file, int line)
468 {
469    long long res;
470    if (b==0)
471    {
472       fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
473       return 0;
474    }
475    if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
476    {
477       fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
478    }
479    res = a/b;
480    if (!VERIFY_SHORT(res))
481    {
482       fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
483       if (res>32767)
484          res = 32767;
485       if (res<-32768)
486          res = -32768;
487    }
488    celt_mips+=35;
489    return res;
490 }
491
492 #define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__)
493 static inline int DIV32_(long long a, long long b, char *file, int line)
494 {
495    long long res;
496    if (b==0)
497    {
498       fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
499       return 0;
500    }
501
502    if (!VERIFY_INT(a) || !VERIFY_INT(b))
503    {
504       fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
505    }
506    res = a/b;
507    if (!VERIFY_INT(res))
508       fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
509    celt_mips+=70;
510    return res;
511 }
512
513 #undef PRINT_MIPS
514 #define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0);
515
516 #endif