Explorar o código

AK+Everywhere: Replace __builtin bit functions

In order to reduce our reliance on __builtin_{ffs, clz, ctz, popcount},
this commit removes all calls to these functions and replaces them with
the equivalent functions in AK/BuiltinWrappers.h.
Nick Johnson %!s(int64=3) %!d(string=hai) anos
pai
achega
08e4a1a4dc

+ 34 - 34
AK/BitmapView.h

@@ -54,30 +54,30 @@ public:
         byte &= bitmask_first_byte[start % 8];
         if (first == last) {
             byte &= bitmask_last_byte[(start + len) % 8];
-            count = __builtin_popcount(byte);
+            count = popcount(byte);
         } else {
-            count = __builtin_popcount(byte);
+            count = popcount(byte);
             // Don't access *last if it's out of bounds
             if (last < &m_data[size_in_bytes()]) {
                 byte = *last;
                 byte &= bitmask_last_byte[(start + len) % 8];
-                count += __builtin_popcount(byte);
+                count += popcount(byte);
             }
             if (++first < last) {
-                const u32* ptr32 = (const u32*)(((FlatPtr)first + sizeof(u32) - 1) & ~(sizeof(u32) - 1));
-                if ((const u8*)ptr32 > last)
-                    ptr32 = (const u32*)last;
-                while (first < (const u8*)ptr32) {
-                    count += __builtin_popcount(*first);
+                const size_t* ptr_large = (const size_t*)(((FlatPtr)first + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1));
+                if ((const u8*)ptr_large > last)
+                    ptr_large = (const size_t*)last;
+                while (first < (const u8*)ptr_large) {
+                    count += popcount(*first);
                     first++;
                 }
-                const u32* last32 = (const u32*)((FlatPtr)last & ~(sizeof(u32) - 1));
-                while (ptr32 < last32) {
-                    count += __builtin_popcountl(*ptr32);
-                    ptr32++;
+                const size_t* last_large = (const size_t*)((FlatPtr)last & ~(sizeof(size_t) - 1));
+                while (ptr_large < last_large) {
+                    count += popcount(*ptr_large);
+                    ptr_large++;
                 }
-                for (first = (const u8*)ptr32; first < last; first++)
-                    count += __builtin_popcount(*first);
+                for (first = (const u8*)ptr_large; first < last; first++)
+                    count += popcount(*first);
             }
         }
 
@@ -100,34 +100,34 @@ public:
             // We will use hint as what it is: a hint. Because we try to
             // scan over entire 32 bit words, we may start searching before
             // the hint!
-            const u32* ptr32 = (const u32*)((FlatPtr)&m_data[hint / 8] & ~(sizeof(u32) - 1));
-            if ((const u8*)ptr32 < &m_data[0]) {
-                ptr32++;
+            const size_t* ptr_large = (const size_t*)((FlatPtr)&m_data[hint / 8] & ~(sizeof(size_t) - 1));
+            if ((const u8*)ptr_large < &m_data[0]) {
+                ptr_large++;
 
                 // m_data isn't aligned, check first bytes
-                size_t start_ptr32 = (const u8*)ptr32 - &m_data[0];
+                size_t start_ptr_large = (const u8*)ptr_large - &m_data[0];
                 size_t i = 0;
                 u8 byte = VALUE ? 0x00 : 0xff;
-                while (i < start_ptr32 && m_data[i] == byte)
+                while (i < start_ptr_large && m_data[i] == byte)
                     i++;
-                if (i < start_ptr32) {
+                if (i < start_ptr_large) {
                     byte = m_data[i];
                     if constexpr (!VALUE)
                         byte = ~byte;
                     VERIFY(byte != 0);
-                    return i * 8 + __builtin_ffs(byte) - 1;
+                    return i * 8 + bit_scan_forward(byte) - 1;
                 }
             }
 
-            u32 val32 = VALUE ? 0x0 : 0xffffffff;
-            const u32* end32 = (const u32*)((FlatPtr)end & ~(sizeof(u32) - 1));
-            while (ptr32 < end32 && *ptr32 == val32)
-                ptr32++;
+            size_t val_large = VALUE ? 0x0 : NumericLimits<size_t>::max();
+            const size_t* end_large = (const size_t*)((FlatPtr)end & ~(sizeof(size_t) - 1));
+            while (ptr_large < end_large && *ptr_large == val_large)
+                ptr_large++;
 
-            if (ptr32 == end32) {
+            if (ptr_large == end_large) {
                 // We didn't find anything, check the remaining few bytes (if any)
                 u8 byte = VALUE ? 0x00 : 0xff;
-                size_t i = (const u8*)ptr32 - &m_data[0];
+                size_t i = (const u8*)ptr_large - &m_data[0];
                 size_t byte_count = m_size / 8;
                 VERIFY(i <= byte_count);
                 while (i < byte_count && m_data[i] == byte)
@@ -137,7 +137,7 @@ public:
                         return {}; // We already checked from the beginning
 
                     // Try scanning before the hint
-                    end = (const u8*)((FlatPtr)&m_data[hint / 8] & ~(sizeof(u32) - 1));
+                    end = (const u8*)((FlatPtr)&m_data[hint / 8] & ~(sizeof(size_t) - 1));
                     hint = 0;
                     continue;
                 }
@@ -145,16 +145,16 @@ public:
                 if constexpr (!VALUE)
                     byte = ~byte;
                 VERIFY(byte != 0);
-                return i * 8 + __builtin_ffs(byte) - 1;
+                return i * 8 + bit_scan_forward(byte) - 1;
             }
 
             // NOTE: We don't really care about byte ordering. We found *one*
             // free bit, just calculate the position and return it
-            val32 = *ptr32;
+            val_large = *ptr_large;
             if constexpr (!VALUE)
-                val32 = ~val32;
-            VERIFY(val32 != 0);
-            return ((const u8*)ptr32 - &m_data[0]) * 8 + __builtin_ffsl(val32) - 1;
+                val_large = ~val_large;
+            VERIFY(val_large != 0);
+            return ((const u8*)ptr_large - &m_data[0]) * 8 + bit_scan_forward(val_large) - 1;
         }
     }
 
@@ -184,7 +184,7 @@ public:
         if constexpr (!VALUE)
             byte = ~byte;
         VERIFY(byte != 0);
-        return i * 8 + __builtin_ffs(byte) - 1;
+        return i * 8 + bit_scan_forward(byte) - 1;
     }
 
     Optional<size_t> find_first_set() const { return find_first<true>(); }

+ 22 - 1
AK/BuiltinWrappers.h

@@ -7,7 +7,6 @@
 #pragma once
 
 #include "Concepts.h"
-#include "Platform.h"
 
 template<Unsigned IntType>
 inline constexpr int popcount(IntType value)
@@ -108,3 +107,25 @@ inline constexpr int count_leading_zeroes_safe(IntType value)
         return 8 * sizeof(IntType);
     return count_leading_zeroes(value);
 }
