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