diff options
| author | Levi <L3ehunin@gmail.com> | 2021-01-10 22:09:56 -0700 | 
|---|---|---|
| committer | Levi <L3ehunin@gmail.com> | 2021-01-10 22:09:56 -0700 | 
| commit | 7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch) | |
| tree | 5056f9406dec188439cb0deb87603498243a9412 /src/common | |
| parent | bc69cc151192326f9b8e18bbda831f1589ba27e0 (diff) | |
| parent | 46cd71d1c773c29cce8b48e7e2b478bdf6d77085 (diff) | |
Merge remote-tracking branch 'upstream/master' into int-flags
Diffstat (limited to 'src/common')
37 files changed, 700 insertions, 701 deletions
| diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5d54516eb..2c2bd2ee8 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -102,7 +102,9 @@ add_library(common STATIC      atomic_ops.h      detached_tasks.cpp      detached_tasks.h +    bit_cast.h      bit_field.h +    bit_set.h      bit_util.h      cityhash.cpp      cityhash.h @@ -111,6 +113,7 @@ add_library(common STATIC      common_paths.h      common_types.h      concepts.h +    div_ceil.h      dynamic_library.cpp      dynamic_library.h      fiber.cpp @@ -132,13 +135,10 @@ add_library(common STATIC      math_util.h      memory_detect.cpp      memory_detect.h -    memory_hook.cpp -    memory_hook.h      microprofile.cpp      microprofile.h      microprofileui.h      misc.cpp -    multi_level_queue.h      page_table.cpp      page_table.h      param_package.cpp @@ -150,6 +150,8 @@ add_library(common STATIC      scope_exit.h      spin_lock.cpp      spin_lock.h +    stream.cpp +    stream.h      string_util.cpp      string_util.h      swap.h @@ -158,6 +160,8 @@ add_library(common STATIC      thread.cpp      thread.h      thread_queue_list.h +    thread_worker.cpp +    thread_worker.h      threadsafe_queue.h      time_zone.cpp      time_zone.h @@ -188,8 +192,28 @@ if(ARCHITECTURE_x86_64)      )  endif() +if (MSVC) +  target_compile_definitions(common PRIVATE +    # The standard library doesn't provide any replacement for codecvt yet +    # so we can disable this deprecation warning for the time being. +    _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING +  ) +  target_compile_options(common PRIVATE +    /W4 +    /WX +  ) +else() +  target_compile_options(common PRIVATE +    -Werror +  ) +endif() +  create_target_directory_groups(common) -find_package(Boost 1.71 COMPONENTS context headers REQUIRED)  target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile) -target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd xbyak) +target_link_libraries(common PRIVATE lz4::lz4 xbyak) +if (MSVC) +  target_link_libraries(common PRIVATE zstd::zstd) +else() +  target_link_libraries(common PRIVATE zstd) +endif() diff --git a/src/common/bit_cast.h b/src/common/bit_cast.h new file mode 100644 index 000000000..a32a063d1 --- /dev/null +++ b/src/common/bit_cast.h @@ -0,0 +1,22 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstring> +#include <type_traits> + +namespace Common { + +template <typename To, typename From> +[[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> && +                                   std::is_trivially_copyable_v<To>, +                               To> +BitCast(const From& src) noexcept { +    To dst; +    std::memcpy(&dst, &src, sizeof(To)); +    return dst; +} + +} // namespace Common diff --git a/src/common/bit_set.h b/src/common/bit_set.h new file mode 100644 index 000000000..9235ad412 --- /dev/null +++ b/src/common/bit_set.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <array> +#include <bit> + +#include "common/alignment.h" +#include "common/bit_util.h" +#include "common/common_types.h" + +namespace Common { + +namespace impl { + +template <typename Storage, size_t N> +class BitSet { + +public: +    constexpr BitSet() = default; + +    constexpr void SetBit(size_t i) { +        this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord); +    } + +    constexpr void ClearBit(size_t i) { +        this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord); +    } + +    constexpr size_t CountLeadingZero() const { +        for (size_t i = 0; i < NumWords; i++) { +            if (this->words[i]) { +                return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]); +            } +        } +        return FlagsPerWord * NumWords; +    } + +    constexpr size_t GetNextSet(size_t n) const { +        for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) { +            Storage word = this->words[i]; +            if (!IsAligned(n + 1, FlagsPerWord)) { +                word &= GetBitMask(n % FlagsPerWord) - 1; +            } +            if (word) { +                return FlagsPerWord * i + CountLeadingZeroImpl(word); +            } +        } +        return FlagsPerWord * NumWords; +    } + +private: +    static_assert(std::is_unsigned_v<Storage>); +    static_assert(sizeof(Storage) <= sizeof(u64)); + +    static constexpr size_t FlagsPerWord = BitSize<Storage>(); +    static constexpr size_t NumWords = AlignUp(N, FlagsPerWord) / FlagsPerWord; + +    static constexpr auto CountLeadingZeroImpl(Storage word) { +        return std::countl_zero(static_cast<unsigned long long>(word)) - +               (BitSize<unsigned long long>() - FlagsPerWord); +    } + +    static constexpr Storage GetBitMask(size_t bit) { +        return Storage(1) << (FlagsPerWord - 1 - bit); +    } + +    std::array<Storage, NumWords> words{}; +}; + +} // namespace impl + +template <size_t N> +using BitSet8 = impl::BitSet<u8, N>; + +template <size_t N> +using BitSet16 = impl::BitSet<u16, N>; + +template <size_t N> +using BitSet32 = impl::BitSet<u32, N>; + +template <size_t N> +using BitSet64 = impl::BitSet<u64, N>; + +} // namespace Common diff --git a/src/common/concepts.h b/src/common/concepts.h index 5bef3ad67..aa08065a7 100644 --- a/src/common/concepts.h +++ b/src/common/concepts.h @@ -31,4 +31,8 @@ concept DerivedFrom = requires {      std::is_convertible_v<const volatile Derived*, const volatile Base*>;  }; +// TODO: Replace with std::convertible_to when libc++ implements it. +template <typename From, typename To> +concept ConvertibleTo = std::is_convertible_v<From, To>; +  } // namespace Common diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h new file mode 100644 index 000000000..95e1489a9 --- /dev/null +++ b/src/common/div_ceil.h @@ -0,0 +1,26 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> +#include <type_traits> + +namespace Common { + +/// Ceiled integer division. +template <typename N, typename D> +requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeil(N number, +                                                                                        D divisor) { +    return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor); +} + +/// Ceiled integer division with logarithmic divisor in base 2 +template <typename N, typename D> +requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeilLog2( +    N value, D alignment_log2) { +    return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); +} + +} // namespace Common diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 1c1d09ccb..3c1eefcb7 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -4,129 +4,51 @@  #include "common/assert.h"  #include "common/fiber.h" -#if defined(_WIN32) || defined(WIN32) -#include <windows.h> -#else +#include "common/spin_lock.h" +#include "common/virtual_buffer.h" +  #include <boost/context/detail/fcontext.hpp> -#endif  namespace Common { -constexpr std::size_t default_stack_size = 256 * 1024; // 256kb - -#if defined(_WIN32) || defined(WIN32) +constexpr std::size_t default_stack_size = 256 * 1024;  struct Fiber::FiberImpl { -    LPVOID handle = nullptr; -    LPVOID rewind_handle = nullptr; +    FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {} + +    VirtualBuffer<u8> stack; +    VirtualBuffer<u8> rewind_stack; + +    SpinLock guard{}; +    std::function<void(void*)> entry_point; +    std::function<void(void*)> rewind_point; +    void* rewind_parameter{}; +    void* start_parameter{}; +    std::shared_ptr<Fiber> previous_fiber; +    bool is_thread_fiber{}; +    bool released{}; + +    u8* stack_limit{}; +    u8* rewind_stack_limit{}; +    boost::context::detail::fcontext_t context{}; +    boost::context::detail::fcontext_t rewind_context{};  }; -void Fiber::Start() { -    ASSERT(previous_fiber != nullptr); -    previous_fiber->guard.unlock(); -    previous_fiber.reset(); -    entry_point(start_parameter); -    UNREACHABLE(); -} - -void Fiber::OnRewind() { -    ASSERT(impl->handle != nullptr); -    DeleteFiber(impl->handle); -    impl->handle = impl->rewind_handle; -    impl->rewind_handle = nullptr; -    rewind_point(rewind_parameter); -    UNREACHABLE(); -} - -void Fiber::FiberStartFunc(void* fiber_parameter) { -    auto fiber = static_cast<Fiber*>(fiber_parameter); -    fiber->Start(); -} - -void Fiber::RewindStartFunc(void* fiber_parameter) { -    auto fiber = static_cast<Fiber*>(fiber_parameter); -    fiber->OnRewind(); -} - -Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) -    : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { -    impl = std::make_unique<FiberImpl>(); -    impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); -} - -Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} - -Fiber::~Fiber() { -    if (released) { -        return; -    } -    // Make sure the Fiber is not being used -    const bool locked = guard.try_lock(); -    ASSERT_MSG(locked, "Destroying a fiber that's still running"); -    if (locked) { -        guard.unlock(); -    } -    DeleteFiber(impl->handle); -} - -void Fiber::Exit() { -    ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); -    if (!is_thread_fiber) { -        return; -    } -    ConvertFiberToThread(); -    guard.unlock(); -    released = true; -} - -void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { -    rewind_point = std::move(rewind_func); -    rewind_parameter = start_parameter; -} - -void Fiber::Rewind() { -    ASSERT(rewind_point); -    ASSERT(impl->rewind_handle == nullptr); -    impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this); -    SwitchToFiber(impl->rewind_handle); -} - -void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { -    ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); -    ASSERT_MSG(to != nullptr, "Next fiber is null!"); -    to->guard.lock(); -    to->previous_fiber = from; -    SwitchToFiber(to->impl->handle); -    ASSERT(from->previous_fiber != nullptr); -    from->previous_fiber->guard.unlock(); -    from->previous_fiber.reset(); +void Fiber::SetStartParameter(void* new_parameter) { +    impl->start_parameter = new_parameter;  } -std::shared_ptr<Fiber> Fiber::ThreadToFiber() { -    std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; -    fiber->guard.lock(); -    fiber->impl->handle = ConvertThreadToFiber(nullptr); -    fiber->is_thread_fiber = true; -    return fiber; +void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) { +    impl->rewind_point = std::move(rewind_func); +    impl->rewind_parameter = rewind_param;  } -#else - -struct Fiber::FiberImpl { -    alignas(64) std::array<u8, default_stack_size> stack; -    alignas(64) std::array<u8, default_stack_size> rewind_stack; -    u8* stack_limit; -    u8* rewind_stack_limit; -    boost::context::detail::fcontext_t context; -    boost::context::detail::fcontext_t rewind_context; -}; -  void Fiber::Start(boost::context::detail::transfer_t& transfer) { -    ASSERT(previous_fiber != nullptr); -    previous_fiber->impl->context = transfer.fctx; -    previous_fiber->guard.unlock(); -    previous_fiber.reset(); -    entry_point(start_parameter); +    ASSERT(impl->previous_fiber != nullptr); +    impl->previous_fiber->impl->context = transfer.fctx; +    impl->previous_fiber->impl->guard.unlock(); +    impl->previous_fiber.reset(); +    impl->entry_point(impl->start_parameter);      UNREACHABLE();  } @@ -137,23 +59,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf      u8* tmp = impl->stack_limit;      impl->stack_limit = impl->rewind_stack_limit;      impl->rewind_stack_limit = tmp; -    rewind_point(rewind_parameter); +    impl->rewind_point(impl->rewind_parameter);      UNREACHABLE();  }  void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { -    auto fiber = static_cast<Fiber*>(transfer.data); +    auto* fiber = static_cast<Fiber*>(transfer.data);      fiber->Start(transfer);  }  void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { -    auto fiber = static_cast<Fiber*>(transfer.data); +    auto* fiber = static_cast<Fiber*>(transfer.data);      fiber->OnRewind(transfer);  }  Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) -    : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { -    impl = std::make_unique<FiberImpl>(); +    : impl{std::make_unique<FiberImpl>()} { +    impl->entry_point = std::move(entry_point_func); +    impl->start_parameter = start_parameter;      impl->stack_limit = impl->stack.data();      impl->rewind_stack_limit = impl->rewind_stack.data();      u8* stack_base = impl->stack_limit + default_stack_size; @@ -161,37 +84,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete          boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);  } -void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { -    rewind_point = std::move(rewind_func); -    rewind_parameter = start_parameter; -} -  Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}  Fiber::~Fiber() { -    if (released) { +    if (impl->released) {          return;      }      // Make sure the Fiber is not being used -    const bool locked = guard.try_lock(); +    const bool locked = impl->guard.try_lock();      ASSERT_MSG(locked, "Destroying a fiber that's still running");      if (locked) { -        guard.unlock(); +        impl->guard.unlock();      }  }  void Fiber::Exit() { - -    ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); -    if (!is_thread_fiber) { +    ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber"); +    if (!impl->is_thread_fiber) {          return;      } -    guard.unlock(); -    released = true; +    impl->guard.unlock(); +    impl->released = true;  }  void Fiber::Rewind() { -    ASSERT(rewind_point); +    ASSERT(impl->rewind_point);      ASSERT(impl->rewind_context == nullptr);      u8* stack_base = impl->rewind_stack_limit + default_stack_size;      impl->rewind_context = @@ -199,24 +116,23 @@ void Fiber::Rewind() {      boost::context::detail::jump_fcontext(impl->rewind_context, this);  } -void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { +void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {      ASSERT_MSG(from != nullptr, "Yielding fiber is null!");      ASSERT_MSG(to != nullptr, "Next fiber is null!"); -    to->guard.lock(); -    to->previous_fiber = from; +    to->impl->guard.lock(); +    to->impl->previous_fiber = from;      auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); -    ASSERT(from->previous_fiber != nullptr); -    from->previous_fiber->impl->context = transfer.fctx; -    from->previous_fiber->guard.unlock(); -    from->previous_fiber.reset(); +    ASSERT(from->impl->previous_fiber != nullptr); +    from->impl->previous_fiber->impl->context = transfer.fctx; +    from->impl->previous_fiber->impl->guard.unlock(); +    from->impl->previous_fiber.reset();  }  std::shared_ptr<Fiber> Fiber::ThreadToFiber() {      std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; -    fiber->guard.lock(); -    fiber->is_thread_fiber = true; +    fiber->impl->guard.lock(); +    fiber->impl->is_thread_fiber = true;      return fiber;  } -#endif  } // namespace Common diff --git a/src/common/fiber.h b/src/common/fiber.h index 89dde5e36..f7f587f8c 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -7,14 +7,9 @@  #include <functional>  #include <memory> -#include "common/common_types.h" -#include "common/spin_lock.h" - -#if !defined(_WIN32) && !defined(WIN32)  namespace boost::context::detail {  struct transfer_t;  } -#endif  namespace Common { @@ -46,10 +41,10 @@ public:      /// Yields control from Fiber 'from' to Fiber 'to'      /// Fiber 'from' must be the currently running fiber. -    static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to); +    static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);      [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); -    void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter); +    void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);      void Rewind(); @@ -57,36 +52,18 @@ public:      void Exit();      /// Changes the start parameter of the fiber. Has no effect if the fiber already started -    void SetStartParameter(void* new_parameter) { -        start_parameter = new_parameter; -    } +    void SetStartParameter(void* new_parameter);  private:      Fiber(); -#if defined(_WIN32) || defined(WIN32) -    void OnRewind(); -    void Start(); -    static void FiberStartFunc(void* fiber_parameter); -    static void RewindStartFunc(void* fiber_parameter); -#else      void OnRewind(boost::context::detail::transfer_t& transfer);      void Start(boost::context::detail::transfer_t& transfer);      static void FiberStartFunc(boost::context::detail::transfer_t transfer);      static void RewindStartFunc(boost::context::detail::transfer_t transfer); -#endif      struct FiberImpl; - -    SpinLock guard{}; -    std::function<void(void*)> entry_point; -    std::function<void(void*)> rewind_point; -    void* rewind_parameter{}; -    void* start_parameter{}; -    std::shared_ptr<Fiber> previous_fiber;      std::unique_ptr<FiberImpl> impl; -    bool is_thread_fiber{}; -    bool released{};  };  } // namespace Common diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 16c3713e0..18fbfa25b 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -472,13 +472,14 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,  }  bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) { -    const auto callback = [recursion](u64* num_entries_out, const std::string& directory, -                                      const std::string& virtual_name) -> bool { -        std::string new_path = directory + DIR_SEP_CHR + virtual_name; +    const auto callback = [recursion](u64*, const std::string& directory, +                                      const std::string& virtual_name) { +        const std::string new_path = directory + DIR_SEP_CHR + virtual_name;          if (IsDirectory(new_path)) { -            if (recursion == 0) +            if (recursion == 0) {                  return false; +            }              return DeleteDirRecursively(new_path, recursion - 1);          }          return Delete(new_path); @@ -492,7 +493,8 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)      return true;  } -void CopyDir(const std::string& source_path, const std::string& dest_path) { +void CopyDir([[maybe_unused]] const std::string& source_path, +             [[maybe_unused]] const std::string& dest_path) {  #ifndef _WIN32      if (source_path == dest_path) {          return; @@ -553,7 +555,7 @@ std::optional<std::string> GetCurrentDir() {      std::string strDir = dir;  #endif      free(dir); -    return std::move(strDir); +    return strDir;  }  bool SetCurrentDir(const std::string& directory) { @@ -772,21 +774,23 @@ std::size_t ReadFileToString(bool text_file, const std::string& filename, std::s  void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,                       std::array<char, 4>& extension) { -    const std::string forbidden_characters = ".\"/\\[]:;=, "; +    static constexpr std::string_view forbidden_characters = ".\"/\\[]:;=, ";      // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces.      short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}};      extension = {{' ', ' ', ' ', '\0'}}; -    std::string::size_type point = filename.rfind('.'); -    if (point == filename.size() - 1) +    auto point = filename.rfind('.'); +    if (point == filename.size() - 1) {          point = filename.rfind('.', point); +    }      // Get short name.      int j = 0;      for (char letter : filename.substr(0, point)) { -        if (forbidden_characters.find(letter, 0) != std::string::npos) +        if (forbidden_characters.find(letter, 0) != std::string::npos) {              continue; +        }          if (j == 8) {              // TODO(Link Mauve): also do that for filenames containing a space.              // TODO(Link Mauve): handle multiple files having the same short name. @@ -794,14 +798,15 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam              short_name[7] = '1';              break;          } -        short_name[j++] = toupper(letter); +        short_name[j++] = static_cast<char>(std::toupper(letter));      }      // Get extension.      if (point != std::string::npos) {          j = 0; -        for (char letter : filename.substr(point + 1, 3)) -            extension[j++] = toupper(letter); +        for (char letter : filename.substr(point + 1, 3)) { +            extension[j++] = static_cast<char>(std::toupper(letter)); +        }      }  } diff --git a/src/common/file_util.h b/src/common/file_util.h index 8b587320f..840cde2a6 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -232,7 +232,7 @@ public:      void Swap(IOFile& other) noexcept; -    [[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0); +    bool Open(const std::string& filename, const char openmode[], int flags = 0);      bool Close();      template <typename T> diff --git a/src/common/hex_util.h b/src/common/hex_util.h index 120f1a5e6..a8d414fb8 100644 --- a/src/common/hex_util.h +++ b/src/common/hex_util.h @@ -16,14 +16,14 @@ namespace Common {  [[nodiscard]] constexpr u8 ToHexNibble(char c) {      if (c >= 65 && c <= 70) { -        return c - 55; +        return static_cast<u8>(c - 55);      }      if (c >= 97 && c <= 102) { -        return c - 87; +        return static_cast<u8>(c - 87);      } -    return c - 48; +    return static_cast<u8>(c - 48);  }  [[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); @@ -33,11 +33,11 @@ template <std::size_t Size, bool le = false>      std::array<u8, Size> out{};      if constexpr (le) {          for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { -            out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); +            out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));          }      } else {          for (std::size_t i = 0; i < 2 * Size; i += 2) { -            out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); +            out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));          }      }      return out; diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 62cfde397..631f64d05 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -23,6 +23,7 @@  #include "common/logging/text_formatter.h"  #include "common/string_util.h"  #include "common/threadsafe_queue.h" +#include "core/settings.h"  namespace Log { @@ -152,10 +153,19 @@ FileBackend::FileBackend(const std::string& filename)  void FileBackend::Write(const Entry& entry) {      // prevent logs from going over the maximum size (in case its spamming and the user doesn't      // know) -    constexpr std::size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L; -    if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { +    constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024; +    constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024; + +    if (!file.IsOpen()) { +        return; +    } + +    if (Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN_EXTENDED) { +        return; +    } else if (!Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN) {          return;      } +      bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n'));      if (entry.log_level >= Level::Error) {          file.Flush(); @@ -222,6 +232,7 @@ void DebuggerBackend::Write(const Entry& entry) {      SUB(Service, NPNS)                                                                             \      SUB(Service, NS)                                                                               \      SUB(Service, NVDRV)                                                                            \ +    SUB(Service, OLSC)                                                                             \      SUB(Service, PCIE)                                                                             \      SUB(Service, PCTL)                                                                             \      SUB(Service, PCV)                                                                              \ @@ -274,7 +285,6 @@ const char* GetLogClassName(Class log_class) {      case Class::Count:          break;      } -    UNREACHABLE();      return "Invalid";  } @@ -293,7 +303,6 @@ const char* GetLevelName(Level log_level) {          break;      }  #undef LVL -    UNREACHABLE();      return "Invalid";  } diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 13a4f1e30..835894918 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -95,6 +95,7 @@ enum class Class : ClassType {      Service_NPNS,      ///< The NPNS service      Service_NS,        ///< The NS services      Service_NVDRV,     ///< The NVDRV (Nvidia driver) service +    Service_OLSC,      ///< The OLSC service      Service_PCIE,      ///< The PCIe service      Service_PCTL,      ///< The PCTL (Parental control) service      Service_PCV,       ///< The PCV service diff --git a/src/common/math_util.h b/src/common/math_util.h index b35ad8507..4c38d8040 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h @@ -20,14 +20,14 @@ struct Rectangle {      constexpr Rectangle() = default; -    constexpr Rectangle(T left, T top, T right, T bottom) -        : left(left), top(top), right(right), bottom(bottom) {} +    constexpr Rectangle(T left_, T top_, T right_, T bottom_) +        : left(left_), top(top_), right(right_), bottom(bottom_) {}      [[nodiscard]] T GetWidth() const {          if constexpr (std::is_floating_point_v<T>) {              return std::abs(right - left);          } else { -            return std::abs(static_cast<std::make_signed_t<T>>(right - left)); +            return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(right - left)));          }      } @@ -35,7 +35,7 @@ struct Rectangle {          if constexpr (std::is_floating_point_v<T>) {              return std::abs(bottom - top);          } else { -            return std::abs(static_cast<std::make_signed_t<T>>(bottom - top)); +            return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(bottom - top)));          }      } diff --git a/src/common/memory_hook.cpp b/src/common/memory_hook.cpp deleted file mode 100644 index 3986986d6..000000000 --- a/src/common/memory_hook.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/memory_hook.h" - -namespace Common { - -MemoryHook::~MemoryHook() = default; - -} // namespace Common diff --git a/src/common/memory_hook.h b/src/common/memory_hook.h deleted file mode 100644 index adaa4c2c5..000000000 --- a/src/common/memory_hook.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <optional> - -#include "common/common_types.h" - -namespace Common { - -/** - * Memory hooks have two purposes: - * 1. To allow reads and writes to a region of memory to be intercepted. This is used to implement - *    texture forwarding and memory breakpoints for debugging. - * 2. To allow for the implementation of MMIO devices. - * - * A hook may be mapped to multiple regions of memory. - * - * If a std::nullopt or false is returned from a function, the read/write request is passed through - * to the underlying memory region. - */ -class MemoryHook { -public: -    virtual ~MemoryHook(); - -    virtual std::optional<bool> IsValidAddress(VAddr addr) = 0; - -    virtual std::optional<u8> Read8(VAddr addr) = 0; -    virtual std::optional<u16> Read16(VAddr addr) = 0; -    virtual std::optional<u32> Read32(VAddr addr) = 0; -    virtual std::optional<u64> Read64(VAddr addr) = 0; - -    virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; - -    virtual bool Write8(VAddr addr, u8 data) = 0; -    virtual bool Write16(VAddr addr, u16 data) = 0; -    virtual bool Write32(VAddr addr, u32 data) = 0; -    virtual bool Write64(VAddr addr, u64 data) = 0; - -    virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0; -}; - -using MemoryHookPointer = std::shared_ptr<MemoryHook>; -} // namespace Common diff --git a/src/common/misc.cpp b/src/common/misc.cpp index 68cb86cd1..1d5393597 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp @@ -16,16 +16,23 @@  // Call directly after the command or use the error num.  // This function might change the error code.  std::string GetLastErrorMsg() { -    static const std::size_t buff_size = 255; +    static constexpr std::size_t buff_size = 255;      char err_str[buff_size];  #ifdef _WIN32      FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); +    return std::string(err_str, buff_size); +#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) +    // Thread safe (GNU-specific) +    const char* str = strerror_r(errno, err_str, buff_size); +    return std::string(str);  #else      // Thread safe (XSI-compliant) -    strerror_r(errno, err_str, buff_size); +    const int success = strerror_r(errno, err_str, buff_size); +    if (success != 0) { +        return {}; +    } +    return std::string(err_str);  #endif - -    return std::string(err_str, buff_size);  } diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h deleted file mode 100644 index 4b305bf40..000000000 --- a/src/common/multi_level_queue.h +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2019 TuxSH -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <iterator> -#include <list> -#include <utility> - -#include "common/bit_util.h" -#include "common/common_types.h" - -namespace Common { - -/** - * A MultiLevelQueue is a type of priority queue which has the following characteristics: - * - iteratable through each of its elements. - * - back can be obtained. - * - O(1) add, lookup (both front and back) - * - discrete priorities and a max of 64 priorities (limited domain) - * This type of priority queue is normaly used for managing threads within an scheduler - */ -template <typename T, std::size_t Depth> -class MultiLevelQueue { -public: -    using value_type = T; -    using reference = value_type&; -    using const_reference = const value_type&; -    using pointer = value_type*; -    using const_pointer = const value_type*; - -    using difference_type = typename std::pointer_traits<pointer>::difference_type; -    using size_type = std::size_t; - -    template <bool is_constant> -    class iterator_impl { -    public: -        using iterator_category = std::bidirectional_iterator_tag; -        using value_type = T; -        using pointer = std::conditional_t<is_constant, T*, const T*>; -        using reference = std::conditional_t<is_constant, const T&, T&>; -        using difference_type = typename std::pointer_traits<pointer>::difference_type; - -        friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) { -            if (lhs.IsEnd() && rhs.IsEnd()) -                return true; -            return std::tie(lhs.current_priority, lhs.it) == std::tie(rhs.current_priority, rhs.it); -        } - -        friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) { -            return !operator==(lhs, rhs); -        } - -        reference operator*() const { -            return *it; -        } - -        pointer operator->() const { -            return it.operator->(); -        } - -        iterator_impl& operator++() { -            if (IsEnd()) { -                return *this; -            } - -            ++it; - -            if (it == GetEndItForPrio()) { -                u64 prios = mlq.used_priorities; -                prios &= ~((1ULL << (current_priority + 1)) - 1); -                if (prios == 0) { -                    current_priority = static_cast<u32>(mlq.depth()); -                } else { -                    current_priority = CountTrailingZeroes64(prios); -                    it = GetBeginItForPrio(); -                } -            } -            return *this; -        } - -        iterator_impl& operator--() { -            if (IsEnd()) { -                if (mlq.used_priorities != 0) { -                    current_priority = 63 - CountLeadingZeroes64(mlq.used_priorities); -                    it = GetEndItForPrio(); -                    --it; -                } -            } else if (it == GetBeginItForPrio()) { -                u64 prios = mlq.used_priorities; -                prios &= (1ULL << current_priority) - 1; -                if (prios != 0) { -                    current_priority = CountTrailingZeroes64(prios); -                    it = GetEndItForPrio(); -                    --it; -                } -            } else { -                --it; -            } -            return *this; -        } - -        iterator_impl operator++(int) { -            const iterator_impl v{*this}; -            ++(*this); -            return v; -        } - -        iterator_impl operator--(int) { -            const iterator_impl v{*this}; -            --(*this); -            return v; -        } - -        // allow implicit const->non-const -        iterator_impl(const iterator_impl<false>& other) -            : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {} - -        iterator_impl(const iterator_impl<true>& other) -            : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {} - -        iterator_impl& operator=(const iterator_impl<false>& other) { -            mlq = other.mlq; -            it = other.it; -            current_priority = other.current_priority; -            return *this; -        } - -        friend class iterator_impl<true>; -        iterator_impl() = default; - -    private: -        friend class MultiLevelQueue; -        using container_ref = -            std::conditional_t<is_constant, const MultiLevelQueue&, MultiLevelQueue&>; -        using list_iterator = std::conditional_t<is_constant, typename std::list<T>::const_iterator, -                                                 typename std::list<T>::iterator>; - -        explicit iterator_impl(container_ref mlq, list_iterator it, u32 current_priority) -            : mlq(mlq), it(it), current_priority(current_priority) {} -        explicit iterator_impl(container_ref mlq, u32 current_priority) -            : mlq(mlq), it(), current_priority(current_priority) {} - -        bool IsEnd() const { -            return current_priority == mlq.depth(); -        } - -        list_iterator GetBeginItForPrio() const { -            return mlq.levels[current_priority].begin(); -        } - -        list_iterator GetEndItForPrio() const { -            return mlq.levels[current_priority].end(); -        } - -        container_ref mlq; -        list_iterator it; -        u32 current_priority; -    }; - -    using iterator = iterator_impl<false>; -    using const_iterator = iterator_impl<true>; - -    void add(const T& element, u32 priority, bool send_back = true) { -        if (send_back) -            levels[priority].push_back(element); -        else -            levels[priority].push_front(element); -        used_priorities |= 1ULL << priority; -    } - -    void remove(const T& element, u32 priority) { -        auto it = ListIterateTo(levels[priority], element); -        if (it == levels[priority].end()) -            return; -        levels[priority].erase(it); -        if (levels[priority].empty()) { -            used_priorities &= ~(1ULL << priority); -        } -    } - -    void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) { -        remove(element, old_priority); -        add(element, new_priority, !adjust_front); -    } -    void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) { -        adjust(*it, old_priority, new_priority, adjust_front); -    } - -    void transfer_to_front(const T& element, u32 priority, MultiLevelQueue& other) { -        ListSplice(other.levels[priority], other.levels[priority].begin(), levels[priority], -                   ListIterateTo(levels[priority], element)); - -        other.used_priorities |= 1ULL << priority; - -        if (levels[priority].empty()) { -            used_priorities &= ~(1ULL << priority); -        } -    } - -    void transfer_to_front(const_iterator it, u32 priority, MultiLevelQueue& other) { -        transfer_to_front(*it, priority, other); -    } - -    void transfer_to_back(const T& element, u32 priority, MultiLevelQueue& other) { -        ListSplice(other.levels[priority], other.levels[priority].end(), levels[priority], -                   ListIterateTo(levels[priority], element)); - -        other.used_priorities |= 1ULL << priority; - -        if (levels[priority].empty()) { -            used_priorities &= ~(1ULL << priority); -        } -    } - -    void transfer_to_back(const_iterator it, u32 priority, MultiLevelQueue& other) { -        transfer_to_back(*it, priority, other); -    } - -    void yield(u32 priority, std::size_t n = 1) { -        ListShiftForward(levels[priority], n); -    } - -    [[nodiscard]] std::size_t depth() const { -        return Depth; -    } - -    [[nodiscard]] std::size_t size(u32 priority) const { -        return levels[priority].size(); -    } - -    [[nodiscard]] std::size_t size() const { -        u64 priorities = used_priorities; -        std::size_t size = 0; -        while (priorities != 0) { -            const u64 current_priority = CountTrailingZeroes64(priorities); -            size += levels[current_priority].size(); -            priorities &= ~(1ULL << current_priority); -        } -        return size; -    } - -    [[nodiscard]] bool empty() const { -        return used_priorities == 0; -    } - -    [[nodiscard]] bool empty(u32 priority) const { -        return (used_priorities & (1ULL << priority)) == 0; -    } - -    [[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const { -        const u64 priorities = -            max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1)); -        return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities)); -    } - -    [[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const { -        const u64 priorities = min_priority >= Depth - 1 -                                   ? used_priorities -                                   : (used_priorities & ((1ULL << (min_priority + 1)) - 1)); -        return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities); -    } - -    [[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const { -        const u32 priority = highest_priority_set(max_prio); -        return priority == Depth ? cend() -                                 : const_iterator{*this, levels[priority].cbegin(), priority}; -    } -    [[nodiscard]] const_iterator begin(u32 max_prio = 0) const { -        return cbegin(max_prio); -    } -    [[nodiscard]] iterator begin(u32 max_prio = 0) { -        const u32 priority = highest_priority_set(max_prio); -        return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority}; -    } - -    [[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const { -        return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1); -    } -    [[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const { -        return cend(min_prio); -    } -    [[nodiscard]] iterator end(u32 min_prio = Depth - 1) { -        return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1); -    } - -    [[nodiscard]] T& front(u32 max_priority = 0) { -        const u32 priority = highest_priority_set(max_priority); -        return levels[priority == Depth ? 0 : priority].front(); -    } -    [[nodiscard]] const T& front(u32 max_priority = 0) const { -        const u32 priority = highest_priority_set(max_priority); -        return levels[priority == Depth ? 0 : priority].front(); -    } - -    [[nodiscard]] T& back(u32 min_priority = Depth - 1) { -        const u32 priority = lowest_priority_set(min_priority); // intended -        return levels[priority == Depth ? 63 : priority].back(); -    } -    [[nodiscard]] const T& back(u32 min_priority = Depth - 1) const { -        const u32 priority = lowest_priority_set(min_priority); // intended -        return levels[priority == Depth ? 63 : priority].back(); -    } - -    void clear() { -        used_priorities = 0; -        for (std::size_t i = 0; i < Depth; i++) { -            levels[i].clear(); -        } -    } - -private: -    using const_list_iterator = typename std::list<T>::const_iterator; - -    static void ListShiftForward(std::list<T>& list, const std::size_t shift = 1) { -        if (shift >= list.size()) { -            return; -        } - -        const auto begin_range = list.begin(); -        const auto end_range = std::next(begin_range, shift); -        list.splice(list.end(), list, begin_range, end_range); -    } - -    static void ListSplice(std::list<T>& in_list, const_list_iterator position, -                           std::list<T>& out_list, const_list_iterator element) { -        in_list.splice(position, out_list, element); -    } - -    [[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list, -                                                           const T& element) { -        auto it = list.cbegin(); -        while (it != list.cend() && *it != element) { -            ++it; -        } -        return it; -    } - -    std::array<std::list<T>, Depth> levels; -    u64 used_priorities = 0; -}; - -} // namespace Common diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index e5d3090d5..8fd8620fd 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp @@ -8,18 +8,12 @@ namespace Common {  PageTable::PageTable() = default; -PageTable::~PageTable() = default; +PageTable::~PageTable() noexcept = default; -void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, -                       bool has_attribute) { -    const std::size_t num_page_table_entries{1ULL -                                             << (address_space_width_in_bits - page_size_in_bits)}; +void PageTable::Resize(size_t address_space_width_in_bits, size_t page_size_in_bits) { +    const size_t num_page_table_entries{1ULL << (address_space_width_in_bits - page_size_in_bits)};      pointers.resize(num_page_table_entries);      backing_addr.resize(num_page_table_entries); - -    if (has_attribute) { -        attributes.resize(num_page_table_entries); -    }  }  } // namespace Common diff --git a/src/common/page_table.h b/src/common/page_table.h index cf5eed780..61c5552e0 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h @@ -4,12 +4,10 @@  #pragma once -#include <vector> - -#include <boost/icl/interval_map.hpp> +#include <atomic> +#include <tuple>  #include "common/common_types.h" -#include "common/memory_hook.h"  #include "common/virtual_buffer.h"  namespace Common { @@ -22,27 +20,6 @@ enum class PageType : u8 {      /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and      /// invalidation      RasterizerCachedMemory, -    /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. -    Special, -    /// Page is allocated for use. -    Allocated, -}; - -struct SpecialRegion { -    enum class Type { -        DebugHook, -        IODevice, -    } type; - -    MemoryHookPointer handler; - -    [[nodiscard]] bool operator<(const SpecialRegion& other) const { -        return std::tie(type, handler) < std::tie(other.type, other.handler); -    } - -    [[nodiscard]] bool operator==(const SpecialRegion& other) const { -        return std::tie(type, handler) == std::tie(other.type, other.handler); -    }  };  /** @@ -50,27 +27,84 @@ struct SpecialRegion {   * mimics the way a real CPU page table works.   */  struct PageTable { +    /// Number of bits reserved for attribute tagging. +    /// This can be at most the guaranteed alignment of the pointers in the page table. +    static constexpr int ATTRIBUTE_BITS = 2; + +    /** +     * Pair of host pointer and page type attribute. +     * This uses the lower bits of a given pointer to store the attribute tag. +     * Writing and reading the pointer attribute pair is guaranteed to be atomic for the same method +     * call. In other words, they are guaranteed to be synchronized at all times. +     */ +    class PageInfo { +    public: +        /// Returns the page pointer +        [[nodiscard]] u8* Pointer() const noexcept { +            return ExtractPointer(raw.load(std::memory_order_relaxed)); +        } + +        /// Returns the page type attribute +        [[nodiscard]] PageType Type() const noexcept { +            return ExtractType(raw.load(std::memory_order_relaxed)); +        } + +        /// Returns the page pointer and attribute pair, extracted from the same atomic read +        [[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept { +            const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed); +            return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)}; +        } + +        /// Returns the raw representation of the page information. +        /// Use ExtractPointer and ExtractType to unpack the value. +        [[nodiscard]] uintptr_t Raw() const noexcept { +            return raw.load(std::memory_order_relaxed); +        } + +        /// Write a page pointer and type pair atomically +        void Store(u8* pointer, PageType type) noexcept { +            raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type)); +        } + +        /// Unpack a pointer from a page info raw representation +        [[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept { +            return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS)); +        } + +        /// Unpack a page type from a page info raw representation +        [[nodiscard]] static PageType ExtractType(uintptr_t raw) noexcept { +            return static_cast<PageType>(raw & ((uintptr_t{1} << ATTRIBUTE_BITS) - 1)); +        } + +    private: +        std::atomic<uintptr_t> raw; +    }; +      PageTable(); -    ~PageTable(); +    ~PageTable() noexcept; + +    PageTable(const PageTable&) = delete; +    PageTable& operator=(const PageTable&) = delete; + +    PageTable(PageTable&&) noexcept = default; +    PageTable& operator=(PageTable&&) noexcept = default;      /** -     * Resizes the page table to be able to accomodate enough pages within +     * Resizes the page table to be able to accommodate enough pages within       * a given address space.       *       * @param address_space_width_in_bits The address size width in bits. +     * @param page_size_in_bits           The page size in bits.       */ -    void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, -                bool has_attribute); +    void Resize(size_t address_space_width_in_bits, size_t page_size_in_bits);      /**       * Vector of memory pointers backing each page. An entry can only be non-null if the -     * corresponding entry in the `attributes` vector is of type `Memory`. +     * corresponding attribute element is of type `Memory`.       */ -    VirtualBuffer<u8*> pointers; +    VirtualBuffer<PageInfo> pointers;      VirtualBuffer<u64> backing_addr; - -    VirtualBuffer<PageType> attributes;  };  } // namespace Common diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 68ef5f197..fa46cb394 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h @@ -10,7 +10,7 @@  namespace detail {  template <typename Func>  struct ScopeExitHelper { -    explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {} +    explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}      ~ScopeExitHelper() {          if (active) {              func(); diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h index 4f946a258..06ac2f5bb 100644 --- a/src/common/spin_lock.h +++ b/src/common/spin_lock.h @@ -15,6 +15,14 @@ namespace Common {   */  class SpinLock {  public: +    SpinLock() = default; + +    SpinLock(const SpinLock&) = delete; +    SpinLock& operator=(const SpinLock&) = delete; + +    SpinLock(SpinLock&&) = delete; +    SpinLock& operator=(SpinLock&&) = delete; +      void lock();      void unlock();      [[nodiscard]] bool try_lock(); diff --git a/src/common/stream.cpp b/src/common/stream.cpp new file mode 100644 index 000000000..bf0496c26 --- /dev/null +++ b/src/common/stream.cpp @@ -0,0 +1,47 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <stdexcept> +#include "common/common_types.h" +#include "common/stream.h" + +namespace Common { + +Stream::Stream() = default; +Stream::~Stream() = default; + +void Stream::Seek(s32 offset, SeekOrigin origin) { +    if (origin == SeekOrigin::SetOrigin) { +        if (offset < 0) { +            position = 0; +        } else if (position >= buffer.size()) { +            position = buffer.size(); +        } else { +            position = offset; +        } +    } else if (origin == SeekOrigin::FromCurrentPos) { +        Seek(static_cast<s32>(position) + offset, SeekOrigin::SetOrigin); +    } else if (origin == SeekOrigin::FromEnd) { +        Seek(static_cast<s32>(buffer.size()) - offset, SeekOrigin::SetOrigin); +    } +} + +u8 Stream::ReadByte() { +    if (position < buffer.size()) { +        return buffer[position++]; +    } else { +        throw std::out_of_range("Attempting to read a byte not within the buffer range"); +    } +} + +void Stream::WriteByte(u8 byte) { +    if (position == buffer.size()) { +        buffer.push_back(byte); +        position++; +    } else { +        buffer.insert(buffer.begin() + position, byte); +    } +} + +} // namespace Common diff --git a/src/common/stream.h b/src/common/stream.h new file mode 100644 index 000000000..0e40692de --- /dev/null +++ b/src/common/stream.h @@ -0,0 +1,56 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include "common/common_types.h" + +namespace Common { + +enum class SeekOrigin { +    SetOrigin, +    FromCurrentPos, +    FromEnd, +}; + +class Stream { +public: +    /// Stream creates a bitstream and provides common functionality on the stream. +    explicit Stream(); +    ~Stream(); + +    Stream(const Stream&) = delete; +    Stream& operator=(const Stream&) = delete; + +    Stream(Stream&&) = default; +    Stream& operator=(Stream&&) = default; + +    /// Reposition bitstream "cursor" to the specified offset from origin +    void Seek(s32 offset, SeekOrigin origin); + +    /// Reads next byte in the stream buffer and increments position +    u8 ReadByte(); + +    /// Writes byte at current position +    void WriteByte(u8 byte); + +    [[nodiscard]] std::size_t GetPosition() const { +        return position; +    } + +    [[nodiscard]] std::vector<u8>& GetBuffer() { +        return buffer; +    } + +    [[nodiscard]] const std::vector<u8>& GetBuffer() const { +        return buffer; +    } + +private: +    std::vector<u8> buffer; +    std::size_t position{0}; +}; + +} // namespace Common diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 84883a1d3..4cba2aaa4 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -8,6 +8,7 @@  #include <cstdlib>  #include <locale>  #include <sstream> +  #include "common/common_paths.h"  #include "common/logging/log.h"  #include "common/string_util.h" @@ -21,14 +22,14 @@ namespace Common {  /// Make a string lowercase  std::string ToLower(std::string str) {      std::transform(str.begin(), str.end(), str.begin(), -                   [](unsigned char c) { return std::tolower(c); }); +                   [](unsigned char c) { return static_cast<char>(std::tolower(c)); });      return str;  }  /// Make a string uppercase  std::string ToUpper(std::string str) {      std::transform(str.begin(), str.end(), str.begin(), -                   [](unsigned char c) { return std::toupper(c); }); +                   [](unsigned char c) { return static_cast<char>(std::toupper(c)); });      return str;  } diff --git a/src/common/swap.h b/src/common/swap.h index 7665942a2..a80e191dc 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -394,7 +394,7 @@ public:      template <typename S, typename T2, typename F2>      friend S operator%(const S& p, const swapped_t v); -    // Arithmetics + assignements +    // Arithmetics + assignments      template <typename S, typename T2, typename F2>      friend S operator+=(const S& p, const swapped_t v); @@ -451,7 +451,7 @@ S operator%(const S& i, const swap_struct_t<T, F> v) {      return i % v.swap();  } -// Arithmetics + assignements +// Arithmetics + assignments  template <typename S, typename T, typename F>  S& operator+=(S& i, const swap_struct_t<T, F> v) {      i += v.swap(); diff --git a/src/common/telemetry.h b/src/common/telemetry.h index a50c5d1de..49186e848 100644 --- a/src/common/telemetry.h +++ b/src/common/telemetry.h @@ -52,8 +52,8 @@ public:  template <typename T>  class Field : public FieldInterface {  public: -    Field(FieldType type, std::string name, T value) -        : name(std::move(name)), type(type), value(std::move(value)) {} +    Field(FieldType type_, std::string name_, T value_) +        : name(std::move(name_)), type(type_), value(std::move(value_)) {}      Field(const Field&) = default;      Field& operator=(const Field&) = default; diff --git a/src/common/thread_worker.cpp b/src/common/thread_worker.cpp new file mode 100644 index 000000000..8f9bf447a --- /dev/null +++ b/src/common/thread_worker.cpp @@ -0,0 +1,58 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/thread.h" +#include "common/thread_worker.h" + +namespace Common { + +ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) { +    for (std::size_t i = 0; i < num_workers; ++i) +        threads.emplace_back([this, thread_name{std::string{name}}] { +            Common::SetCurrentThreadName(thread_name.c_str()); + +            // Wait for first request +            { +                std::unique_lock lock{queue_mutex}; +                condition.wait(lock, [this] { return stop || !requests.empty(); }); +            } + +            while (true) { +                std::function<void()> task; + +                { +                    std::unique_lock lock{queue_mutex}; +                    condition.wait(lock, [this] { return stop || !requests.empty(); }); +                    if (stop || requests.empty()) { +                        return; +                    } +                    task = std::move(requests.front()); +                    requests.pop(); +                } + +                task(); +            } +        }); +} + +ThreadWorker::~ThreadWorker() { +    { +        std::unique_lock lock{queue_mutex}; +        stop = true; +    } +    condition.notify_all(); +    for (std::thread& thread : threads) { +        thread.join(); +    } +} + +void ThreadWorker::QueueWork(std::function<void()>&& work) { +    { +        std::unique_lock lock{queue_mutex}; +        requests.emplace(work); +    } +    condition.notify_one(); +} + +} // namespace Common diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h new file mode 100644 index 000000000..f1859971f --- /dev/null +++ b/src/common/thread_worker.h @@ -0,0 +1,30 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> +#include <functional> +#include <mutex> +#include <string> +#include <vector> +#include <queue> + +namespace Common { + +class ThreadWorker final { +public: +    explicit ThreadWorker(std::size_t num_workers, const std::string& name); +    ~ThreadWorker(); +    void QueueWork(std::function<void()>&& work); + +private: +    std::vector<std::thread> threads; +    std::queue<std::function<void()>> requests; +    std::mutex queue_mutex; +    std::condition_variable condition; +    std::atomic_bool stop{}; +}; + +} // namespace Common diff --git a/src/common/timer.cpp b/src/common/timer.cpp index 2dc15e434..d17dc2a50 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -142,20 +142,18 @@ std::string Timer::GetTimeFormatted() {  // ----------------  double Timer::GetDoubleTime() {      // Get continuous timestamp -    u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count()); -    double ms = static_cast<u64>(GetTimeMs().count()) % 1000; +    auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count()); +    const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000);      // Remove a few years. We only really want enough seconds to make      // sure that we are detecting actual actions, perhaps 60 seconds is      // enough really, but I leave a year of seconds anyway, in case the      // user's clock is incorrect or something like that. -    TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); +    tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60);      // Make a smaller integer that fits in the double -    u32 Seconds = static_cast<u32>(TmpSeconds); -    double TmpTime = Seconds + ms; - -    return TmpTime; +    const auto seconds = static_cast<u32>(tmp_seconds); +    return seconds + ms;  }  } // Namespace Common diff --git a/src/common/vector_math.h b/src/common/vector_math.h index 2a0fcf541..22dba3c2d 100644 --- a/src/common/vector_math.h +++ b/src/common/vector_math.h @@ -87,7 +87,13 @@ public:      template <typename V>      [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { -        return {x * f, y * f}; +        using TV = decltype(T{} * V{}); +        using C = std::common_type_t<T, V>; + +        return { +            static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)), +        };      }      template <typename V> @@ -98,7 +104,13 @@ public:      template <typename V>      [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { -        return {x / f, y / f}; +        using TV = decltype(T{} / V{}); +        using C = std::common_type_t<T, V>; + +        return { +            static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)), +        };      }      template <typename V> @@ -168,7 +180,10 @@ public:  template <typename T, typename V>  [[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { -    return Vec2<T>(f * vec.x, f * vec.y); +    using C = std::common_type_t<T, V>; + +    return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)), +                   static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));  }  using Vec2f = Vec2<float>; @@ -237,7 +252,14 @@ public:      template <typename V>      [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { -        return {x * f, y * f, z * f}; +        using TV = decltype(T{} * V{}); +        using C = std::common_type_t<T, V>; + +        return { +            static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)), +        };      }      template <typename V> @@ -247,7 +269,14 @@ public:      }      template <typename V>      [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { -        return {x / f, y / f, z / f}; +        using TV = decltype(T{} / V{}); +        using C = std::common_type_t<T, V>; + +        return { +            static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)), +        };      }      template <typename V> @@ -367,7 +396,11 @@ public:  template <typename T, typename V>  [[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { -    return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); +    using C = std::common_type_t<T, V>; + +    return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)), +                   static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)), +                   static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));  }  template <> @@ -446,7 +479,15 @@ public:      template <typename V>      [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { -        return {x * f, y * f, z * f, w * f}; +        using TV = decltype(T{} * V{}); +        using C = std::common_type_t<T, V>; + +        return { +            static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)), +        };      }      template <typename V> @@ -457,7 +498,15 @@ public:      template <typename V>      [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { -        return {x / f, y / f, z / f, w / f}; +        using TV = decltype(T{} / V{}); +        using C = std::common_type_t<T, V>; + +        return { +            static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)), +            static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)), +        };      }      template <typename V> @@ -582,7 +631,15 @@ public:  template <typename T, typename V>  [[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { -    return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; +    using TV = decltype(V{} * T{}); +    using C = std::common_type_t<T, V>; + +    return { +        static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)), +        static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)), +        static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)), +        static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)), +    };  }  using Vec4f = Vec4<float>; diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index b009cb500..e3ca29258 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -13,7 +13,7 @@  namespace Common { -void* AllocateMemoryPages(std::size_t size) { +void* AllocateMemoryPages(std::size_t size) noexcept {  #ifdef _WIN32      void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)};  #else @@ -29,7 +29,7 @@ void* AllocateMemoryPages(std::size_t size) {      return base;  } -void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) { +void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {      if (!base) {          return;      } diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 125cb42f0..fb1a6f81f 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -4,29 +4,55 @@  #pragma once -#include "common/common_funcs.h" +#include <type_traits> +#include <utility>  namespace Common { -void* AllocateMemoryPages(std::size_t size); -void FreeMemoryPages(void* base, std::size_t size); +void* AllocateMemoryPages(std::size_t size) noexcept; +void FreeMemoryPages(void* base, std::size_t size) noexcept;  template <typename T> -class VirtualBuffer final : NonCopyable { +class VirtualBuffer final {  public: +    // TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible +    // using std::atomic_ref once libc++ has support for it +    // static_assert( +    //     std::is_trivially_constructible_v<T>, +    //     "T must be trivially constructible, as non-trivial constructors will not be executed " +    //     "with the current allocator"); +      constexpr VirtualBuffer() = default;      explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {          base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));      } -    ~VirtualBuffer() { +    ~VirtualBuffer() noexcept {          FreeMemoryPages(base_ptr, alloc_size);      } +    VirtualBuffer(const VirtualBuffer&) = delete; +    VirtualBuffer& operator=(const VirtualBuffer&) = delete; + +    VirtualBuffer(VirtualBuffer&& other) noexcept +        : alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), +                                                                   nullptr} {} + +    VirtualBuffer& operator=(VirtualBuffer&& other) noexcept { +        alloc_size = std::exchange(other.alloc_size, 0); +        base_ptr = std::exchange(other.base_ptr, nullptr); +        return *this; +    } +      void resize(std::size_t count) { +        const auto new_size = count * sizeof(T); +        if (new_size == alloc_size) { +            return; +        } +          FreeMemoryPages(base_ptr, alloc_size); -        alloc_size = count * sizeof(T); +        alloc_size = new_size;          base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));      } diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 3afbdb898..a8c143f85 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -15,10 +15,10 @@ namespace Common {  using base_timer = std::chrono::steady_clock;  using base_time_point = std::chrono::time_point<base_timer>; -class StandardWallClock : public WallClock { +class StandardWallClock final : public WallClock {  public: -    StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency) -        : WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) { +    explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) +        : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) {          start_time = base_timer::now();      } @@ -53,7 +53,7 @@ public:          return Common::Divide128On32(temporary, 1000000000).first;      } -    void Pause(bool is_paused) override { +    void Pause([[maybe_unused]] bool is_paused) override {          // Do nothing in this clock type.      } diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 5db30083d..cef3e9499 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -13,6 +13,8 @@ namespace Common {  class WallClock {  public: +    virtual ~WallClock() = default; +      /// Returns current wall time in nanoseconds      [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0; @@ -36,9 +38,9 @@ public:      }  protected: -    WallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, bool is_native) -        : emulated_cpu_frequency{emulated_cpu_frequency}, -          emulated_clock_frequency{emulated_clock_frequency}, is_native{is_native} {} +    explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_) +        : emulated_cpu_frequency{emulated_cpu_frequency_}, +          emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {}      u64 emulated_cpu_frequency;      u64 emulated_clock_frequency; diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 424b39b1f..eb8a7782f 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -43,10 +43,10 @@ u64 EstimateRDTSCFrequency() {  }  namespace X64 { -NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, -                         u64 rtsc_frequency) -    : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{ -                                                                             rtsc_frequency} { +NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, +                         u64 rtsc_frequency_) +    : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ +                                                                               rtsc_frequency_} {      _mm_mfence();      last_measure = __rdtsc();      accumulated_ticks = 0U; diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 891a3bbfd..6d1e32ac8 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h @@ -12,9 +12,10 @@  namespace Common {  namespace X64 { -class NativeClock : public WallClock { +class NativeClock final : public WallClock {  public: -    NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency); +    explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, +                         u64 rtsc_frequency_);      std::chrono::nanoseconds GetTimeNS() override; @@ -34,7 +35,7 @@ private:      /// value used to reduce the native clocks accuracy as some apss rely on      /// undefined behavior where the level of accuracy in the clock shouldn't      /// be higher. -    static constexpr u64 inaccuracy_mask = ~(0x400 - 1); +    static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1);      SpinLock rtsc_serialize{};      u64 last_measure{}; diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h index 26e4bfda5..c2c9b6134 100644 --- a/src/common/x64/xbyak_abi.h +++ b/src/common/x64/xbyak_abi.h @@ -11,25 +11,25 @@  namespace Common::X64 { -constexpr std::size_t RegToIndex(const Xbyak::Reg& reg) { +constexpr size_t RegToIndex(const Xbyak::Reg& reg) {      using Kind = Xbyak::Reg::Kind;      ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,                 "RegSet only support GPRs and XMM registers.");      ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15."); -    return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16); +    return static_cast<size_t>(reg.getIdx()) + (reg.getKind() == Kind::REG ? 0 : 16);  } -constexpr Xbyak::Reg64 IndexToReg64(std::size_t reg_index) { +constexpr Xbyak::Reg64 IndexToReg64(size_t reg_index) {      ASSERT(reg_index < 16);      return Xbyak::Reg64(static_cast<int>(reg_index));  } -constexpr Xbyak::Xmm IndexToXmm(std::size_t reg_index) { +constexpr Xbyak::Xmm IndexToXmm(size_t reg_index) {      ASSERT(reg_index >= 16 && reg_index < 32);      return Xbyak::Xmm(static_cast<int>(reg_index - 16));  } -constexpr Xbyak::Reg IndexToReg(std::size_t reg_index) { +constexpr Xbyak::Reg IndexToReg(size_t reg_index) {      if (reg_index < 16) {          return IndexToReg64(reg_index);      } else { @@ -182,7 +182,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b                                                size_t rsp_alignment, size_t needed_frame_size = 0) {      auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); -    for (std::size_t i = 0; i < regs.size(); ++i) { +    for (size_t i = 0; i < regs.size(); ++i) {          if (regs[i] && ABI_ALL_GPRS[i]) {              code.push(IndexToReg64(i));          } @@ -192,7 +192,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b          code.sub(code.rsp, frame_info.subtraction);      } -    for (std::size_t i = 0; i < regs.size(); ++i) { +    for (size_t i = 0; i < regs.size(); ++i) {          if (regs[i] && ABI_ALL_XMMS[i]) {              code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i));              frame_info.xmm_offset += 0x10; @@ -206,7 +206,7 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits                                             size_t rsp_alignment, size_t needed_frame_size = 0) {      auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); -    for (std::size_t i = 0; i < regs.size(); ++i) { +    for (size_t i = 0; i < regs.size(); ++i) {          if (regs[i] && ABI_ALL_XMMS[i]) {              code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]);              frame_info.xmm_offset += 0x10; @@ -218,8 +218,8 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits      }      // GPRs need to be popped in reverse order -    for (std::size_t j = 0; j < regs.size(); ++j) { -        const std::size_t i = regs.size() - j - 1; +    for (size_t j = 0; j < regs.size(); ++j) { +        const size_t i = regs.size() - j - 1;          if (regs[i] && ABI_ALL_GPRS[i]) {              code.pop(IndexToReg64(i));          } | 
