From 3bc815a5dc18a646334ba933c74ce7ce44099625 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Fri, 15 Mar 2019 23:18:11 -0400
Subject: [PATCH] Implement intrinsics CountTrailingZeroes and test it.

---
 src/common/bit_util.h          | 45 +++++++++++++++++++++++++---------
 src/tests/CMakeLists.txt       |  1 +
 src/tests/common/bit_utils.cpp | 42 +++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+), 12 deletions(-)
 create mode 100644 src/tests/common/bit_utils.cpp

diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index 14e53c2732..70e728a5ef 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -59,22 +59,43 @@ inline u64 CountLeadingZeroes64(u64 value) {
 }
 #endif
 
+
+#ifdef _MSC_VER
 inline u32 CountTrailingZeroes32(u32 value) {
-  u32 count = 0;
-  while (((value >> count) & 0xf) == 0 && count < 32)
-    count += 4;
-  while (((value >> count) & 1) == 0 && count < 32)
-    count++;
-  return count;
+    unsigned long trailing_zero = 0;
+
+    if (_BitScanForward(&trailing_zero, value) != 0) {
+        return trailing_zero;
+    }
+
+    return 32;
 }
 
 inline u64 CountTrailingZeroes64(u64 value) {
-  u64 count = 0;
-  while (((value >> count) & 0xf) == 0 && count < 64)
-    count += 4;
-  while (((value >> count) & 1) == 0 && count < 64)
-    count++;
-  return count;
+    unsigned long trailing_zero = 0;
+
+    if (_BitScanForward64(&trailing_zero, value) != 0) {
+        return trailing_zero;
+    }
+
+    return 64;
+}
+#else
+inline u32 CountTrailingZeroes32(u32 value) {
+    if (value == 0) {
+        return 32;
+    }
+
+    return __builtin_ctz(value);
 }
 
+inline u64 CountTrailingZeroes64(u64 value) {
+    if (value == 0) {
+        return 64;
+    }
+
+    return __builtin_ctzll(value);
+}
+#endif
+
 } // namespace Common
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index d0284bdf4c..f38267be89 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_executable(tests
     common/bit_field.cpp
+    common/bit_utils.cpp
     common/param_package.cpp
     common/ring_buffer.cpp
     core/arm/arm_test_common.cpp
diff --git a/src/tests/common/bit_utils.cpp b/src/tests/common/bit_utils.cpp
new file mode 100644
index 0000000000..77c17c526b
--- /dev/null
+++ b/src/tests/common/bit_utils.cpp
@@ -0,0 +1,42 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <catch2/catch.hpp>
+#include <math.h>
+#include "common/bit_util.h"
+
+namespace Common {
+
+inline u32 CTZ32(u32 value) {
+  u32 count = 0;
+  while (((value >> count) & 0xf) == 0 && count < 32)
+    count += 4;
+  while (((value >> count) & 1) == 0 && count < 32)
+    count++;
+  return count;
+}
+
+inline u64 CTZ64(u64 value) {
+  u64 count = 0;
+  while (((value >> count) & 0xf) == 0 && count < 64)
+    count += 4;
+  while (((value >> count) & 1) == 0 && count < 64)
+    count++;
+  return count;
+}
+
+
+TEST_CASE("BitUtils", "[common]") {
+    REQUIRE(Common::CountTrailingZeroes32(0) == CTZ32(0));
+    REQUIRE(Common::CountTrailingZeroes64(0) == CTZ64(0));
+    REQUIRE(Common::CountTrailingZeroes32(9) == CTZ32(9));
+    REQUIRE(Common::CountTrailingZeroes32(8) == CTZ32(8));
+    REQUIRE(Common::CountTrailingZeroes32(0x801000) == CTZ32(0x801000));
+    REQUIRE(Common::CountTrailingZeroes64(9) == CTZ64(9));
+    REQUIRE(Common::CountTrailingZeroes64(8) == CTZ64(8));
+    REQUIRE(Common::CountTrailingZeroes64(0x801000) == CTZ64(0x801000));
+    REQUIRE(Common::CountTrailingZeroes64(0x801000000000UL) == CTZ64(0x801000000000UL));
+}
+
+} // namespace Common