Uncomment the reporting for UADD32 and USUB32 in fixed_debug.h.
[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 int: %u %u in %s: line %d\n", (unsigned)a, (unsigned)b, file, line);
255    }
256    res = a+b;
257    if (!VERIFY_UINT(res))
258    {
259       fprintf (stderr, "UADD32: output is not int: %u in %s: line %d\n", (unsigned)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 int: %llu %llu in %s: line %d\n", (unsigned)a, (unsigned)b, file, line);
273    }
274    res = a-b;
275    if (!VERIFY_UINT(res))
276    {
277       fprintf (stderr, "USUB32: output is not int: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);
278    }
279    celt_mips+=2;
280    return res;
281 }
282
283 /* result fits in 16 bits */
284 static inline short MULT16_16_16(int a, int b)
285 {
286    int res;
287    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
288    {
289       fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
290    }
291    res = a*b;
292    if (!VERIFY_SHORT(res))
293       fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
294    celt_mips++;
295    return res;
296 }
297
298 #define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__)
299 static inline int MULT16_16_(int a, int b, char *file, int line)
300 {
301    long long res;
302    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
303    {
304       fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
305    }
306    res = ((long long)a)*b;
307    if (!VERIFY_INT(res))
308       fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
309    celt_mips++;
310    return res;
311 }
312
313 #define MAC16_16(c,a,b)     (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
314
315 #define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__)
316 static inline int MULT16_32_QX_(int a, long long b, int Q, char *file, int line)
317 {
318    long long res;
319    if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
320    {
321       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);
322    }
323    if (ABS32(b)>=((opus_val32)(1)<<(15+Q)))
324       fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
325    res = (((long long)a)*(long long)b) >> Q;
326    if (!VERIFY_INT(res))
327       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);
328    if (Q==15)
329       celt_mips+=3;
330    else
331       celt_mips+=4;
332    return res;
333 }
334
335 #define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
336 #define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b))))
337
338 static inline int SATURATE(int a, int b)
339 {
340    if (a>b)
341       a=b;
342    if (a<-b)
343       a = -b;
344    celt_mips+=3;
345    return a;
346 }
347
348 static inline int MULT16_16_Q11_32(int a, int b)
349 {
350    long long res;
351    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
352    {
353       fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
354    }
355    res = ((long long)a)*b;
356    res >>= 11;
357    if (!VERIFY_INT(res))
358       fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
359    celt_mips+=3;
360    return res;
361 }
362 static inline short MULT16_16_Q13(int a, int b)
363 {
364    long long res;
365    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
366    {
367       fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
368    }
369    res = ((long long)a)*b;
370    res >>= 13;
371    if (!VERIFY_SHORT(res))
372       fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
373    celt_mips+=3;
374    return res;
375 }
376 static inline short MULT16_16_Q14(int a, int b)
377 {
378    long long res;
379    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
380    {
381       fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
382    }
383    res = ((long long)a)*b;
384    res >>= 14;
385    if (!VERIFY_SHORT(res))
386       fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
387    celt_mips+=3;
388    return res;
389 }
390
391 #define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__)
392 static inline short MULT16_16_Q15_(int a, int b, char *file, int line)
393 {
394    long long res;
395    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
396    {
397       fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
398    }
399    res = ((long long)a)*b;
400    res >>= 15;
401    if (!VERIFY_SHORT(res))
402    {
403       fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line);
404    }
405    celt_mips+=1;
406    return res;
407 }
408
409 static inline short MULT16_16_P13(int a, int b)
410 {
411    long long res;
412    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
413    {
414       fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
415    }
416    res = ((long long)a)*b;
417    res += 4096;
418    if (!VERIFY_INT(res))
419       fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
420    res >>= 13;
421    if (!VERIFY_SHORT(res))
422       fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
423    celt_mips+=4;
424    return res;
425 }
426 static inline short MULT16_16_P14(int a, int b)
427 {
428    long long res;
429    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
430    {
431       fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
432    }
433    res = ((long long)a)*b;
434    res += 8192;
435    if (!VERIFY_INT(res))
436       fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
437    res >>= 14;
438    if (!VERIFY_SHORT(res))
439       fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
440    celt_mips+=4;
441    return res;
442 }
443 static inline short MULT16_16_P15(int a, int b)
444 {
445    long long res;
446    if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
447    {
448       fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
449    }
450    res = ((long long)a)*b;
451    res += 16384;
452    if (!VERIFY_INT(res))
453       fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
454    res >>= 15;
455    if (!VERIFY_SHORT(res))
456       fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
457    celt_mips+=2;
458    return res;
459 }
460
461 #define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__)
462
463 static inline int DIV32_16_(long long a, long long b, char *file, int line)
464 {
465    long long res;
466    if (b==0)
467    {
468       fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
469       return 0;
470    }
471    if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
472    {
473       fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
474    }
475    res = a/b;
476    if (!VERIFY_SHORT(res))
477    {
478       fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
479       if (res>32767)
480          res = 32767;
481       if (res<-32768)
482          res = -32768;
483    }
484    celt_mips+=35;
485    return res;
486 }
487
488 #define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__)
489 static inline int DIV32_(long long a, long long b, char *file, int line)
490 {
491    long long res;
492    if (b==0)
493    {
494       fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
495       return 0;
496    }
497
498    if (!VERIFY_INT(a) || !VERIFY_INT(b))
499    {
500       fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
501    }
502    res = a/b;
503    if (!VERIFY_INT(res))
504       fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
505    celt_mips+=70;
506    return res;
507 }
508
509 #undef PRINT_MIPS
510 #define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0);
511
512 #endif