aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler-intrinsics-vixl.cc2
-rw-r--r--src/compiler-intrinsics-vixl.h19
-rw-r--r--test/aarch64/test-api-aarch64.cc61
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;