diff options
| author | Andrew Mahone <andrew.mahone@gmail.com> | 2009-12-09 02:24:45 +0000 |
|---|---|---|
| committer | Andrew Mahone <andrew.mahone@gmail.com> | 2009-12-09 02:24:45 +0000 |
| commit | 85aad9b3972208b0e34ba0241ebb5314118ae05e (patch) | |
| tree | 27724c068f90b517d4bf9be6ed78d34a01eeba9b /apps/codecs/lib/codeclib.h | |
| parent | 3683bb67db4d5d59a55aabed6eaed72233323ee7 (diff) | |
| download | rockbox-85aad9b3972208b0e34ba0241ebb5314118ae05e.zip rockbox-85aad9b3972208b0e34ba0241ebb5314118ae05e.tar.gz rockbox-85aad9b3972208b0e34ba0241ebb5314118ae05e.tar.bz2 rockbox-85aad9b3972208b0e34ba0241ebb5314118ae05e.tar.xz | |
Extend av_log2 in codeclib into a generic for scanning for set bits, which can provide either log2 or leading-zero-count output, and can force mapping 0 input to 0 output if needed (otherwise 0 input produces undefined result). Replace av_log2 in lib/codeclib.h, floor_log2 and wl_min_lzc in libfaad/common.c and common.h, and count_leading_zeros in libalac/alac.c with macros using bs_generic.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23903 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/lib/codeclib.h')
| -rw-r--r-- | apps/codecs/lib/codeclib.h | 101 |
1 files changed, 68 insertions, 33 deletions
diff --git a/apps/codecs/lib/codeclib.h b/apps/codecs/lib/codeclib.h index 9c3624b..aeae5d6 100644 --- a/apps/codecs/lib/codeclib.h +++ b/apps/codecs/lib/codeclib.h @@ -74,45 +74,80 @@ unsigned udiv32_arm(unsigned a, unsigned b); #define UDIV32(a, b) (a / b) #endif -/* TODO figure out if we really need to care about calculating - av_log2(0) */ -#if defined(CPU_ARM) && ARM_ARCH >= 6 -static inline unsigned int av_log2(uint32_t v) -{ - unsigned int r; - asm volatile("clz %[r], %[v]\n\t" /* count leading zeroes */ - "rsb %[r], %[r], #31\n\t" /* r = 31 - leading zeroes */ - "usat %[r], #5, %[r]\n\t" /* unsigned saturate r so -1 -> 0 */ - :[r] "=r" (r) : [v] "r" (v)); - return(r); -} -#elif defined(CPU_ARM) && ARM_ARCH >= 5 -static inline unsigned int av_log2(uint32_t v) -{ - return v ? 31 - __builtin_clz(v) : 0; -} -#else /* CPU_ARM */ +#if !defined(CPU_ARM) || ARM_ARCH < 5 /* From libavutil/common.h */ -extern const uint8_t ff_log2_tab[256] ICONST_ATTR; +extern const uint8_t bs_log2_tab[256] ICONST_ATTR; +extern const uint8_t bs_clz_tab[256] ICONST_ATTR; +#endif -static inline unsigned int av_log2(unsigned int v) -{ - int n; +#define BS_LOG2 0 /* default personality, equivalent floor(log2(x)) */ +#define BS_CLZ 1 /* alternate personality, Count Leading Zeros */ +#define BS_SHORT 2 /* input guaranteed not to exceed 16 bits */ +#define BS_0_0 4 /* guarantee mapping of 0 input to 0 output */ - n = 0; - if (v & 0xffff0000) { - v >>= 16; - n += 16; +/* Generic bit-scanning function, used to wrap platform CLZ instruction or + scan-and-lookup code, and to provide control over output for 0 inputs. */ +static inline unsigned int bs_generic(unsigned int v, int mode) +{ +#if defined(CPU_ARM) && ARM_ARCH >= 5 + unsigned int r = __builtin_clz(v); + if (mode & BS_CLZ) + { + if (mode & BS_0_0) + r &= 31; + } else { + r = 31 - r; + /* If mode is constant, this is a single conditional instruction */ + if (mode & BS_0_0 && (signed)r < 0) + r += 1; + } +#else + const uint8_t *bs_tab; + unsigned int r; + unsigned int n = v; + int inc; + /* Set up table, increment, and initial result value based on + personality. */ + if (mode & BS_CLZ) + { + bs_tab = bs_clz_tab; + r = 24; + inc = -16; + } else { + bs_tab = bs_log2_tab; + r = 0; + inc = 16; } - if (v & 0xff00) { - v >>= 8; - n += 8; + if (!(mode & BS_SHORT) && n >= 0x10000) { + n >>= 16; + r += inc; } - n += ff_log2_tab[v]; - - return n; -} + if (n > 0xff) { + n >>= 8; + r += inc / 2; + } +#ifdef CPU_COLDFIRE + /* The high 24 bits of n are guaranteed empty after the above, so a + superfluous ext.b instruction can be saved by loading the LUT value over + n with asm */ + asm volatile ( + "move.b (%1,%0.l),%0" + : "+d" (n) + : "a" (bs_tab) + ); +#else + n = bs_tab[n]; #endif + r += n; + if (mode & BS_CLZ && mode & BS_0_0 && v == 0) + r = 0; +#endif + return r; +} + +/* TODO figure out if we really need to care about calculating + av_log2(0) */ +#define av_log2(v) bs_generic(v, BS_0_0) /* Various codec helper functions */ |