ref: 453ccd829a742feb84a5d3666d22a0a6c04666b8
parent: 7b0cb4ba0d2b5117d8ed4dbe0ab49c21090c8854
author: Jean-Marc Valin <[email protected]>
date: Fri Sep 12 16:52:27 EDT 2008
Generate slightly more accurate WMOPS figures
--- a/libcelt/_kiss_fft_guts.h
+++ b/libcelt/_kiss_fft_guts.h
@@ -92,16 +92,16 @@
# define S_MUL(a,b) MULT16_32_Q15(b, a)
# define C_MUL(m,a,b) \
- do{ (m).r = S_MUL((a).r,(b).r) - S_MUL((a).i,(b).i); \
- (m).i = S_MUL((a).r,(b).i) + S_MUL((a).i,(b).r); }while(0)
+ do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+ (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
# define C_MULC(m,a,b) \
- do{ (m).r = S_MUL((a).r,(b).r) + S_MUL((a).i,(b).i); \
- (m).i = S_MUL((a).i,(b).r) - S_MUL((a).r,(b).i); }while(0)
+ do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+ (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
# define C_MUL4(m,a,b) \
- do{ (m).r = SHR(S_MUL((a).r,(b).r) - S_MUL((a).i,(b).i),2); \
- (m).i = SHR(S_MUL((a).r,(b).i) + S_MUL((a).i,(b).r),2); }while(0)
+ do{ (m).r = SHR(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \
+ (m).i = SHR(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0)
# define C_MULBYSCALAR( c, s ) \
do{ (c).r = S_MUL( (c).r , s ) ;\
--- a/libcelt/arch.h
+++ b/libcelt/arch.h
@@ -56,6 +56,10 @@
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+#define UADD32(a,b) ((a)+(b))
+#define USUB32(a,b) ((a)-(b))
+
+#define PRINT_MIPS(file)
#ifdef FIXED_POINT
--- a/libcelt/cwrs.c
+++ b/libcelt/cwrs.c
@@ -47,6 +47,7 @@
#include <string.h>
#include "cwrs.h"
#include "mathops.h"
+#include "arch.h"
#if 0
int log2_frac(ec_uint32 val, int frac)
@@ -147,7 +148,7 @@
int j;
/* doing a do-while would overrun the array if we had less than 2 samples */
j=1; do {
- ui1=_ui[j]+_ui[j-1]+_ui0;
+ ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0);
_ui[j-1]=_ui0;
_ui0=ui1;
} while (++j<_len);
@@ -174,7 +175,7 @@
int j;
/* doing a do-while would overrun the array if we had less than 2 samples */
j=1; do {
- ui1=_ui[j]-_ui[j-1]-_ui0;
+ ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0);
_ui[j-1]=_ui0;
_ui0=ui1;
} while (++j<_n);
--- a/libcelt/fixed_debug.h
+++ b/libcelt/fixed_debug.h
@@ -37,15 +37,19 @@
#include <stdio.h>
-//extern long long celt_mips;
-static long long celt_mips = 0;
+#ifdef CELT_C
+long long celt_mips=0;
+#else
+extern long long celt_mips;
+#endif
+
#define MIPS_INC celt_mips++,
#define MULT16_16SU(a,b) ((celt_word32_t)(celt_word16_t)(a)*(celt_word32_t)(celt_uint16_t)(b))
-#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15))
+#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))
/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
-#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16))
#define QCONST16(x,bits) ((celt_word16_t)(.5+(x)*(((celt_word32_t)1)<<(bits))))
#define QCONST32(x,bits) ((celt_word32_t)(.5+(x)*(((celt_word32_t)1)<<(bits))))
@@ -53,6 +57,7 @@
#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
+#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1))
#define SHR(a,b) SHR32(a,b)
#define PSHR(a,b) PSHR32(a,b)
@@ -80,7 +85,7 @@
res = -x;
if (!VERIFY_INT(res))
fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
- celt_mips++;
+ celt_mips+=2;
return res;
}
@@ -151,7 +156,7 @@
{
fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
}
- celt_mips++;
+ celt_mips+=2;
return res;
}
static inline int SHL32(long long a, int shift)
@@ -166,18 +171,18 @@
{
fprintf (stderr, "SHL32: output is not int: %d\n", (int)res);
}
- celt_mips++;
+ celt_mips+=2;
return res;
}
-#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
-#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift))
+#define PSHR16(a,shift) (celt_mips--,SHR16(ADD16((a),((1<<((shift))>>1))),shift))
+#define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((celt_word32_t)(1)<<((shift))>>1))),shift))
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
-#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a))))
+#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
#define HALF32(x) (SHR32(x,1))
//#define SHR(a,shift) ((a) >> (shift))
@@ -228,26 +233,63 @@
{
fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
}
- celt_mips++;
+ celt_mips+=2;
return res;
}
-static inline int SUB32(long long a, long long b)
+#define SUB32(a, b) _SUB32(a, b, __FILE__, __LINE__)
+static inline int _SUB32(long long a, long long b, char *file, int line)
{
long long res;
if (!VERIFY_INT(a) || !VERIFY_INT(b))
{
- fprintf (stderr, "SUB32: inputs are not int: %d %d\n", (int)a, (int)b);
+ fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
}
res = a-b;
if (!VERIFY_INT(res))
- fprintf (stderr, "SUB32: output is not int: %d\n", (int)res);
- celt_mips++;
+ fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+ celt_mips+=2;
return res;
}
-#define ADD64(a,b) (MIPS_INC(a)+(b))
+#undef UADD32
+#define UADD32(a, b) _UADD32(a, b, __FILE__, __LINE__)
+static inline unsigned int _UADD32(unsigned long long a, unsigned long long b, char *file, int line)
+{
+ long long res;
+ if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+ {
+ fprintf (stderr, "UADD32: inputs are not int: %u %u in %s: line %d\n", (unsigned)a, (unsigned)b, file, line);
+ }
+ res = a+b;
+ if (!VERIFY_UINT(res))
+ {
+ fprintf (stderr, "UADD32: output is not int: %u in %s: line %d\n", (unsigned)res, file, line);
+ }
+ celt_mips+=2;
+ return res;
+}
+#undef USUB32
+#define USUB32(a, b) _USUB32(a, b, __FILE__, __LINE__)
+static inline unsigned int _USUB32(unsigned long long a, unsigned long long b, char *file, int line)
+{
+ long long res;
+ if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+ {
+ /*fprintf (stderr, "USUB32: inputs are not int: %llu %llu in %s: line %d\n", (unsigned)a, (unsigned)b, file, line);*/
+ }
+ res = a-b;
+ if (!VERIFY_UINT(res))
+ {
+ /*fprintf (stderr, "USUB32: output is not int: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);*/
+ }
+ celt_mips+=2;
+ return res;
+}
+
+
+
/* result fits in 16 bits */
static inline short MULT16_16_16(int a, int b)
{
@@ -278,10 +320,10 @@
return res;
}
-#define MAC16_16(c,a,b) (celt_mips--,ADD32((c),MULT16_16((a),(b))))
-#define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11)))))
-#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13)))))
-#define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13))))
+#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
+#define MAC16_16_Q11(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11))))
+#define MAC16_16_Q13(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13))))
+#define MAC16_16_P13(c,a,b) (ADD16((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13)))
#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__)
@@ -292,12 +334,15 @@
{
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);
}
- if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
+ if (ABS32(b)>=((celt_word32_t)(1)<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
res = (((long long)a)*(long long)b) >> Q;
if (!VERIFY_INT(res))
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);
- celt_mips+=5;
+ if (Q==15)
+ celt_mips+=3;
+ else
+ celt_mips+=4;
return res;
}
@@ -308,12 +353,15 @@
{
fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b);
}
- if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
+ if (ABS32(b)>=((celt_word32_t)(1)<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);
- res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<<Q)>>1))>> Q;
+ res = ((((long long)a)*(long long)b) + (((celt_word32_t)(1)<<Q)>>1))>> Q;
if (!VERIFY_INT(res))
fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res);
- celt_mips+=5;
+ if (Q==15)
+ celt_mips+=4;
+ else
+ celt_mips+=5;
return res;
}
@@ -333,6 +381,7 @@
a=b;
if (a<-b)
a = -b;
+ celt_mips+=3;
return a;
}
@@ -391,7 +440,7 @@
{
fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res);
}
- celt_mips+=3;
+ celt_mips+=1;
return res;
}
@@ -443,7 +492,7 @@
res >>= 15;
if (!VERIFY_SHORT(res))
fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
- celt_mips+=4;
+ celt_mips+=2;
return res;
}
@@ -470,7 +519,7 @@
if (res<-32768)
res = -32768;
}
- celt_mips+=20;
+ celt_mips+=35;
return res;
}
@@ -491,10 +540,13 @@
res = a/b;
if (!VERIFY_INT(res))
fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
- celt_mips+=36;
+ celt_mips+=70;
return res;
}
#define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b)
#define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b)
+
+#undef PRINT_MIPS
+#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %d MIPS\n", celt_mips);} while (0);
#endif
--- a/libcelt/testcelt.c
+++ b/libcelt/testcelt.c
@@ -161,6 +161,8 @@
fwrite(out+skip, sizeof(short), (frame_size-skip)*channels, fout);
skip = 0;
}
+ PRINT_MIPS(stderr);
+
celt_encoder_destroy(enc);
celt_decoder_destroy(dec);
fclose(fin);