diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 7f0a6d069e37c63d21b499bfe6398b51f9ee402f..dcd7df764dbc107672c63456d64b711eb024d61f 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -67,6 +67,9 @@ if (YUZU_USE_EXTERNAL_SDL2)
     endif()
     set(SDL_STATIC ON)
     set(SDL_SHARED OFF)
+    if (APPLE)
+        set(SDL_FILE ON)
+    endif()
 
     add_subdirectory(SDL EXCLUDE_FROM_ALL)
     add_library(SDL2 ALIAS SDL2-static)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0ac3d254e5cd8871c5dacbebe574b44dc8a26451..4bd5aa50bb13322efdbe3f6eba0d3acc3251d155 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -112,6 +112,8 @@ else()
 
         $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
         $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
+        $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
+        $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
     )
 
     if (ARCHITECTURE_x86_64)
diff --git a/src/audio_core/audio_event.cpp b/src/audio_core/audio_event.cpp
index 424049c7a291e48a34ec16eb81b04027353e9af2..d15568e1f078529bc814b6b9b2b62b2eb654d511 100644
--- a/src/audio_core/audio_event.cpp
+++ b/src/audio_core/audio_event.cpp
@@ -3,6 +3,7 @@
 
 #include "audio_core/audio_event.h"
 #include "common/assert.h"
+#include "common/polyfill_ranges.h"
 
 namespace AudioCore {
 
diff --git a/src/audio_core/audio_manager.h b/src/audio_core/audio_manager.h
index abf077de4489e7de24dccb921edce56d13250e3a..02270242ace13e9520d9ece3e209bea76e868f78 100644
--- a/src/audio_core/audio_manager.h
+++ b/src/audio_core/audio_manager.h
@@ -9,6 +9,8 @@
 #include <mutex>
 #include <thread>
 
+#include "common/polyfill_thread.h"
+
 #include "audio_core/audio_event.h"
 
 union Result;
diff --git a/src/audio_core/audio_render_manager.h b/src/audio_core/audio_render_manager.h
index bf483719036207b5a55a2124afeb4cf7c99a7533..fffa5944d1878db1c4db2de6cc2e89e9b13bf71b 100644
--- a/src/audio_core/audio_render_manager.h
+++ b/src/audio_core/audio_render_manager.h
@@ -7,6 +7,8 @@
 #include <memory>
 #include <mutex>
 
+#include "common/polyfill_thread.h"
+
 #include "audio_core/common/common.h"
 #include "audio_core/renderer/system_manager.h"
 #include "core/hle/service/audio/errors.h"
diff --git a/src/audio_core/common/feature_support.h b/src/audio_core/common/feature_support.h
index 55c9e690df00ea8621da6ade17f5f57eb6c6b96e..e71905ae8410ac0f9ddfacc73783da6d38d316a9 100644
--- a/src/audio_core/common/feature_support.h
+++ b/src/audio_core/common/feature_support.h
@@ -10,6 +10,7 @@
 #include "common/assert.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 
 namespace AudioCore {
 constexpr u32 CurrentRevision = 11;
diff --git a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp
index c4bf3943a115b8786b50938093d57ea267a182b1..2187d8a6511c0fe19fb4173e8259068031647658 100644
--- a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp
+++ b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp
@@ -5,6 +5,7 @@
 
 #include "audio_core/renderer/adsp/command_list_processor.h"
 #include "audio_core/renderer/command/effect/i3dl2_reverb.h"
+#include "common/polyfill_ranges.h"
 
 namespace AudioCore::AudioRenderer {
 
diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp
index fe2b1eb43144d95adcf9652abfcff8cebfebade5..4274892140f4600efe3054926e3c79da2b5edeec 100644
--- a/src/audio_core/renderer/command/effect/reverb.cpp
+++ b/src/audio_core/renderer/command/effect/reverb.cpp
@@ -6,6 +6,7 @@
 
 #include "audio_core/renderer/adsp/command_list_processor.h"
 #include "audio_core/renderer/command/effect/reverb.h"
+#include "common/polyfill_ranges.h"
 
 namespace AudioCore::AudioRenderer {
 
diff --git a/src/audio_core/renderer/mix/mix_context.cpp b/src/audio_core/renderer/mix/mix_context.cpp
index 2427c83ed651c6cd36fa6859467fd4bf8a78c8ab..35b748ede8882149e93b7934041a22a5edfe30de 100644
--- a/src/audio_core/renderer/mix/mix_context.cpp
+++ b/src/audio_core/renderer/mix/mix_context.cpp
@@ -5,6 +5,7 @@
 
 #include "audio_core/renderer/mix/mix_context.h"
 #include "audio_core/renderer/splitter/splitter_context.h"
+#include "common/polyfill_ranges.h"
 
 namespace AudioCore::AudioRenderer {
 
diff --git a/src/audio_core/renderer/voice/voice_context.cpp b/src/audio_core/renderer/voice/voice_context.cpp
index a501a677d83791a13c139530cd593a69ba836feb..16a3e839d7164ec0fdd0785f60d8de94157999e3 100644
--- a/src/audio_core/renderer/voice/voice_context.cpp
+++ b/src/audio_core/renderer/voice/voice_context.cpp
@@ -4,6 +4,7 @@
 #include <ranges>
 
 #include "audio_core/renderer/voice/voice_context.h"
+#include "common/polyfill_ranges.h"
 
 namespace AudioCore::AudioRenderer {
 
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index 849f862b08d4f4f5ed4a97ca609829e7059b1eb5..e3d060f11164dad5abb57a86ec8b533e4f914dab 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -170,8 +170,8 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
 
         // Get the minimum frames available between the currently playing buffer, and the
         // amount we have left to fill
-        size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played,
-                                         num_frames - frames_written)};
+        size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
+                                              num_frames - frames_written)};
 
         samples_buffer.Push(&input_buffer[frames_written * frame_size],
                             frames_available * frame_size);
@@ -241,8 +241,8 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
 
         // Get the minimum frames available between the currently playing buffer, and the
         // amount we have left to fill
-        size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played,
-                                         num_frames - frames_written)};
+        size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
+                                              num_frames - frames_written)};
 
         samples_buffer.Pop(&output_buffer[frames_written * frame_size],
                            frames_available * frame_size);
diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp
index fa8422c4152cdb1f7f8774ba22ea7fb00d7d5eea..656b03cc55b509ab82b360e5ffa541eb77eb13ea 100644
--- a/src/common/fs/file.cpp
+++ b/src/common/fs/file.cpp
@@ -1,6 +1,8 @@
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <vector>
+
 #include "common/fs/file.h"
 #include "common/fs/fs.h"
 #include "common/logging/log.h"
diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp
index eb4ac1deb420f13c5a3aec95ceafcfd51e179c8c..813a713c3b5fede1ea0fa38da114617a1ad5aa35 100644
--- a/src/common/fs/fs_util.cpp
+++ b/src/common/fs/fs_util.cpp
@@ -4,6 +4,7 @@
 #include <algorithm>
 
 #include "common/fs/fs_util.h"
