From 5671fde1aeef8da1e5e36380f242fda149cbe518 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 26 Apr 2020 18:32:23 +1000 Subject: [PATCH] BitUtils: Make Count{Leading,Trailing}Zeros UB for value==0 --- README.md | 1 + src/common/bitutils.h | 36 ++++++++++------------ src/duckstation-qt/inputbindingwidgets.cpp | 3 +- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c178ef069..3046dc6b7 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Other features include: - Direct booting of homebrew executables - Direct loading of Portable Sound Format (psf) files - Digital and analog controllers for input (rumble is forwarded to host) + - Namco GunCon lightgun support (simulated with mouse) - Qt and SDL frontends for desktop - Automatic content scanning - game titles/regions are provided by redump.org diff --git a/src/common/bitutils.h b/src/common/bitutils.h index e4a182422..12c1d211b 100644 --- a/src/common/bitutils.h +++ b/src/common/bitutils.h @@ -5,6 +5,7 @@ #include #endif +/// Returns the number of zero bits before the first set bit, going MSB->LSB. template ALWAYS_INLINE unsigned CountLeadingZeros(T value) { @@ -12,27 +13,26 @@ ALWAYS_INLINE unsigned CountLeadingZeros(T value) if constexpr (sizeof(value) >= sizeof(u64)) { unsigned long index; - return _BitScanReverse64(&index, ZeroExtend64(value)) ? static_cast(index) : 0; + _BitScanReverse64(&index, ZeroExtend64(value)); + return static_cast(index) ^ static_cast((sizeof(value) * 8u) - 1u); } else { unsigned long index; - return _BitScanReverse(&index, ZeroExtend32(value)) ? static_cast(index) : 0; + _BitScanReverse(&index, ZeroExtend32(value)); + return static_cast(index) ^ static_cast((sizeof(value) * 8u) - 1u); } #else if constexpr (sizeof(value) >= sizeof(u64)) - { - const unsigned bits = static_cast(__builtin_clzl(ZeroExtend64(value))); - return (value != 0) ? static_cast(bits) : 0; - } + return static_cast(__builtin_clzl(ZeroExtend64(value))); + else if constexpr (sizeof(value) == sizeof(u32)) + return static_cast(__builtin_clz(ZeroExtend32(value))); else - { - const unsigned bits = static_cast(__builtin_clz(ZeroExtend32(value))); - return (value != 0) ? static_cast(bits) : 0; - } + return static_cast(__builtin_clz(ZeroExtend32(value))) & static_cast((sizeof(value) * 8u) - 1u); #endif } +/// Returns the number of zero bits before the first set bit, going LSB->MSB. template ALWAYS_INLINE unsigned CountTrailingZeros(T value) { @@ -40,23 +40,19 @@ ALWAYS_INLINE unsigned CountTrailingZeros(T value) if constexpr (sizeof(value) >= sizeof(u64)) { unsigned long index; - return _BitScanForward64(&index, ZeroExtend64(value)) ? static_cast(index) : 0; + _BitScanForward64(&index, ZeroExtend64(value)); + return index; } else { unsigned long index; - return _BitScanForward(&index, ZeroExtend32(value)) ? static_cast(index) : 0; + _BitScanForward(&index, ZeroExtend32(value)); + return index; } #else if constexpr (sizeof(value) >= sizeof(u64)) - { - const unsigned bits = static_cast(__builtin_ctzl(ZeroExtend64(value))); - return (value != 0) ? static_cast(bits) : 0; - } + return static_cast(__builtin_ctzl(ZeroExtend64(value))); else - { - const unsigned bits = static_cast(__builtin_ctz(ZeroExtend32(value))); - return (value != 0) ? static_cast(bits) : 0; - } + return static_cast(__builtin_ctz(ZeroExtend32(value))); #endif } diff --git a/src/duckstation-qt/inputbindingwidgets.cpp b/src/duckstation-qt/inputbindingwidgets.cpp index f1357dd74..67ad82097 100644 --- a/src/duckstation-qt/inputbindingwidgets.cpp +++ b/src/duckstation-qt/inputbindingwidgets.cpp @@ -168,7 +168,8 @@ bool InputButtonBindingWidget::eventFilter(QObject* watched, QEvent* event) } else if (event_type == QEvent::MouseButtonRelease) { - const u32 button_index = CountTrailingZeros(static_cast(static_cast(event)->button())); + const u32 button_mask = static_cast(static_cast(event)->button()); + const u32 button_index = (button_mask == 0u) ? 0 : CountTrailingZeros(button_mask); m_new_binding_value = QStringLiteral("Mouse/Button%1").arg(button_index + 1); setNewBinding(); stopListeningForInput();