mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-26 13:52:21 +00:00
loader: avoid UB when doing count trailing zeros
This commit is contained in:
parent
15381409dc
commit
dbcb1e1564
2 changed files with 49 additions and 10 deletions
|
@ -175,6 +175,8 @@ namespace ams::util {
|
||||||
} else {
|
} else {
|
||||||
using U = typename std::make_unsigned<T>::type;
|
using U = typename std::make_unsigned<T>::type;
|
||||||
const U u = static_cast<U>(x);
|
const U u = static_cast<U>(x);
|
||||||
|
|
||||||
|
if (u != 0) {
|
||||||
if constexpr (std::is_same<U, unsigned long long>::value) {
|
if constexpr (std::is_same<U, unsigned long long>::value) {
|
||||||
return __builtin_clzll(u);
|
return __builtin_clzll(u);
|
||||||
} else if constexpr (std::is_same<U, unsigned long>::value) {
|
} else if constexpr (std::is_same<U, unsigned long>::value) {
|
||||||
|
@ -186,8 +188,45 @@ namespace ams::util {
|
||||||
constexpr size_t BitDiff = BITSIZEOF(unsigned int) - BITSIZEOF(U);
|
constexpr size_t BitDiff = BITSIZEOF(unsigned int) - BITSIZEOF(U);
|
||||||
return __builtin_clz(static_cast<unsigned int>(u)) - BitDiff;
|
return __builtin_clz(static_cast<unsigned int>(u)) - BitDiff;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return BITSIZEOF(U);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(CountLeadingZeros(~static_cast<u64>(0)) == 0);
|
||||||
|
static_assert(CountLeadingZeros(static_cast<u64>(0)) == BITSIZEOF(u64));
|
||||||
|
|
||||||
|
template<typename T> requires std::integral<T>
|
||||||
|
constexpr ALWAYS_INLINE int CountTrailingZeros(T x) {
|
||||||
|
if (std::is_constant_evaluated()) {
|
||||||
|
auto count = 0;
|
||||||
|
for (size_t i = 0; i < BITSIZEOF(T) && (x & 1) == 0; ++i) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
} else {
|
||||||
|
using U = typename std::make_unsigned<T>::type;
|
||||||
|
const U u = static_cast<U>(x);
|
||||||
|
if (u != 0) {
|
||||||
|
if constexpr (std::is_same<U, unsigned long long>::value) {
|
||||||
|
return __builtin_ctzll(u);
|
||||||
|
} else if constexpr (std::is_same<U, unsigned long>::value) {
|
||||||
|
return __builtin_ctzl(u);
|
||||||
|
} else if constexpr(std::is_same<U, unsigned int>::value) {
|
||||||
|
return __builtin_ctz(u);
|
||||||
|
} else {
|
||||||
|
static_assert(sizeof(U) < sizeof(unsigned int));
|
||||||
|
return __builtin_ctz(static_cast<unsigned int>(u));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return BITSIZEOF(U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(CountTrailingZeros(~static_cast<u64>(0)) == 0);
|
||||||
|
static_assert(CountTrailingZeros(static_cast<u64>(0)) == BITSIZEOF(u64));
|
||||||
|
|
||||||
template<typename T> requires std::integral<T>
|
template<typename T> requires std::integral<T>
|
||||||
constexpr ALWAYS_INLINE bool IsPowerOfTwo(T x) {
|
constexpr ALWAYS_INLINE bool IsPowerOfTwo(T x) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace ams::ldr::caps {
|
||||||
constexpr ALWAYS_INLINE typename name::Type Get##name() const { return this->Get<name>(); }
|
constexpr ALWAYS_INLINE typename name::Type Get##name() const { return this->Get<name>(); }
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE CapabilityId GetCapabilityId(util::BitPack32 cap) {
|
constexpr ALWAYS_INLINE CapabilityId GetCapabilityId(util::BitPack32 cap) {
|
||||||
return static_cast<CapabilityId>(__builtin_ctz(~cap.value));
|
return static_cast<CapabilityId>(util::CountTrailingZeros<u32>(~cap.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline util::BitPack32 EmptyCapability = {~u32{}};
|
constexpr inline util::BitPack32 EmptyCapability = {~u32{}};
|
||||||
|
|
Loading…
Reference in a new issue