mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-22 11:56:40 +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,20 +175,59 @@ namespace ams::util {
|
|||
} else {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
const U u = static_cast<U>(x);
|
||||
if constexpr (std::is_same<U, unsigned long long>::value) {
|
||||
return __builtin_clzll(u);
|
||||
} else if constexpr (std::is_same<U, unsigned long>::value) {
|
||||
return __builtin_clzl(u);
|
||||
} else if constexpr(std::is_same<U, unsigned int>::value) {
|
||||
return __builtin_clz(u);
|
||||
|
||||
if (u != 0) {
|
||||
if constexpr (std::is_same<U, unsigned long long>::value) {
|
||||
return __builtin_clzll(u);
|
||||
} else if constexpr (std::is_same<U, unsigned long>::value) {
|
||||
return __builtin_clzl(u);
|
||||
} else if constexpr(std::is_same<U, unsigned int>::value) {
|
||||
return __builtin_clz(u);
|
||||
} else {
|
||||
static_assert(sizeof(U) < sizeof(unsigned int));
|
||||
constexpr size_t BitDiff = BITSIZEOF(unsigned int) - BITSIZEOF(U);
|
||||
return __builtin_clz(static_cast<unsigned int>(u)) - BitDiff;
|
||||
}
|
||||
} else {
|
||||
static_assert(sizeof(U) < sizeof(unsigned int));
|
||||
constexpr size_t BitDiff = BITSIZEOF(unsigned int) - BITSIZEOF(U);
|
||||
return __builtin_clz(static_cast<unsigned int>(u)) - BitDiff;
|
||||
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>
|
||||
constexpr ALWAYS_INLINE bool IsPowerOfTwo(T x) {
|
||||
return x > 0 && ResetLeastSignificantOneBit(x) == 0;
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace ams::ldr::caps {
|
|||
constexpr ALWAYS_INLINE typename name::Type Get##name() const { return this->Get<name>(); }
|
||||
|
||||
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{}};
|
||||
|
|
Loading…
Reference in a new issue