cbe7557987c561f625b0ed9546b06e93f76d55cc
[opus.git] / celt / _kiss_fft_guts.h
1 /*Copyright (c) 2003-2004, Mark Borgerding
2
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions are met:
7
8     * Redistributions of source code must retain the above copyright notice,
9        this list of conditions and the following disclaimer.
10     * Redistributions in binary form must reproduce the above copyright notice,
11        this list of conditions and the following disclaimer in the
12        documentation and/or other materials provided with the distribution.
13
14   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   POSSIBILITY OF SUCH DAMAGE.*/
25
26 #ifndef KISS_FFT_GUTS_H
27 #define KISS_FFT_GUTS_H
28
29 #define MIN(a,b) ((a)<(b) ? (a):(b))
30 #define MAX(a,b) ((a)>(b) ? (a):(b))
31
32 /* kiss_fft.h
33    defines kiss_fft_scalar as either short or a float type
34    and defines
35    typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
36 #include "kiss_fft.h"
37
38 /*
39   Explanation of macros dealing with complex math:
40
41    C_MUL(m,a,b)         : m = a*b
42    C_FIXDIV( c , div )  : if a fixed point impl., c /= div. noop otherwise
43    C_SUB( res, a,b)     : res = a - b
44    C_SUBFROM( res , a)  : res -= a
45    C_ADDTO( res , a)    : res += a
46  * */
47 #ifdef FIXED_POINT
48 #include "arch.h"
49
50
51 #define SAMP_MAX 2147483647
52 #define TWID_MAX 32767
53 #define TRIG_UPSCALE 1
54
55 #define SAMP_MIN -SAMP_MAX
56
57
58 #   define S_MUL(a,b) MULT16_32_Q15(b, a)
59
60 #   define C_MUL(m,a,b) \
61       do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
62           (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
63
64 #   define C_MULC(m,a,b) \
65       do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
66           (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
67
68 #   define C_MUL4(m,a,b) \
69       do{ (m).r = SHR32(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \
70           (m).i = SHR32(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0)
71
72 #   define C_MULBYSCALAR( c, s ) \
73       do{ (c).r =  S_MUL( (c).r , s ) ;\
74           (c).i =  S_MUL( (c).i , s ) ; }while(0)
75
76 #   define DIVSCALAR(x,k) \
77         (x) = S_MUL(  x, (TWID_MAX-((k)>>1))/(k)+1 )
78
79 #   define C_FIXDIV(c,div) \
80         do {    DIVSCALAR( (c).r , div);  \
81                 DIVSCALAR( (c).i  , div); }while (0)
82
83 #define  C_ADD( res, a,b)\
84     do {(res).r=ADD32((a).r,(b).r);  (res).i=ADD32((a).i,(b).i); \
85     }while(0)
86 #define  C_SUB( res, a,b)\
87     do {(res).r=SUB32((a).r,(b).r);  (res).i=SUB32((a).i,(b).i); \
88     }while(0)
89 #define C_ADDTO( res , a)\
90     do {(res).r = ADD32((res).r, (a).r);  (res).i = ADD32((res).i,(a).i);\
91     }while(0)
92
93 #define C_SUBFROM( res , a)\
94     do {(res).r = ADD32((res).r,(a).r);  (res).i = SUB32((res).i,(a).i); \
95     }while(0)
96
97 #if defined(ARMv4_ASM)
98
99 #undef C_MUL
100 #define C_MUL(m,a,b) \
101     do{ \
102        int br__; \
103        int bi__; \
104        int tt__; \
105         __asm__ __volatile__( \
106             "#C_MUL\n\t" \
107             "ldm %[ap], {r0,r1}\n\t" \
108             "ldrsh %[br], [%[bp], #0]\n\t" \
109             "ldrsh %[bi], [%[bp], #2]\n\t" \
110             "smull %[tt], %[mi], r1, %[br]\n\t" \
111             "smlal %[tt], %[mi], r0, %[bi]\n\t" \
112             "rsb %[bi], %[bi], #0\n\t" \
113             "smull r0, %[mr], %[br], r0\n\t" \
114             "mov %[tt], %[tt], lsr #15\n\t" \
115             "smlal r0, %[mr], r1, %[bi]\n\t" \
116             "orr %[mi], %[tt], %[mi], lsl #17\n\t" \
117             "mov r0, r0, lsr #15\n\t" \
118             "orr %[mr], r0, %[mr], lsl #17\n\t" \
119             : [mr]"=r"((m).r), [mi]"=r"((m).i), \
120               [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
121             : [ap]"r"(&(a)), [bp]"r"(&(b)) \
122             : "r0", "r1" \
123         ); \
124     } \
125     while(0)
126
127 #undef C_MUL4
128 #define C_MUL4(m,a,b) \
129     do{ \
130        int br__; \
131        int bi__; \
132        int tt__; \
133         __asm__ __volatile__( \
134             "#C_MUL4\n\t" \
135             "ldm %[ap], {r0,r1}\n\t" \
136             "ldrsh %[br], [%[bp], #0]\n\t" \
137             "ldrsh %[bi], [%[bp], #2]\n\t" \
138             "smull %[tt], %[mi], r1, %[br]\n\t" \
139             "smlal %[tt], %[mi], r0, %[bi]\n\t" \
140             "rsb %[bi], %[bi], #0\n\t" \
141             "smull r0, %[mr], %[br], r0\n\t" \
142             "mov %[tt], %[tt], lsr #17\n\t" \
143             "smlal r0, %[mr], r1, %[bi]\n\t" \
144             "orr %[mi], %[tt], %[mi], lsl #15\n\t" \
145             "mov r0, r0, lsr #17\n\t" \
146             "orr %[mr], r0, %[mr], lsl #15\n\t" \
147             : [mr]"=r"((m).r), [mi]"=r"((m).i), \
148               [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
149             : [ap]"r"(&(a)), [bp]"r"(&(b)) \
150             : "r0", "r1" \
151         ); \
152     } \
153     while(0)
154
155 #undef C_MULC
156 #define C_MULC(m,a,b) \
157     do{ \
158        int br__; \
159        int bi__; \
160        int tt__; \
161         __asm__ __volatile__( \
162             "#C_MULC\n\t" \
163             "ldm %[ap], {r0,r1}\n\t" \
164             "ldrsh %[br], [%[bp], #0]\n\t" \
165             "ldrsh %[bi], [%[bp], #2]\n\t" \
166             "smull %[tt], %[mr], r0, %[br]\n\t" \
167             "smlal %[tt], %[mr], r1, %[bi]\n\t" \
168             "rsb %[bi], %[bi], #0\n\t" \
169             "smull r1, %[mi], %[br], r1\n\t" \
170             "mov %[tt], %[tt], lsr #15\n\t" \
171             "smlal r1, %[mi], r0, %[bi]\n\t" \
172             "orr %[mr], %[tt], %[mr], lsl #17\n\t" \
173             "mov r1, r1, lsr #15\n\t" \
174             "orr %[mi], r1, %[mi], lsl #17\n\t" \
175             : [mr]"=r"((m).r), [mi]"=r"((m).i), \
176               [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
177             : [ap]"r"(&(a)), [bp]"r"(&(b)) \
178             : "r0", "r1" \
179         ); \
180     } \
181     while(0)
182
183 #endif /* ARMv4_ASM */
184
185 #if defined(ARMv5E_ASM)
186
187 #if defined(__thumb__)||defined(__thumb2__)
188 #define LDRD_CONS "Q"
189 #else
190 #define LDRD_CONS "Uq"
191 #endif
192
193 #undef C_MUL
194 #define C_MUL(m,a,b) \
195     do{ \
196         int mr1__; \
197         int mr2__; \
198         int mi__; \
199         long long aval__; \
200         int bval__; \
201         __asm__( \
202             "#C_MUL\n\t" \
203             "ldrd %[aval], %H[aval], %[ap]\n\t" \
204             "ldr %[bval], %[bp]\n\t" \
205             "smulwb %[mi], %H[aval], %[bval]\n\t" \
206             "smulwb %[mr1], %[aval], %[bval]\n\t" \
207             "smulwt %[mr2], %H[aval], %[bval]\n\t" \
208             "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
209             : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
210               [aval]"=&r"(aval__), [bval]"=r"(bval__) \
211             : [ap]LDRD_CONS(a), [bp]"m"(b) \
212         ); \
213         (m).r = SHL32(SUB32(mr1__, mr2__), 1); \
214         (m).i = SHL32(mi__, 1); \
215     } \
216     while(0)
217
218 #undef C_MUL4
219 #define C_MUL4(m,a,b) \
220     do{ \
221         int mr1__; \
222         int mr2__; \
223         int mi__; \
224         long long aval__; \
225         int bval__; \
226         __asm__( \
227             "#C_MUL4\n\t" \
228             "ldrd %[aval], %H[aval], %[ap]\n\t" \
229             "ldr %[bval], %[bp]\n\t" \
230             "smulwb %[mi], %H[aval], %[bval]\n\t" \
231             "smulwb %[mr1], %[aval], %[bval]\n\t" \
232             "smulwt %[mr2], %H[aval], %[bval]\n\t" \
233             "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
234             : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
235               [aval]"=&r"(aval__), [bval]"=r"(bval__) \
236             : [ap]LDRD_CONS(a), [bp]"m"(b) \
237         ); \
238         (m).r = SHR32(SUB32(mr1__, mr2__), 1); \
239         (m).i = SHR32(mi__, 1); \
240     } \
241     while(0)
242
243 #undef C_MULC
244 #define C_MULC(m,a,b) \
245     do{ \
246         int mr__; \
247         int mi1__; \
248         int mi2__; \
249         long long aval__; \
250         int bval__; \
251         __asm__( \
252             "#C_MULC\n\t" \
253             "ldrd %[aval], %H[aval], %[ap]\n\t" \
254             "ldr %[bval], %[bp]\n\t" \
255             "smulwb %[mr], %[aval], %[bval]\n\t" \
256             "smulwb %[mi1], %H[aval], %[bval]\n\t" \
257             "smulwt %[mi2], %[aval], %[bval]\n\t" \
258             "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \
259             : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \
260               [aval]"=&r"(aval__), [bval]"=r"(bval__) \
261             : [ap]LDRD_CONS(a), [bp]"m"(b) \
262         ); \
263         (m).r = SHL32(mr__, 1); \
264         (m).i = SHL32(SUB32(mi1__, mi2__), 1); \
265     } \
266     while(0)
267
268 #endif /* ARMv5E_ASM */
269
270 #else  /* not FIXED_POINT*/
271
272 #   define S_MUL(a,b) ( (a)*(b) )
273 #define C_MUL(m,a,b) \
274     do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
275         (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
276 #define C_MULC(m,a,b) \
277     do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
278         (m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
279
280 #define C_MUL4(m,a,b) C_MUL(m,a,b)
281
282 #   define C_FIXDIV(c,div) /* NOOP */
283 #   define C_MULBYSCALAR( c, s ) \
284     do{ (c).r *= (s);\
285         (c).i *= (s); }while(0)
286 #endif
287
288 #ifndef CHECK_OVERFLOW_OP
289 #  define CHECK_OVERFLOW_OP(a,op,b) /* noop */
290 #endif
291
292 #ifndef C_ADD
293 #define  C_ADD( res, a,b)\
294     do { \
295             CHECK_OVERFLOW_OP((a).r,+,(b).r)\
296             CHECK_OVERFLOW_OP((a).i,+,(b).i)\
297             (res).r=(a).r+(b).r;  (res).i=(a).i+(b).i; \
298     }while(0)
299 #define  C_SUB( res, a,b)\
300     do { \
301             CHECK_OVERFLOW_OP((a).r,-,(b).r)\
302             CHECK_OVERFLOW_OP((a).i,-,(b).i)\
303             (res).r=(a).r-(b).r;  (res).i=(a).i-(b).i; \
304     }while(0)
305 #define C_ADDTO( res , a)\
306     do { \
307             CHECK_OVERFLOW_OP((res).r,+,(a).r)\
308             CHECK_OVERFLOW_OP((res).i,+,(a).i)\
309             (res).r += (a).r;  (res).i += (a).i;\
310     }while(0)
311
312 #define C_SUBFROM( res , a)\
313     do {\
314             CHECK_OVERFLOW_OP((res).r,-,(a).r)\
315             CHECK_OVERFLOW_OP((res).i,-,(a).i)\
316             (res).r -= (a).r;  (res).i -= (a).i; \
317     }while(0)
318 #endif /* C_ADD defined */
319
320 #ifdef FIXED_POINT
321 /*#  define KISS_FFT_COS(phase)  TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
322 #  define KISS_FFT_SIN(phase)  TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/
323 #  define KISS_FFT_COS(phase)  floor(.5+TWID_MAX*cos (phase))
324 #  define KISS_FFT_SIN(phase)  floor(.5+TWID_MAX*sin (phase))
325 #  define HALF_OF(x) ((x)>>1)
326 #elif defined(USE_SIMD)
327 #  define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
328 #  define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
329 #  define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
330 #else
331 #  define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
332 #  define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
333 #  define HALF_OF(x) ((x)*.5f)
334 #endif
335
336 #define  kf_cexp(x,phase) \
337         do{ \
338                 (x)->r = KISS_FFT_COS(phase);\
339                 (x)->i = KISS_FFT_SIN(phase);\
340         }while(0)
341
342 #define  kf_cexp2(x,phase) \
343    do{ \
344       (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
345       (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
346 }while(0)
347
348 #endif /* KISS_FFT_GUTS_H */