diff --git a/Makefile b/Makefile index 9d18cbde3d47ff872b918dc70675543fc18cfba9..d212bb3148525b1f837b3ee6549e4908f4fb0739 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,8 @@ endif CFLAGS += -std=c99 -pedantic -Wcast-qual -Wall -W -Wextra -Wno-long-long \ -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes \ -Werror-implicit-function-declaration \ - -Wno-implicit-fallthrough -ffp-contract=off + -Wno-implicit-fallthrough -ffp-contract=off \ + -Wno-attributes -Wno-unused-function # to be uncommented in CI # CFLAGS += -Werror CFLAGS += -Winit-self diff --git a/lib_com/basop32.c b/lib_com/basop32.c index 6a34cff43e570ae4a6a3212891067ca5887bef48..6dd653764ce2f1fe131ab7ce0b89d1744b982ae8 100644 --- a/lib_com/basop32.c +++ b/lib_com/basop32.c @@ -3577,24 +3577,33 @@ Word16 DEPR_i_mult( Word16 a, Word16 b ) #endif } +#ifndef BASOP_WATCH_i_mult_o + Word16 i_mult_o( Word16 a, Word16 b, Flag *Overflow ) { #ifdef ORIGINAL_G7231 return a * b; #else register Word32 c = (Word32) a * b; + return saturate_o( c, Overflow ); #endif } +#endif +#ifndef BASOP_WATCH_i_mult Word16 i_mult( Word16 a, Word16 b ) { return i_mult_sat( a, b ); } +#endif + +#ifndef BASOP_WATCH_i_mult_sat Word16 i_mult_sat( Word16 a, Word16 b ) { Flag Overflow; return i_mult_o( a, b, &Overflow ); } +#endif /* ****************************************************************************** * The following three operators are not part of the original diff --git a/lib_com/basop32.h b/lib_com/basop32.h index 9bbf24f1c52e1c5159ad4ff22fa6720f3bfcd60a..b74b14fb7a232821bb87079ec1e9322f143bac79 100644 --- a/lib_com/basop32.h +++ b/lib_com/basop32.h @@ -102,6 +102,13 @@ extern Flag BASOP_Carry; #define BASOP_SATURATE_ERROR_OFF #define BASOP_CHECK() +/* BASOP-Watches */ +#define BASOP_WATCH_i_mult +#define BASOP_WATCH_i_mult_o +#define BASOP_WATCH_i_mult_sat +#define INLINE __attribute__( ( always_inline ) ) +#include +#include #define MAX_32 (Word32) 0x7fffffffL #define MIN_32 (Word32) 0x80000000L @@ -175,9 +182,41 @@ Word32 L_sat( Word32 L_var1 ); /* Long saturation, 4 */ /* * Additional G.723.1 operators */ -Word32 L_mls( Word32, Word16 ); /* Weight FFS; currently assigned 5 */ -Word16 div_l( Word32, Word16 ); /* Weight FFS; currently assigned 32 */ -Word16 i_mult( Word16 a, Word16 b ); /* Weight FFS; currently assigned 3 */ +Word32 L_mls( Word32, Word16 ); /* Weight FFS; currently assigned 5 */ +Word16 div_l( Word32, Word16 ); /* Weight FFS; currently assigned 32 */ +// Word16 i_mult( Word16 a, Word16 b ); /* Weight FFS; currently assigned 3 */ +#ifdef BASOP_WATCH_i_mult +#define i_mult( a, b ) i_mult_watch( a, b, __FILE__, __LINE__ ) +static INLINE Word16 i_mult_watch( Word16 a, Word16 b, const char *fname, int linenumber ) /* Weight FFS: currently assigned 3 */ +#else +static INLINE Word16 i_mult( Word16 a, Word16 b ) /* Weight FFS: currently assigned 3 */ +#endif /* BASOP_WATCH_i_mult */ +{ + Word32 c = (Word32) a * b; +#ifdef BASOP_WATCH_i_mult + static Word32 BASOP_WATCH_i_mult_Cnt = 0; + if ( BASOP_WATCH_i_mult_Cnt == 0 ) + { + Word16 c1 = a * b; + if ( (Word32) c1 != c ) + { + fprintf( stderr, "BASOP WATCH i_mult: 0x%08X = 0x%04X * 0x%04X (legacy: 0x%08X <= 16 bit overflow in File: %s, line: %d\n", c, a & 0xFFFF, b & 0xFFFF, (Word32) c1, fname, linenumber ); + BASOP_WATCH_i_mult_Cnt++; + // assert( 0 ); + return c1; + } + } +#endif + if ( c > MAX_16 ) + { + c = MAX_16; + } + else if ( c < MIN_16 ) + { + c = MIN_16; + } + return (Word16) c; +} Word16 DEPR_i_mult( Word16 a, Word16 b ); /* Weight FFS; currently assigned 3 */ /* @@ -190,7 +229,50 @@ Word32 L_msu0( Word32 L_v3, Word16 v1, Word16 v2 ); /* 32-bit Msu w/o shift 1 * /* * Overflowing operators */ -Word16 i_mult_o( Word16 a, Word16 b, Flag *Overflow ); +// Word16 i_mult_o( Word16 a, Word16 b, Flag *Overflow ); +#ifdef BASOP_WATCH_i_mult_o +#define i_mult_o( a, b, c ) i_mult_o_watch( a, b, c, __FILE__, __LINE__ ) +static INLINE Word16 i_mult_o_watch( Word16 a, Word16 b, Flag *Overflow, const char *fname, int linenumber ) +#else +static INLINE Word16 i_mult_o( Word16 a, Word16 b, Flag *Overflow ) /* integer Mpy with ovl ? */ +#endif /* BASOP_WATCH_i_mult_o */ +{ +#ifdef ORIGINAL_G7231 + return a * b; +#else + Word32 c = (Word32) a * b; +#ifdef BASOP_WATCH_i_mult_o + static Word32 BASOP_WATCH_i_mult_o_Cnt = 0; + if ( BASOP_WATCH_i_mult_o_Cnt == 0 ) + { + Word16 c1 = a * b; + if ( (Word32) c1 != c ) + { + fprintf( stderr, "BASOP WATCH i_mult_o: 0x%08X = 0x%04X * 0x%04X (legacy: 0x%08X) <= 16 bit Overflow File: %s, line: %d\n", c, a & 0xFFFF, b & 0xFFFF, (Word32) c1, fname, linenumber ); + if ( Overflow == (Flag *) NULL ) + printf( "BASOP WATCH i_mult_o: Overflow == NULL File: %s, line: %d\n", fname, linenumber ); + BASOP_WATCH_i_mult_o_Cnt++; + // assert( 0 ); + return c1; // Legacy return value to bypass Crash due to NULL pointer + } + } + +#endif /* BASOP_WATCH_i_mult_o */ + if ( c > MAX_16 ) + { + c = MAX_16; + if ( Overflow ) + *Overflow = 1; + } + else if ( c < MIN_16 ) + { + c = MIN_16; + if ( Overflow ) + *Overflow = 1; + } + return (Word16) c; +#endif /* ORIGINAL_G7231 */ +} Word16 add_o( Word16 var1, Word16 var2, Flag *Overflow ); Word16 sub_o( Word16 var1, Word16 var2, Flag *Overflow ); Word16 shl_o( Word16 var1, Word16 var2, Flag *Overflow ); @@ -220,7 +302,36 @@ Word32 L_msuNs_co( Word32 L_var3, Word16 var1, Word16 var2, Flag *Carry, Flag *O /* * Saturating operators */ -Word16 i_mult_sat( Word16 a, Word16 b ); +// Word16 i_mult_sat( Word16 a, Word16 b ); +#ifdef BASOP_WATCH_i_mult_sat +#define i_mult_sat( a, b ) i_mult_sat_watch( a, b, __FILE__, __LINE__ ) +static INLINE Word16 i_mult_sat_watch( Word16 a, Word16 b, const char *fname, int linenumber ) +#else +static INLINE Word16 i_mult_sat( Word16 a, Word16 b ) /* integer Mpy with saturation */ +#endif /* BASOP_WATCH_i_mult_sat */ +{ + Word32 c = (Word32) a * b; + +#ifdef BASOP_WATCH_i_mult_sat + static Word32 BASOP_WATCH_i_mult_sat_Cnt = 0; + if ( ( BASOP_WATCH_i_mult_sat_Cnt == 0 ) || 1 ) + { + Word16 c1 = a * b; /* emulate strange behaviour interpreting product as 16-bit */ + if ( (Word32) c1 != c ) + { + fprintf( stderr, "BASOP WATCH i_mult_sat: 0x%08X = 0x%04X * 0x%04X (legacy: 0x%08X <= 16 bit overflow File: %s line %d\n", c, a & 0xFFFF, b & 0xFFFF, (Word32) c1, fname, linenumber ); + BASOP_WATCH_i_mult_sat_Cnt++; + // assert( 0 ); + return c1; + } + } +#endif /* BASOP_WATCH_i_mult_sat */ + if ( c > MAX_16 ) + c = MAX_16; + else if ( c < MIN_16 ) + c = MIN_16; + return (Word16) c; +} Word16 add_sat( Word16 var1, Word16 var2 ); Word16 sub_sat( Word16 var1, Word16 var2 ); Word16 shl_sat( Word16 var1, Word16 var2 ); diff --git a/lib_com/options.h b/lib_com/options.h index 0cf958d03f0ea1e00be423e92f82dd91da395295..47ba546eda08a4bed5f90d1384639c9e6d183d7f 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -123,5 +123,14 @@ #define FIX_ISSUE_1795_Q3_OVERFLOW /* FhG: Q3 overflow in function WB_BWE_gain_pred_fx (EVS legacy code) BE, MR1855 */ #define NONBE_FIX_1748_SPAR_DIV_OPT /*Dlb: issue 1748: SPAR common div optimizations*/ +/* Info for issue 1771: + * Some compilers do not automatically use 32 bit for 16x16bit products. The code "Word32 c = (Word16) a * (Word16) b;" creates then a 16-bit result, sign-extending the + * lower 16-bit of the product, any upper bits are omitted. Example: Product 0x0100 * 0x0100 results in 0x0001.0000, gets truncated to its lower bits and return 0x0000. + * The issue is fixed by simply casting one of the product operands to Word32 in lib_com/basop32.c + */ +#define FIX_ISSUE_1771_USE_W32_FOR_MPY_W16xW16 /* FhG: (QA-FIX) Use doubled data width for 16x16 product, some compilers keep 16-bit format also for products */ +#define FIX_ISSUE_1771_IMPROVE_MPY_ZERO_DOT_1_PRECISION /* FhG: (NON-BE) improve precision of multiplications with factor 0.1f, avoids overflow with up-rounded value */ + #define FIX_ISSUE_1801_NOISE_FLOOR_REDUCTION /* FhG: Fixed getScalefactor usage */ + #endif diff --git a/lib_dec/swb_tbe_dec_fx.c b/lib_dec/swb_tbe_dec_fx.c index 61dc3d0c56749685434360b3a72d0e8d6498a914..96e9d18ca267e3258ffa3ca5ca3ed77dc026ad7b 100644 --- a/lib_dec/swb_tbe_dec_fx.c +++ b/lib_dec/swb_tbe_dec_fx.c @@ -2725,7 +2725,14 @@ void swb_tbe_dec_fx( } FOR( ; i < L_SHB_LAHEAD + 10; i++ ) { + +#ifdef FIX_ISSUE_1771_IMPROVE_MPY_ZERO_DOT_1_PRECISION + temp = round_fx_sat( L_shl( L_mult( 0x6666 /* 0.1 in Q12 */, shl( sub( i, 19 ), 11 ) ), 1 ) ); +#else temp = i_mult_sat( sub( i, 19 ), 3277 /*0.1f Q15*/ ); /* Q15 */ +#endif + + L_tmp1 = Mult_32_16( L_shl_sat( 1, sub( 31, exp ) ), temp ); /* Q31-exp */ temp = sub( 32767 /*1.0f Q15*/, temp ); Lscale = L_add( Mult_32_16( Lscale, temp ), L_tmp1 ); @@ -6287,7 +6294,12 @@ void ivas_swb_tbe_dec_fx( } FOR( ; i < L_SHB_LAHEAD + 10; i++ ) { - temp_fx = i_mult_sat( sub( i, 19 ), 3277 /*0.1f Q15*/ ); /* Q15 */ +#ifdef FIX_ISSUE_1771_IMPROVE_MPY_ZERO_DOT_1_PRECISION + temp_fx = round_fx_sat( L_shl( L_mult( 0x6666 /* 0.1 in Q12 */, shl( sub( i, 19 ), 11 ) ), 1 ) ); +#else + temp_fx = i_mult_sat( sub( i, 19 ), 3277 /*0.1f Q15*/ ); /* Q15 */ +#endif + L_tmp1 = Mult_32_16( L_shl_sat( 1, sub( 31, exp ) ), temp_fx ); /* Q31-exp */ temp_fx = sub( 32767 /*1.0f Q15*/, temp_fx ); Lscale = L_add( Mult_32_16( Lscale, temp_fx ), L_tmp1 ); diff --git a/lib_enc/swb_tbe_enc_fx.c b/lib_enc/swb_tbe_enc_fx.c index d016cd7216d58c7d8fcaccee58ea5994442c9f01..1c49142e2d2b7d8be4e448ae5152fb2df93fcea8 100644 --- a/lib_enc/swb_tbe_enc_fx.c +++ b/lib_enc/swb_tbe_enc_fx.c @@ -2537,12 +2537,17 @@ void swb_tbe_enc_fx( } FOR( ; i < L_SHB_LAHEAD + 10; i++ ) { - tmp = i_mult_o( sub( i, 19 ), 3277 /*0.1f Q15*/, &Overflow ); /* Q15 */ +#ifdef FIX_ISSUE_1771_IMPROVE_MPY_ZERO_DOT_1_PRECISION + tmp = round_fx_sat( L_shl( L_mult( 0x6666 /* 0.1 in Q12 */, shl( sub( i, 19 ), 11 ) ), 1 ) ); +#else + tmp = i_mult_o( sub( i, 19 ), 3277 /*0.1f Q15*/, &Overflow ); /* Q15 */ +#endif L_tmp1 = Mult_32_16( L_shl_o( 1, sub( 31, exp ), &Overflow ), tmp ); /* Q31-exp */ tmp = sub( 32767 /*1.0f Q15*/, tmp ); Lscale = L_add( Mult_32_16( Lscale, tmp ), L_tmp1 ); L_tmp = Mult_32_16( Lscale, shaped_shb_excitation_fx[i] ); /* Q_bwe_exc + (31-exp) - 15 */ shaped_shb_excitation_fx[i] = round_fx_o( L_shl_o( L_tmp, exp, &Overflow ), &Overflow ); /* Q_bwe_exc */ + // printf("i_mult_o: tmp = 0x%04X (a=%d) Lscale = 0x%08X L_tmp = 0x%08X exc[%d] = 0x%04X\n", tmp&0xFFFF, i - 19, Lscale, L_tmp, i, shaped_shb_excitation_fx[i]); move16(); } @@ -3833,7 +3838,11 @@ void swb_tbe_enc_ivas_fx( } FOR( ; i < L_SHB_LAHEAD + 10; i++ ) { - tmp = i_mult_o( sub( i, 19 ), 3277 /*0.1f Q15*/, &Overflow ); /* Q15 */ +#ifdef FIX_ISSUE_1771_IMPROVE_MPY_ZERO_DOT_1_PRECISION + tmp = round_fx_sat( L_shl( L_mult( 0x6666 /* 0.1 in Q12 */, shl( sub( i, 19 ), 11 ) ), 1 ) ); +#else + tmp = i_mult_o( sub( i, 19 ), 3277 /*0.1f Q15*/, &Overflow ); /* Q15 */ +#endif L_tmp1 = Mult_32_16( L_shl_o( 1, sub( 31, exp ), &Overflow ), tmp ); /* Q31-exp */ tmp = sub( 32767 /*1.0f Q15*/, tmp ); L_tmp = L_add( Mult_32_16( Lscale, tmp ), L_tmp1 );