+
+// The function will return the number of leading zeroes in the type. If
+// the given number is zero, this function will return the number of bits
+// in the IntType.
+template<Integral IntType>
+inline constexpr int bit_scan_forward(IntType value)
+{
+#if defined(__GNUC__) || defined(__clang__)
+    static_assert(sizeof(IntType) <= sizeof(unsigned long long));
+    if constexpr (sizeof(IntType) <= sizeof(unsigned int))
+        return __builtin_ffs(value);
+    if constexpr (sizeof(IntType) == sizeof(unsigned long))
+        return __builtin_ffsl(value);
+    if constexpr (sizeof(IntType) == sizeof(unsigned long long))
+        return __builtin_ffsll(value);
+    VERIFY_NOT_REACHED();
+#else
+    if (value == 0)
+        return 0;
+    return 1 + count_trailing_zeroes(static_cast<MakeUnsigned<IntType>>(value));
+#endif
+}

+ 2 - 17
AK/Math.h

@@ -6,6 +6,7 @@
 
 #pragma once
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Concepts.h>
 #include <AK/StdLibExtraDetails.h>
 #include <AK/Types.h>
@@ -45,21 +46,6 @@ constexpr size_t product_odd() { return value * product_odd<value - 2>(); }
             return __builtin_##function##f(args); \
     }
 