+#include "common/polyfill_ranges.h"
 
 namespace Common::FS {
 
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index 1074f242116e4f57be628faf9c15735a22fbbf0c..defa3e91812d895d18ce9a96fe6e9b9ad6f5dec6 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <algorithm>
+#include <sstream>
 #include <unordered_map>
 
 #include "common/fs/fs.h"
diff --git a/src/common/input.h b/src/common/input.h
index cb30b72547d16008f7db6469760b99e797989afa..9f7b897999c31777c98a2b072bc9ced2240f50eb 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <unordered_map>
 #include <utility>
+#include <vector>
 #include "common/logging/log.h"
 #include "common/param_package.h"
 #include "common/uuid.h"
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 15d92505e30f3a353bde5b029f051b8a5c2147a4..2a3bded40ef8a88293f91aa7a04fdf2ca18f28bd 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -4,7 +4,6 @@
 #include <atomic>
 #include <chrono>
 #include <climits>
-#include <stop_token>
 #include <thread>
 
 #include <fmt/format.h>
@@ -18,6 +17,7 @@
 #include "common/fs/fs_paths.h"
 #include "common/fs/path_util.h"
 #include "common/literals.h"
+#include "common/polyfill_thread.h"
 #include "common/thread.h"
 
 #include "common/logging/backend.h"
diff --git a/src/common/polyfill_ranges.h b/src/common/polyfill_ranges.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca44bfaef1fd88d02fa6b01d4e262b9df3ae84fe
--- /dev/null
+++ b/src/common/polyfill_ranges.h
@@ -0,0 +1,530 @@
+// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//
+// TODO: remove this file when ranges are supported by all compilation targets
+//
+
+#pragma once
+
+#include <algorithm>
+#include <utility>
+#include <version>
+
+#ifndef __cpp_lib_ranges
+
+namespace std {
+namespace ranges {
+
+template <typename T>
+concept range = requires(T& t) {
+    begin(t);
+    end(t);
+};
+
+template <typename T>
+concept input_range = range<T>;
+
+template <typename T>
+concept output_range = range<T>;
+
+template <range R>
+using range_difference_t = ptrdiff_t;
+
+//
+// find, find_if, find_if_not
+//
+
+struct find_fn {
+    template <typename Iterator, typename T, typename Proj = std::identity>
+    constexpr Iterator operator()(Iterator first, Iterator last, const T& value,
+                                  Proj proj = {}) const {
+        for (; first != last; ++first) {
+            if (std::invoke(proj, *first) == value) {
+                return first;
+            }
+        }
+        return first;
+    }
+
+    template <ranges::input_range R, typename T, typename Proj = std::identity>
+    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
+    }
+};
+
+struct find_if_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred>
+    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
+        for (; first != last; ++first) {
+            if (std::invoke(pred, std::invoke(proj, *first))) {
+                return first;
+            }
+        }
+        return first;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
+    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+struct find_if_not_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred>
+    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
+        for (; first != last; ++first) {
+            if (!std::invoke(pred, std::invoke(proj, *first))) {
+                return first;
+            }
+        }
+        return first;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
+    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+inline constexpr find_fn find;
+inline constexpr find_if_fn find_if;
+inline constexpr find_if_not_fn find_if_not;
+
+//
+// any_of, all_of, none_of
+//
+
+struct all_of_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred>
+    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
+        return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
+    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+struct any_of_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred>
+    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
+        return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
+    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+struct none_of_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred>
+    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
+        return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
+    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+inline constexpr any_of_fn any_of;
+inline constexpr all_of_fn all_of;
+inline constexpr none_of_fn none_of;
+
+//
+// count, count_if
+//
+
+struct count_fn {
+    template <typename Iterator, typename T, typename Proj = std::identity>
+    constexpr ptrdiff_t operator()(Iterator first, Iterator last, const T& value,
+                                   Proj proj = {}) const {
+        ptrdiff_t counter = 0;
+        for (; first != last; ++first)
+            if (std::invoke(proj, *first) == value)
+                ++counter;
+        return counter;
+    }
+
+    template <ranges::input_range R, typename T, typename Proj = std::identity>
+    constexpr ptrdiff_t operator()(R&& r, const T& value, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
+    }
+};
+
+struct count_if_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred>
+    constexpr ptrdiff_t operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
+        ptrdiff_t counter = 0;
+        for (; first != last; ++first)
+            if (std::invoke(pred, std::invoke(proj, *first)))
+                ++counter;
+        return counter;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
+    constexpr ptrdiff_t operator()(R&& r, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+inline constexpr count_fn count;
+inline constexpr count_if_fn count_if;
+
+//
+// transform
+//
+
+struct transform_fn {
+    template <typename InputIterator, typename OutputIterator, typename F,
+              typename Proj = std::identity>
+    constexpr void operator()(InputIterator first1, InputIterator last1, OutputIterator result,
+                              F op, Proj proj = {}) const {
+        for (; first1 != last1; ++first1, (void)++result) {
+            *result = std::invoke(op, std::invoke(proj, *first1));
+        }
+    }
+
+    template <ranges::input_range R, typename OutputIterator, typename F,
+              typename Proj = std::identity>
+    constexpr void operator()(R&& r, OutputIterator result, F op, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), result, std::ref(op), std::ref(proj));
+    }
+};
+
+inline constexpr transform_fn transform;
+
+//
+// sort
+//
+
+struct sort_fn {
+    template <typename Iterator, typename Comp = ranges::less, typename Proj = std::identity>
+    constexpr void operator()(Iterator first, Iterator last, Comp comp = {}, Proj proj = {}) const {
+        if (first == last)
+            return;
+
+        Iterator last_iter = ranges::next(first, last);
+        std::sort(first, last_iter,
+                  [&](auto& lhs, auto& rhs) { return comp(proj(lhs), proj(rhs)); });
+    }
+
+    template <ranges::input_range R, typename Comp = ranges::less, typename Proj = std::identity>
+    constexpr void operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
+    }
+};
+
+inline constexpr sort_fn sort;
+
+//
+// fill
+//
+
+struct fill_fn {
+    template <typename T, typename OutputIterator>
+    constexpr OutputIterator operator()(OutputIterator first, OutputIterator last,
+                                        const T& value) const {
+        while (first != last) {
+            *first++ = value;
+        }
+
+        return first;
+    }
+
+    template <typename T, ranges::output_range R>
+    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value) const {
+        return operator()(ranges::begin(r), ranges::end(r), value);
+    }
+};
+
+inline constexpr fill_fn fill;
+
+//
+// for_each
+//
+
+struct for_each_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Fun>
+    constexpr void operator()(Iterator first, Iterator last, Fun f, Proj proj = {}) const {
+        for (; first != last; ++first) {
+            std::invoke(f, std::invoke(proj, *first));
+        }
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Fun>
+    constexpr void operator()(R&& r, Fun f, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj));
+    }
+};
+
+inline constexpr for_each_fn for_each;
+
+//
+// min_element, max_element
+//
+
+struct min_element_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less>
+    constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {},
+                                  Proj proj = {}) const {
+        if (first == last) {
+            return last;
+        }
+
+        auto smallest = first;
+        ++first;
+        for (; first != last; ++first) {
+            if (!std::invoke(comp, std::invoke(proj, *smallest), std::invoke(proj, *first))) {
+                smallest = first;
+            }
+        }
+        return smallest;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less>
+    constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
+    }
+};
+
+struct max_element_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less>
+    constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {},
+                                  Proj proj = {}) const {
+        if (first == last) {
+            return last;
+        }
+
+        auto largest = first;
+        ++first;
+        for (; first != last; ++first) {
+            if (std::invoke(comp, std::invoke(proj, *largest), std::invoke(proj, *first))) {
+                largest = first;
+            }
+        }
+        return largest;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less>
+    constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
+    }
+};
+
+inline constexpr min_element_fn min_element;
+inline constexpr max_element_fn max_element;
+
+//
+// replace, replace_if
+//
+
+struct replace_fn {
+    template <typename Iterator, typename T1, typename T2, typename Proj = std::identity>
+    constexpr Iterator operator()(Iterator first, Iterator last, const T1& old_value,
+                                  const T2& new_value, Proj proj = {}) const {
+        for (; first != last; ++first) {
+            if (old_value == std::invoke(proj, *first)) {
+                *first = new_value;
+            }
+        }
+        return first;
+    }
+
+    template <ranges::input_range R, typename T1, typename T2, typename Proj = std::identity>
+    constexpr ranges::iterator_t<R> operator()(R&& r, const T1& old_value, const T2& new_value,
+                                               Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), old_value, new_value, std::move(proj));
+    }
+};
+
+struct replace_if_fn {
+    template <typename Iterator, typename T, typename Proj = std::identity, typename Pred>
+    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, const T& new_value,
+                                  Proj proj = {}) const {
+        for (; first != last; ++first) {
+            if (!!std::invoke(pred, std::invoke(proj, *first))) {
+                *first = new_value;
+            }
+        }
+        return std::move(first);
+    }
+
+    template <ranges::input_range R, typename T, typename Proj = std::identity, typename Pred>
+    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, const T& new_value,
+                                               Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::move(pred), new_value,
+                          std::move(proj));
+    }
+};
+
+inline constexpr replace_fn replace;
+inline constexpr replace_if_fn replace_if;
+
+//
+// copy, copy_if
+//
+
+struct copy_fn {
+    template <typename InputIterator, typename OutputIterator>
+    constexpr void operator()(InputIterator first, InputIterator last,
+                              OutputIterator result) const {
+        for (; first != last; ++first, (void)++result) {
+            *result = *first;
+        }
+    }
+
+    template <ranges::input_range R, typename OutputIterator>
+    constexpr void operator()(R&& r, OutputIterator result) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::move(result));
+    }
+};
+
+struct copy_if_fn {
+    template <typename InputIterator, typename OutputIterator, typename Proj = std::identity,
+              typename Pred>
+    constexpr void operator()(InputIterator first, InputIterator last, OutputIterator result,
+                              Pred pred, Proj proj = {}) const {
+        for (; first != last; ++first) {
+            if (std::invoke(pred, std::invoke(proj, *first))) {
+                *result = *first;
+                ++result;
+            }
+        }
+    }
+
+    template <ranges::input_range R, typename OutputIterator, typename Proj = std::identity,
+              typename Pred>
+    constexpr void operator()(R&& r, OutputIterator result, Pred pred, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::move(result), std::ref(pred),
+                          std::ref(proj));
+    }
+};
+
+inline constexpr copy_fn copy;
+inline constexpr copy_if_fn copy_if;
+
+//
+// generate
+//
+
+struct generate_fn {
+    template <typename Iterator, typename F>
+    constexpr Iterator operator()(Iterator first, Iterator last, F gen) const {
+        for (; first != last; *first = std::invoke(gen), ++first)
+            ;
+        return first;
+    }
+
+    template <typename R, std::copy_constructible F>
+    requires std::invocable<F&> && ranges::output_range<R>
+    constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
+    }
+};
+
+inline constexpr generate_fn generate;
+
+//
+// lower_bound, upper_bound
+//
+
+struct lower_bound_fn {
+    template <typename Iterator, typename T, typename Proj = std::identity,
+              typename Comp = ranges::less>
+    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {},
+                                  Proj proj = {}) const {
+        Iterator it;
+        std::ptrdiff_t _count, _step;
+        _count = std::distance(first, last);
+
+        while (_count > 0) {
+            it = first;
+            _step = _count / 2;
+            ranges::advance(it, _step, last);
+            if (comp(std::invoke(proj, *it), value)) {
+                first = ++it;
+                _count -= _step + 1;
+            } else {
+                _count = _step;
+            }
+        }
+        return first;
+    }
+
+    template <ranges::input_range R, typename T, typename Proj = std::identity,
+              typename Comp = ranges::less>
+    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {},
+                                               Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj));
+    }
+};
+
+struct upper_bound_fn {
+    template <typename Iterator, typename T, typename Proj = std::identity,
+              typename Comp = ranges::less>
+    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {},
+                                  Proj proj = {}) const {
+        Iterator it;
+        std::ptrdiff_t _count, _step;
+        _count = std::distance(first, last);
+
+        while (_count > 0) {
+            it = first;
+            _step = _count / 2;
+            ranges::advance(it, _step, last);
+            if (!comp(value, std::invoke(proj, *it))) {
+                first = ++it;
+                _count -= _step + 1;
+            } else {
+                _count = _step;
+            }
+        }
+        return first;
+    }
+
+    template <ranges::input_range R, typename T, typename Proj = std::identity,
+              typename Comp = ranges::less>
+    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {},
+                                               Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj));
+    }
+};
+
+inline constexpr lower_bound_fn lower_bound;
+inline constexpr upper_bound_fn upper_bound;
+
+//
+// adjacent_find
+//
+
+struct adjacent_find_fn {
+    template <typename Iterator, typename Proj = std::identity, typename Pred = ranges::equal_to>
+    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred = {},
+                                  Proj proj = {}) const {
+        if (first == last)
+            return first;
+        auto _next = ranges::next(first);
+        for (; _next != last; ++_next, ++first)
+            if (std::invoke(pred, std::invoke(proj, *first), std::invoke(proj, *_next)))
+                return first;
+        return _next;
+    }
+
+    template <ranges::input_range R, typename Proj = std::identity,
+              typename Pred = ranges::equal_to>
+    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const {
+        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
+    }
+};
+
+inline constexpr adjacent_find_fn adjacent_find;
+
+} // namespace ranges
+} // namespace std
+
+#endif
diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a8d1ce085b2a3429f3d1756702f133061d25d75
--- /dev/null
+++ b/src/common/polyfill_thread.h
@@ -0,0 +1,323 @@
+// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//
+// TODO: remove this file when jthread is supported by all compilation targets
+//
+
+#pragma once
+
+#include <version>
+
+#ifdef __cpp_lib_jthread
+
+#include <stop_token>
+#include <thread>
+
+namespace Common {
+
+template <typename Condvar, typename Lock, typename Pred>
+void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) {
+    cv.wait(lock, token, std::move(pred));
+}
+
+} // namespace Common
+
+#else
+
+#include <atomic>
+#include <functional>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <thread>
+#include <type_traits>
+
+namespace std {
+namespace polyfill {
+
+using stop_state_callbacks = list<function<void()>>;
+
+class stop_state {
+public:
+    stop_state() = default;
+    ~stop_state() = default;
+
+    bool request_stop() {
+        stop_state_callbacks callbacks;
+
+        {
+            scoped_lock lk{m_lock};
+
+            if (m_stop_requested.load()) {
+                // Already set, nothing to do
+                return false;
+            }
+
+            // Set as requested
+            m_stop_requested = true;
+
+            // Copy callback list
+            callbacks = m_callbacks;
+        }
+
+        for (auto callback : callbacks) {
+            callback();
+        }
+
+        return true;
+    }
+
+    bool stop_requested() const {
+        return m_stop_requested.load();
+    }
+
+    stop_state_callbacks::const_iterator insert_callback(function<void()> f) {
+        stop_state_callbacks::const_iterator ret{};
+        bool should_run{};
+
+        {
+            scoped_lock lk{m_lock};
+            should_run = m_stop_requested.load();
+            m_callbacks.push_front(f);
+            ret = m_callbacks.begin();
+        }
+
+        if (should_run) {
+            f();
+        }
+
+        return ret;
+    }
+
+    void remove_callback(stop_state_callbacks::const_iterator it) {
+        scoped_lock lk{m_lock};
+        m_callbacks.erase(it);
+    }
+
+private:
+    mutex m_lock;
+    atomic<bool> m_stop_requested;
+    stop_state_callbacks m_callbacks;
+};
+
+} // namespace polyfill
+
+class stop_token;
+class stop_source;
+struct nostopstate_t {
+    explicit nostopstate_t() = default;
+};
+inline constexpr nostopstate_t nostopstate{};
+
+template <class Callback>
+class stop_callback;
+
+class stop_token {
+public:
+    stop_token() noexcept = default;
+
+    stop_token(const stop_token&) noexcept = default;
+    stop_token(stop_token&&) noexcept = default;
+    stop_token& operator=(const stop_token&) noexcept = default;
+    stop_token& operator=(stop_token&&) noexcept = default;
+    ~stop_token() = default;
+
+    void swap(stop_token& other) noexcept {
+        m_stop_state.swap(other.m_stop_state);
+    }
+
+    [[nodiscard]] bool stop_requested() const noexcept {
+        return m_stop_state && m_stop_state->stop_requested();
+    }
+    [[nodiscard]] bool stop_possible() const noexcept {
+        return m_stop_state != nullptr;
+    }
+
+private:
+    friend class stop_source;
+    template <typename Callback>
+    friend class stop_callback;
+    stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {}
+
+private:
+    shared_ptr<polyfill::stop_state> m_stop_state;
+};
+
+class stop_source {
+public:
+    stop_source() : m_stop_state(make_shared<polyfill::stop_state>()) {}
+    explicit stop_source(nostopstate_t) noexcept {}
+
+    stop_source(const stop_source&) noexcept = default;
+    stop_source(stop_source&&) noexcept = default;
+    stop_source& operator=(const stop_source&) noexcept = default;
+    stop_source& operator=(stop_source&&) noexcept = default;
+    ~stop_source() = default;
+    void swap(stop_source& other) noexcept {
+        m_stop_state.swap(other.m_stop_state);
+    }
+
+    [[nodiscard]] stop_token get_token() const noexcept {
+        return stop_token(m_stop_state);
+    }
+    [[nodiscard]] bool stop_possible() const noexcept {
+        return m_stop_state != nullptr;
+    }
+    [[nodiscard]] bool stop_requested() const noexcept {
+        return m_stop_state && m_stop_state->stop_requested();
+    }
+    bool request_stop() noexcept {
+        return m_stop_state && m_stop_state->request_stop();
+    }
+
+private:
+    friend class jthread;
+    explicit stop_source(shared_ptr<polyfill::stop_state> stop_state)
+        : m_stop_state(move(stop_state)) {}
+
+private:
+    shared_ptr<polyfill::stop_state> m_stop_state;
+};
+
+template <typename Callback>
+class stop_callback {
+    static_assert(is_nothrow_destructible_v<Callback>);
+    static_assert(is_invocable_v<Callback>);
+
+public:
+    using callback_type = Callback;
+
+    template <typename C>
+    requires constructible_from<Callback, C>
+    explicit stop_callback(const stop_token& st,
+                           C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
+        : m_stop_state(st.m_stop_state) {
+        if (m_stop_state) {
+            m_callback = m_stop_state->insert_callback(move(cb));
+        }
+    }
+    template <typename C>
+    requires constructible_from<Callback, C>
+    explicit stop_callback(stop_token&& st,
+                           C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
+        : m_stop_state(move(st.m_stop_state)) {
+        if (m_stop_state) {
+            m_callback = m_stop_state->insert_callback(move(cb));
+        }
+    }
+    ~stop_callback() {
+        if (m_stop_state && m_callback) {
+            m_stop_state->remove_callback(*m_callback);
+        }
+    }
+
+    stop_callback(const stop_callback&) = delete;
+    stop_callback(stop_callback&&) = delete;
+    stop_callback& operator=(const stop_callback&) = delete;
+    stop_callback& operator=(stop_callback&&) = delete;
+
+private:
+    shared_ptr<polyfill::stop_state> m_stop_state;
+    optional<polyfill::stop_state_callbacks::const_iterator> m_callback;
+};
+
+template <typename Callback>
+stop_callback(stop_token, Callback) -> stop_callback<Callback>;
+
+class jthread {
+public:
+    using id = thread::id;
+    using native_handle_type = thread::native_handle_type;
+
+    jthread() noexcept = default;
+
+    template <typename F, typename... Args,
+              typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>>
+    explicit jthread(F&& f, Args&&... args)
+        : m_stop_state(make_shared<polyfill::stop_state>()),
+          m_thread(make_thread(move(f), move(args)...)) {}
+
+    ~jthread() {
+        if (joinable()) {
+            request_stop();
+            join();
+        }
+    }
+
+    jthread(const jthread&) = delete;
+    jthread(jthread&&) noexcept = default;
+    jthread& operator=(const jthread&) = delete;
+
+    jthread& operator=(jthread&& other) noexcept {
+        m_thread.swap(other.m_thread);
+        m_stop_state.swap(other.m_stop_state);
+        return *this;
+    }
+
+    void swap(jthread& other) noexcept {
+        m_thread.swap(other.m_thread);
+        m_stop_state.swap(other.m_stop_state);
+    }
+    [[nodiscard]] bool joinable() const noexcept {
+        return m_thread.joinable();
+    }
+    void join() {
+        m_thread.join();
+    }
+    void detach() {
+        m_thread.detach();
+        m_stop_state.reset();
+    }
+
+    [[nodiscard]] id get_id() const noexcept {
+        return m_thread.get_id();
+    }
+    [[nodiscard]] native_handle_type native_handle() {
+        return m_thread.native_handle();
+    }
+    [[nodiscard]] stop_source get_stop_source() noexcept {
+        return stop_source(m_stop_state);
+    }
+    [[nodiscard]] stop_token get_stop_token() const noexcept {
+        return stop_source(m_stop_state).get_token();
+    }
+    bool request_stop() noexcept {
+        return get_stop_source().request_stop();
+    }
+    [[nodiscard]] static unsigned int hardware_concurrency() noexcept {
+        return thread::hardware_concurrency();
+    }
+
+private:
+    template <typename F, typename... Args>
+    thread make_thread(F&& f, Args&&... args) {
+        if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) {
+            return thread(move(f), get_stop_token(), move(args)...);
+        } else {
+            return thread(move(f), move(args)...);
+        }
+    }
+
+    shared_ptr<polyfill::stop_state> m_stop_state;
+    thread m_thread;
+};
+
+} // namespace std
+
+namespace Common {
+
+template <typename Condvar, typename Lock, typename Pred>
+void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) {
+    if (token.stop_requested()) {
+        return;
+    }
+
+    std::stop_callback callback(token, [&] { cv.notify_all(); });
+    cv.wait(lock, [&] { return pred() || token.stop_requested(); });
+}
+
+} // namespace Common
+
+#endif
diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h
index 62c60f7242912b137dd67c30295119d5533b2239..260ad44e453b811a8dc82858a7c67d58ec279359 100644
--- a/src/common/thread_worker.h
+++ b/src/common/thread_worker.h
@@ -7,13 +7,13 @@
 #include <condition_variable>
 #include <functional>
 #include <mutex>
