From 729b21f97f3d849b1ef2bd61114e4b39d073884d Mon Sep 17 00:00:00 2001 From: kwiberg Date: Thu, 2 Jun 2016 04:02:12 -0700 Subject: [PATCH] Add clz functions (Count number of Leading Zero bits), 32-and 64-bit variants Using __builtin_clz on gcc/clang, and a fallback implementation otherwise. Also redefine WebRtcSpl_GetSizeInBits(x) as simply 32 - clz32(x). BUG=chromium:601787 Review-Url: https://codereview.webrtc.org/2014023002 Cr-Commit-Position: refs/heads/master@{#13014} --- webrtc/common_audio/BUILD.gn | 1 + webrtc/common_audio/common_audio.gyp | 1 + webrtc/common_audio/real_fourier.cc | 2 +- .../signal_processing/include/spl_inl.h | 127 ++++++++---------- .../signal_processing_unittest.cc | 26 ++++ .../common_audio/signal_processing/spl_inl.c | 24 ++++ .../include/compile_assert_c.h | 5 +- 7 files changed, 113 insertions(+), 73 deletions(-) create mode 100644 webrtc/common_audio/signal_processing/spl_inl.c diff --git a/webrtc/common_audio/BUILD.gn b/webrtc/common_audio/BUILD.gn index fcf8403a62..eef0a76aea 100644 --- a/webrtc/common_audio/BUILD.gn +++ b/webrtc/common_audio/BUILD.gn @@ -81,6 +81,7 @@ source_set("common_audio") { "signal_processing/resample_by_2_internal.h", "signal_processing/resample_fractional.c", "signal_processing/spl_init.c", + "signal_processing/spl_inl.c", "signal_processing/spl_sqrt.c", "signal_processing/splitting_filter.c", "signal_processing/sqrt_of_one_minus_x_squared.c", diff --git a/webrtc/common_audio/common_audio.gyp b/webrtc/common_audio/common_audio.gyp index c26cdcd948..fcd7a411bf 100644 --- a/webrtc/common_audio/common_audio.gyp +++ b/webrtc/common_audio/common_audio.gyp @@ -94,6 +94,7 @@ 'signal_processing/resample_by_2_internal.h', 'signal_processing/resample_fractional.c', 'signal_processing/spl_init.c', + 'signal_processing/spl_inl.c', 'signal_processing/spl_sqrt.c', 'signal_processing/spl_sqrt_floor.c', 'signal_processing/splitting_filter.c', diff --git a/webrtc/common_audio/real_fourier.cc b/webrtc/common_audio/real_fourier.cc index 67f942d560..e721346f31 100644 --- a/webrtc/common_audio/real_fourier.cc +++ b/webrtc/common_audio/real_fourier.cc @@ -13,7 +13,7 @@ #include "webrtc/base/checks.h" #include "webrtc/common_audio/real_fourier_ooura.h" #include "webrtc/common_audio/real_fourier_openmax.h" -#include "webrtc/common_audio/signal_processing/include/spl_inl.h" +#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" namespace webrtc { diff --git a/webrtc/common_audio/signal_processing/include/spl_inl.h b/webrtc/common_audio/signal_processing/include/spl_inl.h index 3c0a81cf34..90098caaaa 100644 --- a/webrtc/common_audio/signal_processing/include/spl_inl.h +++ b/webrtc/common_audio/signal_processing/include/spl_inl.h @@ -15,6 +15,54 @@ #ifndef WEBRTC_SPL_SPL_INL_H_ #define WEBRTC_SPL_SPL_INL_H_ +#include "webrtc/system_wrappers/include/compile_assert_c.h" + +extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64]; + +// Don't call this directly except in tests! +static __inline int WebRtcSpl_CountLeadingZeros32_NotBuiltin(uint32_t n) { + // Normalize n by rounding up to the nearest number that is a sequence of 0 + // bits followed by a sequence of 1 bits. This number has the same number of + // leading zeros as the original n. There are exactly 33 such values. + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + + // Multiply the modified n with a constant selected (by exhaustive search) + // such that each of the 33 possible values of n give a product whose 6 most + // significant bits are unique. Then look up the answer in the table. + return kWebRtcSpl_CountLeadingZeros32_Table[(n * 0x8c0b2891) >> 26]; +} + +// Don't call this directly except in tests! +static __inline int WebRtcSpl_CountLeadingZeros64_NotBuiltin(uint64_t n) { + const int leading_zeros = n >> 32 == 0 ? 32 : 0; + return leading_zeros + WebRtcSpl_CountLeadingZeros32_NotBuiltin( + (uint32_t)(n >> (32 - leading_zeros))); +} + +// Returns the number of leading zero bits in the argument. +static __inline int WebRtcSpl_CountLeadingZeros32(uint32_t n) { +#ifdef __GNUC__ + COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t)); + return n == 0 ? 32 : __builtin_clz(n); +#else + return WebRtcSpl_CountLeadingZeros32_NotBuiltin(n); +#endif +} + +// Returns the number of leading zero bits in the argument. +static __inline int WebRtcSpl_CountLeadingZeros64(uint64_t n) { +#ifdef __GNUC__ + COMPILE_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); + return n == 0 ? 64 : __builtin_clzll(n); +#else + return WebRtcSpl_CountLeadingZeros64_NotBuiltin(n); +#endif +} + #ifdef WEBRTC_ARCH_ARM_V7 #include "webrtc/common_audio/signal_processing/include/spl_inl_armv7.h" #else @@ -74,83 +122,26 @@ static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { #if !defined(MIPS32_LE) static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { - int16_t bits; - - if (0xFFFF0000 & n) { - bits = 16; - } else { - bits = 0; - } - if (0x0000FF00 & (n >> bits)) bits += 8; - if (0x000000F0 & (n >> bits)) bits += 4; - if (0x0000000C & (n >> bits)) bits += 2; - if (0x00000002 & (n >> bits)) bits += 1; - if (0x00000001 & (n >> bits)) bits += 1; - - return bits; + return 32 - WebRtcSpl_CountLeadingZeros32(n); } +// Return the number of steps a can be left-shifted without overflow, +// or 0 if a == 0. static __inline int16_t WebRtcSpl_NormW32(int32_t a) { - int16_t zeros; - - if (a == 0) { - return 0; - } - else if (a < 0) { - a = ~a; - } - - if (!(0xFFFF8000 & a)) { - zeros = 16; - } else { - zeros = 0; - } - if (!(0xFF800000 & (a << zeros))) zeros += 8; - if (!(0xF8000000 & (a << zeros))) zeros += 4; - if (!(0xE0000000 & (a << zeros))) zeros += 2; - if (!(0xC0000000 & (a << zeros))) zeros += 1; - - return zeros; + return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a : a) - 1; } +// Return the number of steps a can be left-shifted without overflow, +// or 0 if a == 0. static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { - int16_t zeros; - - if (a == 0) return 0; - - if (!(0xFFFF0000 & a)) { - zeros = 16; - } else { - zeros = 0; - } - if (!(0xFF000000 & (a << zeros))) zeros += 8; - if (!(0xF0000000 & (a << zeros))) zeros += 4; - if (!(0xC0000000 & (a << zeros))) zeros += 2; - if (!(0x80000000 & (a << zeros))) zeros += 1; - - return zeros; + return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a); } +// Return the number of steps a can be left-shifted without overflow, +// or 0 if a == 0. static __inline int16_t WebRtcSpl_NormW16(int16_t a) { - int16_t zeros; - - if (a == 0) { - return 0; - } - else if (a < 0) { - a = ~a; - } - - if (!(0xFF80 & a)) { - zeros = 8; - } else { - zeros = 0; - } - if (!(0xF800 & (a << zeros))) zeros += 4; - if (!(0xE000 & (a << zeros))) zeros += 2; - if (!(0xC000 & (a << zeros))) zeros += 1; - - return zeros; + const int32_t a32 = a; + return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a32 : a32) - 17; } static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { diff --git a/webrtc/common_audio/signal_processing/signal_processing_unittest.cc b/webrtc/common_audio/signal_processing/signal_processing_unittest.cc index 0dc0d37878..445c421ee3 100644 --- a/webrtc/common_audio/signal_processing/signal_processing_unittest.cc +++ b/webrtc/common_audio/signal_processing/signal_processing_unittest.cc @@ -142,6 +142,32 @@ TEST_F(SplTest, AddSubSatW32) { } } +TEST_F(SplTest, CountLeadingZeros32) { + EXPECT_EQ(32, WebRtcSpl_CountLeadingZeros32(0)); + EXPECT_EQ(32, WebRtcSpl_CountLeadingZeros32_NotBuiltin(0)); + for (int i = 0; i < 32; ++i) { + const uint32_t single_one = uint32_t{1} << i; + const uint32_t all_ones = 2 * single_one - 1; + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32(single_one)); + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32_NotBuiltin(single_one)); + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32(all_ones)); + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32_NotBuiltin(all_ones)); + } +} + +TEST_F(SplTest, CountLeadingZeros64) { + EXPECT_EQ(64, WebRtcSpl_CountLeadingZeros64(0)); + EXPECT_EQ(64, WebRtcSpl_CountLeadingZeros64_NotBuiltin(0)); + for (int i = 0; i < 64; ++i) { + const uint64_t single_one = uint64_t{1} << i; + const uint64_t all_ones = 2 * single_one - 1; + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64(single_one)); + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64_NotBuiltin(single_one)); + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64(all_ones)); + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64_NotBuiltin(all_ones)); + } +} + TEST_F(SplTest, MathOperationsTest) { int A = 1134567892; int32_t num = 117; diff --git a/webrtc/common_audio/signal_processing/spl_inl.c b/webrtc/common_audio/signal_processing/spl_inl.c new file mode 100644 index 0000000000..efa6a65f0e --- /dev/null +++ b/webrtc/common_audio/signal_processing/spl_inl.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "webrtc/common_audio/signal_processing/include/spl_inl.h" + +// Table used by WebRtcSpl_CountLeadingZeros32_NotBuiltin. For each uint32_t n +// that's a sequence of 0 bits followed by a sequence of 1 bits, the entry at +// index (n * 0x8c0b2891) >> 26 in this table gives the number of zero bits in +// n. +const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64] = { + 32, 8, 17, -1, -1, 14, -1, -1, -1, 20, -1, -1, -1, 28, -1, 18, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 26, 25, 24, + 4, 11, 23, 31, 3, 7, 10, 16, 22, 30, -1, -1, 2, 6, 13, 9, + -1, 15, -1, 21, -1, 29, 19, -1, -1, -1, -1, -1, 1, 27, 5, 12, +}; diff --git a/webrtc/system_wrappers/include/compile_assert_c.h b/webrtc/system_wrappers/include/compile_assert_c.h index b402d7192d..00f6306e9f 100644 --- a/webrtc/system_wrappers/include/compile_assert_c.h +++ b/webrtc/system_wrappers/include/compile_assert_c.h @@ -11,14 +11,11 @@ #ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_COMPILE_ASSERT_H_ #define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_COMPILE_ASSERT_H_ -#ifdef __cplusplus -#error "Only use this for C files. For C++, use static_assert." -#endif - // Use this macro to verify at compile time that certain restrictions are met. // The argument is the boolean expression to evaluate. // Example: // COMPILE_ASSERT(sizeof(foo) < 128); +// Note: In C++, use static_assert instead! #define COMPILE_ASSERT(expression) switch (0) {case 0: case expression:;} #endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_COMPILE_ASSERT_H_