BitUtils: Make Count{Leading,Trailing}Zeros UB for value==0

This commit is contained in:
Connor McLaughlin 2020-04-26 18:32:23 +10:00
parent 38b075c014
commit 5671fde1ae
3 changed files with 19 additions and 21 deletions

View File

@ -27,6 +27,7 @@ Other features include:
- Direct booting of homebrew executables - Direct booting of homebrew executables
- Direct loading of Portable Sound Format (psf) files - Direct loading of Portable Sound Format (psf) files
- Digital and analog controllers for input (rumble is forwarded to host) - Digital and analog controllers for input (rumble is forwarded to host)
- Namco GunCon lightgun support (simulated with mouse)
- Qt and SDL frontends for desktop - Qt and SDL frontends for desktop
- Automatic content scanning - game titles/regions are provided by redump.org - Automatic content scanning - game titles/regions are provided by redump.org

View File

@ -5,6 +5,7 @@
#include <intrin.h> #include <intrin.h>
#endif #endif
/// Returns the number of zero bits before the first set bit, going MSB->LSB.
template<typename T> template<typename T>
ALWAYS_INLINE unsigned CountLeadingZeros(T value) ALWAYS_INLINE unsigned CountLeadingZeros(T value)
{ {
@ -12,27 +13,26 @@ ALWAYS_INLINE unsigned CountLeadingZeros(T value)
if constexpr (sizeof(value) >= sizeof(u64)) if constexpr (sizeof(value) >= sizeof(u64))
{ {
unsigned long index; unsigned long index;
return _BitScanReverse64(&index, ZeroExtend64(value)) ? static_cast<unsigned>(index) : 0; _BitScanReverse64(&index, ZeroExtend64(value));
return static_cast<unsigned>(index) ^ static_cast<unsigned>((sizeof(value) * 8u) - 1u);
} }
else else
{ {
unsigned long index; unsigned long index;
return _BitScanReverse(&index, ZeroExtend32(value)) ? static_cast<unsigned>(index) : 0; _BitScanReverse(&index, ZeroExtend32(value));
return static_cast<unsigned>(index) ^ static_cast<unsigned>((sizeof(value) * 8u) - 1u);
} }
#else #else
if constexpr (sizeof(value) >= sizeof(u64)) if constexpr (sizeof(value) >= sizeof(u64))
{ return static_cast<unsigned>(__builtin_clzl(ZeroExtend64(value)));
const unsigned bits = static_cast<unsigned>(__builtin_clzl(ZeroExtend64(value))); else if constexpr (sizeof(value) == sizeof(u32))
return (value != 0) ? static_cast<unsigned>(bits) : 0; return static_cast<unsigned>(__builtin_clz(ZeroExtend32(value)));
}
else else
{ return static_cast<unsigned>(__builtin_clz(ZeroExtend32(value))) & static_cast<unsigned>((sizeof(value) * 8u) - 1u);
const unsigned bits = static_cast<unsigned>(__builtin_clz(ZeroExtend32(value)));
return (value != 0) ? static_cast<unsigned>(bits) : 0;
}
#endif #endif
} }
/// Returns the number of zero bits before the first set bit, going LSB->MSB.
template<typename T> template<typename T>
ALWAYS_INLINE unsigned CountTrailingZeros(T value) ALWAYS_INLINE unsigned CountTrailingZeros(T value)
{ {
@ -40,23 +40,19 @@ ALWAYS_INLINE unsigned CountTrailingZeros(T value)
if constexpr (sizeof(value) >= sizeof(u64)) if constexpr (sizeof(value) >= sizeof(u64))
{ {
unsigned long index; unsigned long index;
return _BitScanForward64(&index, ZeroExtend64(value)) ? static_cast<unsigned>(index) : 0; _BitScanForward64(&index, ZeroExtend64(value));
return index;
} }
else else
{ {
unsigned long index; unsigned long index;
return _BitScanForward(&index, ZeroExtend32(value)) ? static_cast<unsigned>(index) : 0; _BitScanForward(&index, ZeroExtend32(value));
return index;
} }
#else #else
if constexpr (sizeof(value) >= sizeof(u64)) if constexpr (sizeof(value) >= sizeof(u64))
{ return static_cast<unsigned>(__builtin_ctzl(ZeroExtend64(value)));
const unsigned bits = static_cast<unsigned>(__builtin_ctzl(ZeroExtend64(value)));
return (value != 0) ? static_cast<unsigned>(bits) : 0;
}
else else
{ return static_cast<unsigned>(__builtin_ctz(ZeroExtend32(value)));
const unsigned bits = static_cast<unsigned>(__builtin_ctz(ZeroExtend32(value)));
return (value != 0) ? static_cast<unsigned>(bits) : 0;
}
#endif #endif
} }

View File

@ -168,7 +168,8 @@ bool InputButtonBindingWidget::eventFilter(QObject* watched, QEvent* event)
} }
else if (event_type == QEvent::MouseButtonRelease) else if (event_type == QEvent::MouseButtonRelease)
{ {
const u32 button_index = CountTrailingZeros(static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())); const u32 button_mask = static_cast<u32>(static_cast<const QMouseEvent*>(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); m_new_binding_value = QStringLiteral("Mouse/Button%1").arg(button_index + 1);
setNewBinding(); setNewBinding();
stopListeningForInput(); stopListeningForInput();