-#include <stop_token>
 #include <string>
 #include <thread>
 #include <type_traits>
 #include <vector>
 #include <queue>
 
+#include "common/polyfill_thread.h"
 #include "common/thread.h"
 #include "common/unique_function.h"
 
@@ -47,7 +47,8 @@ public:
                         if (requests.empty()) {
                             wait_condition.notify_all();
                         }
-                        condition.wait(lock, stop_token, [this] { return !requests.empty(); });
+                        Common::CondvarWait(condition, lock, stop_token,
+                                            [this] { return !requests.empty(); });
                         if (stop_token.stop_requested()) {
                             break;
                         }
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index 053798e79baecbe479a0fbe44e35d68b697fe8df..2ef1da06449c2489665a84aea804f06357772175 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -12,6 +12,8 @@
 #include <mutex>
 #include <utility>
 
+#include "common/polyfill_thread.h"
+
 namespace Common {
 template <typename T, bool with_stop_token = false>
 class SPSCQueue {
@@ -97,7 +99,7 @@ public:
     T PopWait(std::stop_token stop_token) {
         if (Empty()) {
             std::unique_lock lock{cv_mutex};
-            cv.wait(lock, stop_token, [this] { return !Empty(); });
+            Common::CondvarWait(cv, lock, stop_token, [this] { return !Empty(); });
         }
         if (stop_token.stop_requested()) {
             return T{};
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index 95ea3ef390748cb72f004e21edb4521fcf018dcf..3743674683ff5aac7beabd99a63d7b3d9e305635 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -10,6 +10,7 @@
 #include <thread>
 
 #include "common/fiber.h"
+#include "common/polyfill_thread.h"
 #include "common/thread.h"
 #include "core/hardware_properties.h"
 
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp
index 1a8e02e6a4dd1ac109142b92b948de3229d4c89a..a9675df76d3ef6e7a69e8d732cbbc8645cac48b9 100644
--- a/src/core/debugger/debugger.cpp
+++ b/src/core/debugger/debugger.cpp
@@ -9,6 +9,7 @@
 #include <boost/process/async_pipe.hpp>
 
 #include "common/logging/log.h"
+#include "common/polyfill_thread.h"
 #include "common/thread.h"
 #include "core/core.h"
 #include "core/debugger/debugger.h"
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 78e56bbbd2fdef67b752763ce8d0ea1998406eb6..50303fe42c721824286404bb7981f16eea81f3f8 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "core/crypto/aes_util.h"
 #include "core/crypto/ctr_encryption_layer.h"
 #include "core/crypto/key_manager.h"
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
index 1d2850ad5c254d455734a877c3b10e2d09a8f24d..71698df742287721ac7b3aaf8f70ffaf2828e3f4 100644
--- a/src/core/frontend/applets/controller.h
+++ b/src/core/frontend/applets/controller.h
@@ -4,6 +4,7 @@
 #pragma once
 
 #include <functional>
+#include <vector>
 
 #include "common/common_types.h"
 
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index d004ca56ad5aad017f906e548b8436c18f8952b9..3f83108d38f118a4a8fc4b908335ea2587d7a4be 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <mutex>
 #include <unordered_map>
+#include <vector>
 
 #include "common/common_types.h"
 #include "common/input.h"
diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h
index 4149eecedd72818e12c86969701cd90637086ecc..4cdbf9dc641ccd95c04926ccc7568b8e540c52ca 100644
--- a/src/core/hid/emulated_devices.h
+++ b/src/core/hid/emulated_devices.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <mutex>
 #include <unordered_map>
+#include <vector>
 
 #include "common/common_types.h"
 #include "common/input.h"
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index c4bf306e8f289e1fc2d16c6358da7e081c78b1a1..bd33571daac79513aa71d6a1f1930f8fd875e4c0 100644
--- a/src/core/hle/kernel/k_memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -225,8 +225,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
     ON_RESULT_FAILURE {
         for (const auto& it : out->Nodes()) {
             auto& manager = this->GetManager(it.GetAddress());
-            const size_t node_num_pages =
-                std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
+            const size_t node_num_pages = std::min<u64>(
+                it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
             manager.Free(it.GetAddress(), node_num_pages);
         }
         out->Finalize();
diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h
index a8c77a7d480c776c55abb93212c3ccc553ab4e3d..68469b04150530a0571b21c5acd8b546624cbcc5 100644
--- a/src/core/hle/kernel/k_slab_heap.h
+++ b/src/core/hle/kernel/k_slab_heap.h
@@ -6,6 +6,7 @@
 #include <atomic>
 
 #include "common/assert.h"
+#include "common/atomic_ops.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/spin_lock.h"
@@ -82,16 +83,13 @@ private:
 
 private:
     void UpdatePeakImpl(uintptr_t obj) {
-        static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free);
-        std::atomic_ref<uintptr_t> peak_ref(m_peak);
-
         const uintptr_t alloc_peak = obj + this->GetObjectSize();
         uintptr_t cur_peak = m_peak;
         do {
             if (alloc_peak <= cur_peak) {
                 break;
             }
-        } while (!peak_ref.compare_exchange_strong(cur_peak, alloc_peak));
+        } while (!Common::AtomicCompareAndSwap(&m_peak, alloc_peak, cur_peak, cur_peak));
     }
 
 public:
diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h
index 5d466ace7ab209ac059ffbf94c0d594cbfb32e61..fe0cff084bc32442f5d8be1ea95771e08e1583fd 100644
--- a/src/core/hle/kernel/k_thread_local_page.h
+++ b/src/core/hle/kernel/k_thread_local_page.h
@@ -10,6 +10,7 @@
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/intrusive_red_black_tree.h"
+#include "common/polyfill_ranges.h"
 #include "core/hle/kernel/memory_types.h"
 #include "core/hle/kernel/slab_helpers.h"
 #include "core/hle/result.h"
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index e6e41ac34814d66646cd41e21293eed0d74e1327..0690f9a1c440e095c7d87b9027dcdf7b796ec237 100644
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -7,6 +7,7 @@
 #include <thread>
 #include <vector>
 
+#include "common/polyfill_thread.h"
 #include "common/scope_exit.h"
 #include "common/thread.h"
 #include "core/hle/ipc_helpers.h"
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 3730937fe34d832c62c2708ceb4e57c60846bb95..1ea8c7fbcff831bfbfb641f580cd8b5e97a618e1 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -82,7 +82,7 @@ void SvcWrap64(Core::System& system) {
 }
 
 // Used by ControlCodeMemory
-template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
+template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)>
 void SvcWrap64(Core::System& system) {
     FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
                             static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
@@ -327,7 +327,7 @@ void SvcWrap64(Core::System& system) {
 }
 
 // Used by CreateCodeMemory
-template <Result func(Core::System&, Handle*, u64, u64)>
+template <Result func(Core::System&, Handle*, VAddr, size_t)>
 void SvcWrap64(Core::System& system) {
     u32 param_1 = 0;
     const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2)).raw;
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 85a3f08023312c5163fa4afc7672eb3eda2d5f9e..6d1084fd13490fb677c81a937b0cd4fa36f0f4b2 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -7,6 +7,7 @@
 #include "common/fs/file.h"
 #include "common/fs/path_util.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "common/string_util.h"
 #include "common/swap.h"
 #include "core/constants.h"
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 481e0d1410870a3b1e47966efd8be1c89a03a845..97f7c6688759fa0b4d124fa4a9b0fb0a4f512795 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -9,6 +9,7 @@
 #include "common/fs/file.h"
 #include "common/fs/fs.h"
 #include "common/fs/path_util.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "core/hle/service/acc/profile_manager.h"
 
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 8ea7fd760826da5339e73d95f792b13cf4f4606a..22999c942f9af699ac69177390e9d833ce61130a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1125,7 +1125,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
 
     const u64 offset{rp.Pop<u64>()};
     const std::vector<u8> data{ctx.ReadBuffer()};
-    const std::size_t size{std::min(data.size(), backing.GetSize() - offset)};
+    const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
 
     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
 
@@ -1149,7 +1149,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
 
     const u64 offset{rp.Pop<u64>()};
-    const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
+    const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
 
     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
 
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 13423dca67d5d208cf7ea28da45cfae639e1d0e5..77431e74316f9ae2c0358b9e0132bd711e5e5d86 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -14,6 +14,7 @@
 #include "common/bit_util.h"
 #include "common/common_funcs.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "common/string_util.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 460bef976d9342df81b341fb49937d330c033616..9b22397db7c768e51f1f3008e46f8e5009b2f3d8 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "common/common_types.h"
+#include "common/polyfill_thread.h"
 #include "core/hle/result.h"
 #include "core/hle/service/kernel_helpers.h"
 
diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp
index 057fd3661748531be5e15ab6de313bb72112815d..7b8e510a20e79a6b8910692d93a2d44da99a2ebd 100644
--- a/src/core/internal_network/network_interface.cpp
+++ b/src/core/internal_network/network_interface.cpp
@@ -9,6 +9,7 @@
 #include "common/bit_cast.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "common/string_util.h"
 #include "core/internal_network/network_interface.h"
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h
index 7f81767f7764ae3b0c86ee3683ce37289b9a987a..b5270fd0bb433ac5b6899076112595179c5df6b9 100644
--- a/src/input_common/drivers/gc_adapter.h
+++ b/src/input_common/drivers/gc_adapter.h
@@ -5,10 +5,10 @@
 
 #include <array>
 #include <memory>
-#include <stop_token>
 #include <string>
 #include <thread>
 
+#include "common/polyfill_thread.h"
 #include "input_common/input_engine.h"
 
 struct libusb_context;
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp
index 98c3157a897ae5cbdecbd593b8c5ed65c1e29e45..faf9cbdc3347d148b88fc5119bfcca29997d0370 100644
--- a/src/input_common/drivers/mouse.cpp
+++ b/src/input_common/drivers/mouse.cpp
@@ -1,7 +1,6 @@
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
-#include <stop_token>
 #include <thread>
 #include <fmt/format.h>
 
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h
index 286ce1cf6c3093084e2257ab4baf75676f55f777..72073cc2324f1d143a488016c844bf055e6d1976 100644
--- a/src/input_common/drivers/mouse.h
+++ b/src/input_common/drivers/mouse.h
@@ -3,9 +3,9 @@
 
 #pragma once
 
-#include <stop_token>
 #include <thread>
 
+#include "common/polyfill_thread.h"
 #include "common/vector_math.h"
 #include "input_common/input_engine.h"
 
diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp
index 21c6ed4055642675b3983eb035416c6a886e0388..f3ade90da70124fe4e3de52a4dc52b4ae4d23fa8 100644
--- a/src/input_common/drivers/tas_input.cpp
+++ b/src/input_common/drivers/tas_input.cpp
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <cstring>
+#include <sstream>
 #include <fmt/format.h>
 
 #include "common/fs/file.h"
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt
index 545d69c7e5b62c9c552f5709fd275fb2cc9eef4d..c173b20021ab951897aab1f52f9c38c95aad5121 100644
--- a/src/shader_recompiler/CMakeLists.txt
+++ b/src/shader_recompiler/CMakeLists.txt
@@ -254,6 +254,7 @@ else()
         # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
         # And this in turns limits the size of a std::array.
         $<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024>
+        $<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024>
     )
 endif()
 
diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h
index e70d7745cdecce9c4cc37dd2e288162921474bb1..d155afd0f3ea79fa5c1182e1579bb763ab875701 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.h
+++ b/src/shader_recompiler/frontend/ir/opcodes.h
@@ -8,6 +8,7 @@
 
 #include <fmt/format.h>
 
+#include "common/polyfill_ranges.h"
 #include "shader_recompiler/frontend/ir/type.h"
 
 namespace Shader::IR {
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
index 6939692cddf80a88fc717c266642ca72a6188c74..dce414cb47861f33ee111bd7330bda7b945c49e5 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
@@ -9,6 +9,7 @@
 
 #include <fmt/format.h>
 
+#include "common/polyfill_ranges.h"
 #include "shader_recompiler/exception.h"
 #include "shader_recompiler/frontend/maxwell/control_flow.h"
 #include "shader_recompiler/frontend/maxwell/decode.h"
diff --git a/src/shader_recompiler/frontend/maxwell/decode.cpp b/src/shader_recompiler/frontend/maxwell/decode.cpp
index 455c91470d87faba485d34795af9a047b3248c90..774f65bc59df7ae8d475c1293da97a51a639809f 100644
--- a/src/shader_recompiler/frontend/maxwell/decode.cpp
+++ b/src/shader_recompiler/frontend/maxwell/decode.cpp
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 #include "shader_recompiler/exception.h"
 #include "shader_recompiler/frontend/maxwell/decode.h"
 #include "shader_recompiler/frontend/maxwell/opcodes.h"
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index ce42475d469d73f58c23713a5af9f3a4a71a4afe..80c90fe6ac1a470395c34734dafc3717cd1985b4 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -12,6 +12,7 @@
 
 #include <boost/intrusive/list.hpp>
 
+#include "common/polyfill_ranges.h"
 #include "shader_recompiler/environment.h"
 #include "shader_recompiler/frontend/ir/basic_block.h"
 #include "shader_recompiler/frontend/ir/ir_emitter.h"
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
index 4942878b94ebf00a9d1cb5142f35659a9db753f5..85c18d9422054d6c76d326c279c83b37ead6aacb 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
@@ -176,12 +176,13 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
         (f2i.src_format == SrcFormat::F64) != (f2i.dest_format == DestFormat::I64);
     if (special_nan_cases) {
         if (f2i.dest_format == DestFormat::I32) {
+            constexpr u32 nan_value = 0x8000'0000U;
             handled_special_case = true;
-            result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)};
+            result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(nan_value), result)};
         } else if (f2i.dest_format == DestFormat::I64) {
+            constexpr u64 nan_value = 0x8000'0000'0000'0000ULL;
             handled_special_case = true;
-            result = IR::U64{
-                v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(0x8000'0000'0000'0000UL), result)};
+            result = IR::U64{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(nan_value), result)};
         }
     }
     if (!handled_special_case && is_signed) {
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index f9a6472cfd0b8d5a7e59a13ea45e321bf8fa1d34..92d77eef2d2363a9ec720f9d78c7a5b51644fede 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -535,7 +535,7 @@ private:
         const u64* const state_words = Array<type>();
         const u64 num_query_words = size / BYTES_PER_WORD + 1;
         const u64 word_begin = offset / BYTES_PER_WORD;
-        const u64 word_end = std::min(word_begin + num_query_words, NumWords());
+        const u64 word_end = std::min<u64>(word_begin + num_query_words, NumWords());
         const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
         u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD;
         for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) {
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 59955101374748bf5a677a3abf6ab91991ff645d..b970f06dc100ff580f48bf7e76e2b302e3fb76a9 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -19,6 +19,7 @@
 #include "common/literals.h"
 #include "common/lru_cache.h"
 #include "common/microprofile.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "core/memory.h"
 #include "video_core/buffer_cache/buffer_base.h"
diff --git a/src/video_core/control/channel_state_cache.h b/src/video_core/control/channel_state_cache.h
index 584a0c26cd5b42aaeca8bc7fb0d299cb5d427880..cdaf4f8d59001d313b08c38e8d237c0926752059 100644
--- a/src/video_core/control/channel_state_cache.h
+++ b/src/video_core/control/channel_state_cache.h
@@ -35,8 +35,6 @@ public:
     explicit ChannelInfo(Tegra::Control::ChannelState& state);
     ChannelInfo(const ChannelInfo& state) = delete;
     ChannelInfo& operator=(const ChannelInfo&) = delete;
-    ChannelInfo(ChannelInfo&& other) = default;
-    ChannelInfo& operator=(ChannelInfo&& other) = default;
 
     Tegra::Engines::Maxwell3D& maxwell3d;
     Tegra::Engines::KeplerCompute& kepler_compute;
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 1bd477011e31133c4e20b25dacaaf75a7dba9cd7..164a5252ac48493c66db47f5dc1278662aeda263 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -125,7 +125,7 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
     state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
 
     if (block) {
-        state.cv.wait(lk, thread.get_stop_token(), [this, fence] {
+        Common::CondvarWait(state.cv, lk, thread.get_stop_token(), [this, fence] {
             return fence <= state.signaled_fence.load(std::memory_order_relaxed);
         });
     }
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 64628d3e38b164c22985f95f7d79fab1b7fc0f37..c71a419c75182c155fa76d450ee324c2bbc814ea 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -10,6 +10,7 @@
 #include <thread>
 #include <variant>
 
+#include "common/polyfill_thread.h"
 #include "common/threadsafe_queue.h"
 #include "video_core/framebuffer_config.h"
 
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index cfd872a40eced956daa72e07afab25545d45b247..b6907463c54b348bea62d51bfc6dfb285f9ba67e 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -6,8 +6,8 @@
 #include <functional>
 #include <optional>
 #include <span>
-#include <stop_token>
 #include "common/common_types.h"
+#include "common/polyfill_thread.h"
 #include "video_core/engines/fermi_2d.h"
 #include "video_core/gpu.h"
 
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 1663e277d34126ba028333779a8858653eddf0ac..e2e3dac345c159b112246d8095d709c9b39b2478 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -14,6 +14,7 @@
 
 #include "common/literals.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "shader_recompiler/stage.h"
 #include "video_core/renderer_opengl/gl_device.h"
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 89f181fe300b949ce91366879ac760a209f28a5c..53ffea904df5d7f156827479a8230cda4581e86f 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -4,7 +4,6 @@
 #pragma once
 
 #include <filesystem>
-#include <stop_token>
 #include <unordered_map>
 
 #include "common/common_types.h"
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 98cc26679c94dd2635d4bf9ad20ecafc044a5cc5..f3f08b42c341e53c5ccffa7c138360822b276331 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -7,6 +7,7 @@
 #include "common/bit_cast.h"
 #include "common/cityhash.h"
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 #include "video_core/renderer_vulkan/fixed_pipeline_state.h"
 #include "video_core/renderer_vulkan/vk_state_tracker.h"
 
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 89426121fdc1584f23c4f4261481a5166a8a86c1..6e5abade45530a7d7f1c07d1e65352f6f6cd0cca 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -10,6 +10,7 @@
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/math_util.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "core/core.h"
 #include "core/frontend/emu_window.h"
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index c7196b64e304706c9bcd65b1638c6185198c8147..b5ae6443ca6e33cfae67160ae787827600f66d0a 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 #include "video_core/renderer_vulkan/vk_descriptor_pool.h"
 #include "video_core/renderer_vulkan/vk_resource_pool.h"
 #include "video_core/renderer_vulkan/vk_scheduler.h"
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 362ed579a5164b69ac5f13533cc726aa74359a13..689f02ea5facbde9625c2ae60e12f784c6f11115 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -7,6 +7,7 @@
 #include <thread>
 
 #include "common/common_types.h"
+#include "common/polyfill_thread.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
 
 namespace Vulkan {
diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.h b/src/video_core/renderer_vulkan/vk_render_pass_cache.h
index dc21b7e69815ae42e2fb22d7708a435d97ec557f..91ad4bf577692695b8a9084946ba529ffa97f89c 100644
--- a/src/video_core/renderer_vulkan/vk_render_pass_cache.h
+++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.h
@@ -12,7 +12,7 @@
 namespace Vulkan {
 
 struct RenderPassKey {
-    auto operator<=>(const RenderPassKey&) const noexcept = default;
+    bool operator==(const RenderPassKey&) const noexcept = default;
 
     std::array<VideoCore::Surface::PixelFormat, 8> color_formats;
     VideoCore::Surface::PixelFormat depth_format;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 4a7b633b7d58b10638d680e0d51cc88c1342a3f5..c09fb3e98e2cc593decb7005766d2ce2e3fa8f39 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -145,7 +145,7 @@ void Scheduler::WorkerThread(std::stop_token stop_token) {
             if (work_queue.empty()) {
                 wait_cv.notify_all();
             }
-            work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); });
+            Common::CondvarWait(work_cv, lock, stop_token, [&] { return !work_queue.empty(); });
             if (stop_token.stop_requested()) {
                 continue;
             }
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 929216749790b9aa0ec103f7b2956e671fe57d09..3858c506c4449061ff32ea073a665a584ac26f22 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -12,6 +12,7 @@
 
 #include "common/alignment.h"
 #include "common/common_types.h"
+#include "common/polyfill_thread.h"
 #include "video_core/renderer_vulkan/vk_master_semaphore.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
 
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 706d9ba746d7b5794b33c7611706bf2d22af9a50..d7be417f5cf22e7aa3b2f1e18bbfb9624828689d 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "core/core.h"
 #include "video_core/renderer_vulkan/vk_scheduler.h"
diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h
index a4391202dea92d7d3e11947d0897aae87fd55a62..f3cc4c70b5d4a9a45fe389626799755e868ceb02 100644
--- a/src/video_core/shader_cache.h
+++ b/src/video_core/shader_cache.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 #include "video_core/control/channel_state_cache.h"
 #include "video_core/rasterizer_interface.h"
 #include "video_core/shader_environment.h"
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index f24f320b62bb5e2e9118d89e57938c23eae039ae..95881074735b2152e66e5b6875f9f6938825ba68 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -15,6 +15,7 @@
 #include "common/fs/fs.h"
 #include "common/fs/path_util.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "shader_recompiler/environment.h"
 #include "video_core/engines/kepler_compute.h"
 #include "video_core/memory_manager.h"
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h
index bb55b029fe040ef7343719691e6a862042aa5ca5..1342fab1e99ca00fb016799d17bf46908dc65f74 100644
--- a/src/video_core/shader_environment.h
+++ b/src/video_core/shader_environment.h
@@ -10,12 +10,12 @@
 #include <memory>
 #include <optional>
 #include <span>
-#include <stop_token>
 #include <type_traits>
 #include <unordered_map>
 #include <vector>
 
 #include "common/common_types.h"
+#include "common/polyfill_thread.h"
 #include "common/unique_function.h"
 #include "shader_recompiler/environment.h"
 #include "video_core/engines/maxwell_3d.h"
diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp
index ee4f2d4066648f25b75f80beab540fd874f4f865..41889012686d66973a179f78537e9f8b46164633 100644
--- a/src/video_core/texture_cache/formatter.cpp
+++ b/src/video_core/texture_cache/formatter.cpp
@@ -4,6 +4,7 @@
 #include <algorithm>
 #include <string>
 
+#include "common/polyfill_ranges.h"
 #include "video_core/texture_cache/formatter.h"
 #include "video_core/texture_cache/image_base.h"
 #include "video_core/texture_cache/image_info.h"
diff --git a/src/video_core/texture_cache/render_targets.h b/src/video_core/texture_cache/render_targets.h
index 1efbd65079048cc1c8fc284ae336c3e6fca098b0..0829d773a5f7b0d90547494f28138912e82bbf24 100644
--- a/src/video_core/texture_cache/render_targets.h
+++ b/src/video_core/texture_cache/render_targets.h
@@ -13,7 +13,7 @@ namespace VideoCommon {
 
 /// Framebuffer properties used to lookup a framebuffer
 struct RenderTargets {
-    constexpr auto operator<=>(const RenderTargets&) const noexcept = default;
+    constexpr bool operator==(const RenderTargets&) const noexcept = default;
 
     constexpr bool Contains(std::span<const ImageViewId> elements) const noexcept {
         const auto contains = [elements](ImageViewId item) {
diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h
index 46e8a86e6474f2bbc8c77a5dd123a56b62caadbc..1e2aad76a84709af3178163991e6481a7bfee075 100644
--- a/src/video_core/texture_cache/slot_vector.h
+++ b/src/video_core/texture_cache/slot_vector.h
@@ -12,6 +12,7 @@
 
 #include "common/assert.h"
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 
 namespace VideoCommon {
 
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 2fa8445eb47da12824c08207735af44bc49a524b..7bdb5fd50218974f8fa1cd0ddcaa5379a074f605 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -16,6 +16,7 @@
 #include "common/hash.h"
 #include "common/literals.h"
 #include "common/lru_cache.h"
+#include "common/polyfill_ranges.h"
 #include "video_core/compatible_formats.h"
 #include "video_core/control/channel_state_cache.h"
 #include "video_core/delayed_destruction_ring.h"
@@ -60,8 +61,6 @@ public:
     TextureCacheChannelInfo(Tegra::Control::ChannelState& state) noexcept;
     TextureCacheChannelInfo(const TextureCacheChannelInfo& state) = delete;
     TextureCacheChannelInfo& operator=(const TextureCacheChannelInfo&) = delete;
-    TextureCacheChannelInfo(TextureCacheChannelInfo&& other) noexcept = default;
-    TextureCacheChannelInfo& operator=(TextureCacheChannelInfo&& other) noexcept = default;
 
     DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
     DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index 69a32819a553c078afdc2d150eeab98fa3fc1077..e8d7c78637a2fa2a54a358e61e444cf6ac9f0b61 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -15,6 +15,7 @@
 
 #include "common/alignment.h"
 #include "common/common_types.h"
+#include "common/polyfill_ranges.h"
 #include "common/thread_worker.h"
 #include "video_core/textures/astc.h"
 
diff --git a/src/video_core/transform_feedback.cpp b/src/video_core/transform_feedback.cpp
index 45071185adbd7618ed9886677773bc4a1326e1b9..155599316b9686ecbc6c5f05a1828e1c81591497 100644
--- a/src/video_core/transform_feedback.cpp
+++ b/src/video_core/transform_feedback.cpp
@@ -7,6 +7,7 @@
 
 #include "common/alignment.h"
 #include "common/assert.h"
+#include "common/polyfill_ranges.h"
 #include "shader_recompiler/shader_info.h"
 #include "video_core/transform_feedback.h"
 
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index ddecfca132f6e2a9fc50e0e6d3b2d5b4e23d3539..afc7216ed571cff856dfb97dca2fffa21f4e7b2f 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -12,6 +12,7 @@
 
 #include "common/assert.h"
 #include "common/literals.h"
+#include "common/polyfill_ranges.h"
 #include "common/settings.h"
 #include "video_core/vulkan_common/nsight_aftermath_tracker.h"
 #include "video_core/vulkan_common/vulkan_device.h"
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index a082e30593f7890f47e96e9de09c30ce7c5e0487..170b8e7cb8067276dab9608fff0c6b6b5f4dadd0 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -9,6 +9,7 @@
 #include "common/common_types.h"
 #include "common/dynamic_library.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "core/frontend/emu_window.h"
 #include "video_core/vulkan_common/vulkan_instance.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 6442898bda74e46ab3a45e91c709e788c4a8a338..1732866e0424b5ed4a28c6b4b49e33d1567eab94 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -12,6 +12,7 @@
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
 #include "video_core/vulkan_common/vulkan_device.h"
 #include "video_core/vulkan_common/vulkan_memory_allocator.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index d88efacd78b0473874b269eb7b3d972838df2713..ee0126d00338b4535b2555db1fbbb7fbbcbcd92b 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -116,7 +116,7 @@ void EmuThread::run() {
             }
         } else {
             std::unique_lock lock{running_mutex};
-            running_cv.wait(lock, stop_token, [this] { return IsRunning(); });
+            Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); });
         }
     }
 
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index c45ebf1a2d34bb9a319edea3ec331729a37bdf1e..751f3408856e7c7cadb168aa5b75a61ae7bb6a03 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -14,6 +14,7 @@
 #include <QTouchEvent>
 #include <QWidget>
 
+#include "common/polyfill_thread.h"
 #include "common/thread.h"
 #include "core/frontend/emu_window.h"
 
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 4081af391dda750d1802a3c6fc886d1888f1aa96..ecb606a34ffcbf8827687dcf312f084bcfe0b68b 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2844,6 +2844,7 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
 }
 
 void GMainWindow::OnMenuReportCompatibility() {
+#if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__)
     const auto& caps = Common::GetCPUCaps();
     const bool has_fma = caps.fma || caps.fma4;
     const auto processor_count = std::thread::hardware_concurrency();
@@ -2870,6 +2871,11 @@ void GMainWindow::OnMenuReportCompatibility() {
                "&gt; "
                "Web."));
     }
+#else
+    QMessageBox::critical(this, tr("Hardware requirements not met"),
+                          tr("Your system does not meet the recommended hardware requirements. "
+                             "Compatibility reporting has been disabled."));
+#endif
 }
 
 void GMainWindow::OpenURL(const QUrl& url) {
diff --git a/src/yuzu/multiplayer/chat_room.h b/src/yuzu/multiplayer/chat_room.h
index 01c70fad073f916d57497ab6542c67797a202c9c..dd71ea4cdd0292642626773855f6986c5e2f6c8d 100644
--- a/src/yuzu/multiplayer/chat_room.h
+++ b/src/yuzu/multiplayer/chat_room.h
@@ -4,6 +4,7 @@
 #pragma once
 
 #include <memory>
+#include <unordered_map>
 #include <unordered_set>
 #include <QDialog>
 #include <QSortFilterProxyModel>