diff options
-rw-r--r-- | src/compiler-intrinsics-vixl.cc | 2 | ||||
-rw-r--r-- | src/compiler-intrinsics-vixl.h | 19 | ||||
-rw-r--r-- | test/aarch64/test-api-aarch64.cc | 61 |
3 files changed, 76 insertions, 6 deletions
diff --git a/src/compiler-intrinsics-vixl.cc b/src/compiler-intrinsics-vixl.cc index ae182c7d..f6234fa6 100644 --- a/src/compiler-intrinsics-vixl.cc +++ b/src/compiler-intrinsics-vixl.cc @@ -25,12 +25,14 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "compiler-intrinsics-vixl.h" +#include "utils-vixl.h" namespace vixl { int CountLeadingSignBitsFallBack(int64_t value, int width) { VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); + if (width < 64) VIXL_ASSERT(IsIntN(width, value)); if (value >= 0) { return CountLeadingZeros(value, width) - 1; } else { diff --git a/src/compiler-intrinsics-vixl.h b/src/compiler-intrinsics-vixl.h index b27f94eb..50ed3579 100644 --- a/src/compiler-intrinsics-vixl.h +++ b/src/compiler-intrinsics-vixl.h @@ -28,6 +28,7 @@ #ifndef VIXL_COMPILER_INTRINSICS_H #define VIXL_COMPILER_INTRINSICS_H +#include <limits.h> #include "globals-vixl.h" namespace vixl { @@ -104,16 +105,22 @@ int CountTrailingZerosFallBack(uint64_t value, int width); // TODO: The implementations could be improved for sizes different from 32bit // and 64bit: we could mask the values and call the appropriate builtin. +// Return the number of leading bits that match the topmost (sign) bit, +// excluding the topmost bit itself. template <typename V> inline int CountLeadingSignBits(V value, int width = (sizeof(V) * 8)) { + VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); #if COMPILER_HAS_BUILTIN_CLRSB - if (width == 32) { - return __builtin_clrsb(value); - } else if (width == 64) { - return __builtin_clrsbll(value); - } -#endif + VIXL_ASSERT((LLONG_MIN <= value) && (value <= LLONG_MAX)); + int ll_width = sizeof(long long) * kBitsPerByte; // NOLINT(runtime/int) + int result = __builtin_clrsbll(value) - (ll_width - width); + // Check that the value fits in the specified width. + VIXL_ASSERT(result >= 0); + return result; +#else + VIXL_ASSERT((INT64_MIN <= value) && (value <= INT64_MAX)); return CountLeadingSignBitsFallBack(value, width); +#endif } diff --git a/test/aarch64/test-api-aarch64.cc b/test/aarch64/test-api-aarch64.cc index cca50374..1cb66cd7 100644 --- a/test/aarch64/test-api-aarch64.cc +++ b/test/aarch64/test-api-aarch64.cc @@ -41,6 +41,67 @@ namespace vixl { namespace aarch64 { +// Check compiler intrinsics helpers. + +TEST(count_leading_sign_bits) { + class Helper { + public: + static void Check(int64_t value, int non_sign_bits) { + VIXL_ASSERT((0 <= non_sign_bits) && (non_sign_bits < 64)); + + for (int width = 1; width <= 64; width *= 2) { + // Note that leading_sign_bits does not include the topmost bit. + int leading_sign_bits = width - non_sign_bits - 1; + if (leading_sign_bits < 0) continue; + + int64_t result = CountLeadingSignBits(value, width); + int64_t fallback_result = CountLeadingSignBitsFallBack(value, width); + VIXL_CHECK(result == leading_sign_bits); + VIXL_CHECK(fallback_result == leading_sign_bits); + } + } + }; + + // Basic positive (and zero) cases. Sign bits are all zeroes. + Helper::Check(0, 0); // 0b++++ + Helper::Check(1, 1); // 0b+++1 + Helper::Check(2, 2); // 0b++10 + Helper::Check(3, 2); // 0b++11 + Helper::Check(4, 3); // 0b+100 + + // Basic negative cases. Sign bits are all ones. + Helper::Check(-1, 0); // 0b---- + Helper::Check(-2, 1); // 0b---0 + Helper::Check(-3, 2); // 0b--01 + Helper::Check(-4, 2); // 0b--00 + Helper::Check(-5, 3); // 0b-011 + + // Boundary conditions. + Helper::Check(INT8_MAX, 7); + Helper::Check(INT8_MIN, 7); + Helper::Check(static_cast<int64_t>(INT8_MAX) + 1, 8); + Helper::Check(static_cast<int64_t>(INT8_MIN) - 1, 8); + + Helper::Check(INT16_MAX, 15); + Helper::Check(INT16_MIN, 15); + Helper::Check(static_cast<int64_t>(INT16_MAX) + 1, 16); + Helper::Check(static_cast<int64_t>(INT16_MIN) - 1, 16); + + Helper::Check(INT32_MAX, 31); + Helper::Check(INT32_MIN, 31); + Helper::Check(static_cast<int64_t>(INT32_MAX) + 1, 32); + Helper::Check(static_cast<int64_t>(INT32_MIN) - 1, 32); + + Helper::Check(INT64_MAX, 63); + Helper::Check(INT64_MIN, 63); + + // Check automatic width detection. + VIXL_CHECK(CountLeadingSignBits(static_cast<int8_t>(42)) == 1); // 0b00101010 + VIXL_CHECK(CountLeadingSignBits(static_cast<int16_t>(42)) == 9); + VIXL_CHECK(CountLeadingSignBits(static_cast<int32_t>(42)) == 25); + VIXL_CHECK(CountLeadingSignBits(static_cast<int64_t>(42)) == 57); +} + // Check SimFloat16 class mechanics. TEST(float16_operators) { ::vixl::internal::SimFloat16 f1 = kFP16DefaultNaN; |