-#define INTEGER_BUILTIN(name)                         \
-    template<Integral T>                              \
-    constexpr T name(T x)                             \
-    {                                                 \
-        if constexpr (sizeof(T) == sizeof(long long)) \
-            return __builtin_##name##ll(x);           \
-        if constexpr (sizeof(T) == sizeof(long))      \
-            return __builtin_##name##l(x);            \
-        return __builtin_##name(x);                   \
-    }
-
-INTEGER_BUILTIN(clz);
-INTEGER_BUILTIN(ctz);
-INTEGER_BUILTIN(popcnt);
-
 namespace Division {
 template<FloatingPoint T>
 constexpr T fmod(T x, T y)
@@ -312,7 +298,7 @@ constexpr T log2(T x)
 template<Integral T>
 constexpr T log2(T x)
 {
-    return x ? 8 * sizeof(T) - clz(x) : 0;
+    return x ? 8 * sizeof(T) - count_leading_zeroes(static_cast<MakeUnsigned<T>>(x)) : 0;
 }
 
 template<FloatingPoint T>
@@ -468,6 +454,5 @@ constexpr T pow(T x, T y)
 }
 
 #undef CONSTEXPR_STATE
-#undef INTEGER_BUILTIN
 
 }

+ 0 - 23
AK/Platform.h

@@ -106,29 +106,6 @@ extern "C" {
 #    endif
 #endif
 
-#ifdef __cplusplus
-ALWAYS_INLINE int count_trailing_zeroes_32(unsigned int val)
-{
-#    if defined(__GNUC__) || defined(__clang__)
-    return __builtin_ctz(val);
-#    else
-    for (u8 i = 0; i < 32; ++i) {
-        if ((val >> i) & 1) {
-            return i;
-        }
-    }
-    return 0;
-#    endif
-}
-
-ALWAYS_INLINE int count_trailing_zeroes_32_safe(unsigned int val)
-{
-    if (val == 0)
-        return 32;
-    return count_trailing_zeroes_32(val);
-}
-#endif
-
 #ifdef AK_OS_BSD_GENERIC
 #    define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
 #    define CLOCK_REALTIME_COARSE CLOCK_REALTIME

+ 8 - 7
AK/UFixedBigInt.h

@@ -6,6 +6,7 @@
 
 #pragma once
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Checked.h>
 #include <AK/Concepts.h>
 #include <AK/Format.h>
@@ -90,9 +91,9 @@ public:
     constexpr size_t clz() const requires(IsSame<T, u64>)
     {
         if (m_high)
-            return __builtin_clzll(m_high);
+            return count_leading_zeroes(m_high);
         else
-            return sizeof(T) * 8 + __builtin_clzll(m_low);
+            return sizeof(T) * 8 + count_leading_zeroes(m_low);
     }
     constexpr size_t clz() const requires(!IsSame<T, u64>)
     {
@@ -104,9 +105,9 @@ public:
     constexpr size_t ctz() const requires(IsSame<T, u64>)
     {
         if (m_low)
-            return __builtin_ctzll(m_low);
+            return count_trailing_zeroes(m_low);
         else
-            return sizeof(T) * 8 + __builtin_ctzll(m_high);
+            return sizeof(T) * 8 + count_trailing_zeroes(m_high);
     }
     constexpr size_t ctz() const requires(!IsSame<T, u64>)
     {
@@ -598,7 +599,7 @@ public:
         R x1 = *this;
         R x2 = *this * *this;
         u64 exp_copy = exp;
-        for (ssize_t i = sizeof(u64) * 8 - __builtin_clzll(exp) - 2; i >= 0; --i) {
+        for (ssize_t i = sizeof(u64) * 8 - count_leading_zeroes(exp) - 2; i >= 0; --i) {
             if (exp_copy & 1u) {
                 x2 *= x1;
                 x1 *= x1;
@@ -642,7 +643,7 @@ public:
 
         U res = 1;
         u64 exp_copy = exp;
-        for (size_t i = sizeof(u64) - __builtin_clzll(exp) - 1u; i < exp; ++i) {
+        for (size_t i = sizeof(u64) - count_leading_zeroes(exp) - 1u; i < exp; ++i) {
             res *= res;
             res %= mod;
             if (exp_copy & 1u) {
@@ -682,7 +683,7 @@ public:
     constexpr size_t logn(u64 base)
     {
         // FIXME: proper rounding
-        return log2() / (sizeof(u64) - __builtin_clzll(base));
+        return log2() / (sizeof(u64) - count_leading_zeroes(base));
     }
     template<Unsigned U>
     requires(sizeof(U) > sizeof(u64)) constexpr size_t logn(U base)

+ 5 - 4
Kernel/Arch/x86/common/Processor.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Format.h>
 #include <AK/StdLibExtras.h>
 #include <AK/String.h>
@@ -771,13 +772,13 @@ u32 Processor::smp_wake_n_idle_processors(u32 wake_count)
     while (did_wake_count < wake_count) {
         // Try to get a set of idle CPUs and flip them to busy
         u32 idle_mask = s_idle_cpu_mask.load(AK::MemoryOrder::memory_order_relaxed) & ~(1u << current_id);
-        u32 idle_count = __builtin_popcountl(idle_mask);
+        u32 idle_count = popcount(idle_mask);
         if (idle_count == 0)
             break; // No (more) idle processor available
 
         u32 found_mask = 0;
         for (u32 i = 0; i < idle_count; i++) {
-            u32 cpu = __builtin_ffsl(idle_mask) - 1;
+            u32 cpu = bit_scan_forward(idle_mask) - 1;
             idle_mask &= ~(1u << cpu);
             found_mask |= 1u << cpu;
         }
@@ -785,9 +786,9 @@ u32 Processor::smp_wake_n_idle_processors(u32 wake_count)
         idle_mask = s_idle_cpu_mask.fetch_and(~found_mask, AK::MemoryOrder::memory_order_acq_rel) & found_mask;
         if (idle_mask == 0)
             continue; // All of them were flipped to busy, try again
-        idle_count = __builtin_popcountl(idle_mask);
+        idle_count = popcount(idle_mask);
         for (u32 i = 0; i < idle_count; i++) {
-            u32 cpu = __builtin_ffsl(idle_mask) - 1;
+            u32 cpu = bit_scan_forward(idle_mask) - 1;
             idle_mask &= ~(1u << cpu);
 
             // Send an IPI to that CPU to wake it up. There is a possibility

+ 2 - 1
Kernel/Memory/PhysicalRegion.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/NonnullRefPtr.h>
 #include <AK/RefPtr.h>
 #include <Kernel/Assertions.h>
@@ -80,7 +81,7 @@ OwnPtr<PhysicalRegion> PhysicalRegion::try_take_pages_from_beginning(unsigned pa
 NonnullRefPtrVector<PhysicalPage> PhysicalRegion::take_contiguous_free_pages(size_t count)
 {
     auto rounded_page_count = next_power_of_two(count);
-    auto order = __builtin_ctz(rounded_page_count);
+    auto order = count_trailing_zeroes(rounded_page_count);
 
     Optional<PhysicalAddress> page_base;
     for (auto& zone : m_usable_zones) {

+ 2 - 1
Kernel/Memory/PhysicalZone.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Format.h>
 #include <Kernel/Memory/MemoryManager.h>
 #include <Kernel/Memory/PhysicalPage.h>
@@ -31,7 +32,7 @@ PhysicalZone::PhysicalZone(PhysicalAddress base_address, size_t page_count)
             bucket.bitmap.grow(bitmap_size_for_order, false);
     }
 
-    auto first_order = __builtin_ctz(page_count);
+    auto first_order = count_trailing_zeroes(page_count);
     size_t block_size = 2u << first_order;
     auto& bucket = m_buckets[first_order];
     size_t remaining_chunk_count = chunk_count;

+ 3 - 2
Kernel/Scheduler.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/ScopeGuard.h>
 #include <AK/Singleton.h>
 #include <AK/Time.h>
@@ -77,7 +78,7 @@ Thread& Scheduler::pull_next_runnable_thread()
     return g_ready_queues->with([&](auto& ready_queues) -> Thread& {
         auto priority_mask = ready_queues.mask;
         while (priority_mask != 0) {
-            auto priority = __builtin_ffsl(priority_mask);
+            auto priority = bit_scan_forward(priority_mask);
             VERIFY(priority > 0);
             auto& ready_queue = ready_queues.queues[--priority];
             for (auto& thread : ready_queue.thread_list) {
@@ -116,7 +117,7 @@ Thread* Scheduler::peek_next_runnable_thread()
     return g_ready_queues->with([&](auto& ready_queues) -> Thread* {
         auto priority_mask = ready_queues.mask;
         while (priority_mask != 0) {
-            auto priority = __builtin_ffsl(priority_mask);
+            auto priority = bit_scan_forward(priority_mask);
             VERIFY(priority > 0);
             auto& ready_queue = ready_queues.queues[--priority];
             for (auto& thread : ready_queue.thread_list) {

+ 3 - 2
Kernel/Storage/ATA/AHCIController.cpp

@@ -5,6 +5,7 @@
  */
 
 #include <AK/Atomic.h>
+#include <AK/BuiltinWrappers.h>
 #include <AK/OwnPtr.h>
 #include <AK/RefPtr.h>
 #include <AK/Types.h>
@@ -185,12 +186,12 @@ RefPtr<StorageDevice> AHCIController::device(u32 index) const
 {
     NonnullRefPtrVector<StorageDevice> connected_devices;
     u32 pi = hba().control_regs.pi;
-    u32 bit = __builtin_ffsl(pi);
+    u32 bit = bit_scan_forward(pi);
     while (bit) {
         dbgln_if(AHCI_DEBUG, "Checking implemented port {}, pi {:b}", bit - 1, pi);
         pi &= ~(1u << (bit - 1));
         auto checked_device = device_by_port(bit - 1);
-        bit = __builtin_ffsl(pi);
+        bit = bit_scan_forward(pi);
         if (checked_device.is_null())
             continue;
         connected_devices.append(checked_device.release_nonnull());

+ 2 - 1
Kernel/ThreadBlockers.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <Kernel/Debug.h>
 #include <Kernel/FileSystem/OpenFileDescription.h>
 #include <Kernel/Net/Socket.h>
@@ -473,7 +474,7 @@ bool Thread::SignalBlocker::check_pending_signals(bool from_add_blocker)
         if (m_did_unblock)
             return false;
 
-        auto matching_pending_signal = __builtin_ffsl(thread().pending_signals() & m_pending_set);
+        auto matching_pending_signal = bit_scan_forward(thread().pending_signals() & m_pending_set);
         if (matching_pending_signal == 0)
             return false;
 

+ 2 - 1
Userland/DevTools/UserspaceEmulator/SoftCPU.cpp

@@ -8,6 +8,7 @@
 #include "SoftCPU.h"
 #include "Emulator.h"
 #include <AK/Assertions.h>
+#include <AK/BuiltinWrappers.h>
 #include <AK/Debug.h>
 #include <stdio.h>
 #include <string.h>
@@ -978,7 +979,7 @@ void SoftCPU::BOUND(const X86::Instruction&) { TODO_INSN(); }
 template<typename T>
 ALWAYS_INLINE static T op_bsf(SoftCPU&, T value)
 {
-    return { (typename T::ValueType)__builtin_ctz(value.value()), value.shadow() };
+    return { (typename T::ValueType)bit_scan_forward(value.value()), value.shadow() };
 }
 
 template<typename T>

+ 2 - 1
Userland/Libraries/LibC/malloc.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Debug.h>
 #include <AK/ScopedValueRollback.h>
 #include <AK/Vector.h>
@@ -437,7 +438,7 @@ void* malloc(size_t size)
 // _aligned_free(), so it can be easily implemented on top of malloc().
 void* _aligned_malloc(size_t size, size_t alignment)
 {
-    if (__builtin_popcount(alignment) != 1) {
+    if (popcount(alignment) != 1) {
         errno = EINVAL;
         return nullptr;
     }

+ 2 - 1
Userland/Libraries/LibCrypto/BigInt/Algorithms/BitwiseOperations.cpp

@@ -6,6 +6,7 @@
  */
 
 #include "UnsignedBigIntegerAlgorithms.h"
+#include <AK/BuiltinWrappers.h>
 
 namespace Crypto {
 
@@ -153,7 +154,7 @@ FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_not_without_allocation(
     auto last_word_index = right.length() - 1;
     auto last_word = right.words()[last_word_index];
 
-    output.m_words[last_word_index] = ((u32)0xffffffffffffffff >> __builtin_clz(last_word)) & ~last_word;
+    output.m_words[last_word_index] = ((u32)0xffffffffffffffff >> count_leading_zeroes(last_word)) & ~last_word;
 }
 
 /**

+ 3 - 2
Userland/Libraries/LibGfx/BMPLoader.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Debug.h>
 #include <AK/Function.h>
 #include <AK/String.h>
@@ -326,9 +327,9 @@ static void populate_dib_mask_info_if_needed(BMPLoadingContext& context)
             mask_sizes.append(0);
             continue;
         }
-        int trailing_zeros = count_trailing_zeroes_32(mask);
+        int trailing_zeros = count_trailing_zeroes(mask);
         // If mask is exactly `0xFFFFFFFF`, then we might try to count the trailing zeros of 0x00000000 here, so we need the safe version:
-        int size = count_trailing_zeroes_32_safe(~(mask >> trailing_zeros));
+        int size = count_trailing_zeroes_safe(~(mask >> trailing_zeros));
         if (size > 8) {
             // Drop lowest bits if mask is longer than 8 bits.
             trailing_zeros += size - 8;

+ 3 - 2
Userland/Libraries/LibGfx/BitmapFont.cpp

@@ -6,6 +6,7 @@
 
 #include "BitmapFont.h"
 #include "Emoji.h"
+#include <AK/BuiltinWrappers.h>
 #include <AK/Utf32View.h>
 #include <AK/Utf8View.h>
 #include <LibCore/FileStream.h>
@@ -95,7 +96,7 @@ NonnullRefPtr<BitmapFont> BitmapFont::masked_character_set() const
     }
     size_t new_glyph_count { 0 };
     for (size_t i = 0; i < new_range_mask_size; ++i) {
-        new_glyph_count += 256 * __builtin_popcount(new_range_mask[i]);
+        new_glyph_count += 256 * popcount(new_range_mask[i]);
     }
     size_t bytes_per_glyph = sizeof(u32) * m_glyph_height;
     auto* new_rows = static_cast<u8*>(calloc(new_glyph_count, bytes_per_glyph));
@@ -191,7 +192,7 @@ RefPtr<BitmapFont> BitmapFont::load_from_memory(const u8* data)
     size_t glyph_count { 0 };
     u8* range_mask = const_cast<u8*>(data + sizeof(FontFileHeader));
     for (size_t i = 0; i < header.range_mask_size; ++i)
-        glyph_count += 256 * __builtin_popcount(range_mask[i]);
+        glyph_count += 256 * popcount(range_mask[i]);
     u8* rows = range_mask + header.range_mask_size;
     u8* widths = (u8*)(rows) + glyph_count * bytes_per_glyph;
     return adopt_ref(*new BitmapFont(String(header.name), String(header.family), rows, widths, !header.is_variable_width, header.glyph_width, header.glyph_height, header.glyph_spacing, header.range_mask_size, range_mask, header.baseline, header.mean_line, header.presentation_size, header.weight, header.slope));

+ 2 - 1
Userland/Libraries/LibJS/Runtime/GlobalObject.cpp

@@ -5,6 +5,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/CharacterTypes.h>
 #include <AK/Hex.h>
 #include <AK/Platform.h>
@@ -500,7 +501,7 @@ static ThrowCompletionOr<String> decode(JS::GlobalObject& global_object, const S
             continue;
         }
 
-        auto leading_ones = count_trailing_zeroes_32_safe(~decoded_code_unit) - 24;
+        auto leading_ones = count_trailing_zeroes_safe(static_cast<u32>(~decoded_code_unit)) - 24;
         if (leading_ones == 1 || leading_ones > 4)
             return global_object.vm().throw_completion<URIError>(global_object, ErrorType::URIMalformed);
 

+ 2 - 1
Userland/Libraries/LibJS/Runtime/MathObject.cpp

@@ -6,6 +6,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/Function.h>
 #include <AK/Random.h>
 #include <LibJS/Runtime/GlobalObject.h>
@@ -303,7 +304,7 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::clz32)
     auto number = TRY(vm.argument(0).to_u32(global_object));
     if (number == 0)
         return Value(32);
-    return Value(__builtin_clz(number));
+    return Value(count_leading_zeroes(number));
 }
 
 // 21.3.2.2 Math.acos ( x ), https://tc39.es/ecma262/#sec-math.acos

+ 2 - 1
Userland/Libraries/LibM/math.cpp

@@ -5,6 +5,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/BuiltinWrappers.h>
 #include <AK/ExtraMathConstants.h>
 #include <AK/Math.h>
 #include <AK/Platform.h>
@@ -278,7 +279,7 @@ static FloatT internal_scalbn(FloatT x, int exponent) NOEXCEPT
         return extractor.d;
     }
 
-    unsigned leading_mantissa_zeroes = extractor.mantissa == 0 ? 32 : __builtin_clz(extractor.mantissa);
+    unsigned leading_mantissa_zeroes = extractor.mantissa == 0 ? 32 : count_leading_zeroes(extractor.mantissa);
     int shift = min((int)leading_mantissa_zeroes, exponent);
     exponent = max(exponent - shift, 0);
 

+ 7 - 12
Userland/Libraries/LibWasm/AbstractMachine/Operators.h

@@ -7,6 +7,7 @@
 #pragma once
 
 #include <AK/BitCast.h>
+#include <AK/BuiltinWrappers.h>
 #include <AK/Result.h>
 #include <AK/StringView.h>
 #include <AK/Types.h>
@@ -176,10 +177,8 @@ struct CountLeadingZeros {
         if (lhs == 0)
             return sizeof(Lhs) * CHAR_BIT;
 
-        if constexpr (sizeof(Lhs) == 4)
-            return __builtin_clz(lhs);
-        else if constexpr (sizeof(Lhs) == 8)
-            return __builtin_clzll(lhs);
+        if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
+            return count_leading_zeroes(MakeUnsigned<Lhs>(lhs));
         else
             VERIFY_NOT_REACHED();
     }
@@ -193,10 +192,8 @@ struct CountTrailingZeros {
         if (lhs == 0)
             return sizeof(Lhs) * CHAR_BIT;
 
-        if constexpr (sizeof(Lhs) == 4)
-            return __builtin_ctz(lhs);
-        else if constexpr (sizeof(Lhs) == 8)
-            return __builtin_ctzll(lhs);
+        if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
+            return count_trailing_zeroes(MakeUnsigned<Lhs>(lhs));
         else
             VERIFY_NOT_REACHED();
     }
@@ -207,10 +204,8 @@ struct PopCount {
     template<typename Lhs>
     auto operator()(Lhs lhs) const
     {
-        if constexpr (sizeof(Lhs) == 4)
-            return __builtin_popcount(lhs);
-        else if constexpr (sizeof(Lhs) == 8)
-            return __builtin_popcountll(lhs);
+        if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
+            return popcount(MakeUnsigned<Lhs>(lhs));
         else
             VERIFY_NOT_REACHED();
     }