From e04590a06d0c6081f88b40477782b50187a39b87 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 6 Apr 2020 16:44:59 +0100 Subject: [PATCH 1/3] externals: Update dynarmic to b58048a --- externals/dynarmic | 2 +- src/core/arm/dynarmic/arm_dynarmic.cpp | 8 +++++ src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | 34 ++++++++++----------- src/core/arm/dynarmic/arm_dynarmic_cp15.h | 14 ++++----- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/externals/dynarmic b/externals/dynarmic index 4e6848d1c..b58048a5a 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit 4e6848d1c9e8dadc70595c15b5589f8b14aad478 +Subproject commit b58048a5a88ad6184d64f16cfd2c5d63a1952e77 diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index b39a4a24e..bb32f470c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -143,6 +143,14 @@ public: return; } break; + case Dynarmic::A32::Exception::SendEvent: + case Dynarmic::A32::Exception::SendEventLocal: + case Dynarmic::A32::Exception::WaitForInterrupt: + case Dynarmic::A32::Exception::WaitForEvent: + case Dynarmic::A32::Exception::Yield: + case Dynarmic::A32::Exception::PreloadData: + case Dynarmic::A32::Exception::PreloadDataWithIntentToWrite: + return; } ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast(exception), pc, MemoryReadCode(pc)); diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index 119aefac7..167f58e47 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp @@ -14,10 +14,10 @@ DynarmicCP15::DynarmicCP15(const std::shared_ptr& state) : interpre DynarmicCP15::~DynarmicCP15() = default; -boost::optional DynarmicCP15::CompileInternalOperation(bool two, unsigned opc1, - CoprocReg CRd, CoprocReg CRn, - CoprocReg CRm, unsigned opc2) { - return boost::none; +std::optional DynarmicCP15::CompileInternalOperation(bool two, unsigned opc1, + CoprocReg CRd, CoprocReg CRn, + CoprocReg CRm, unsigned opc2) { + return std::nullopt; } CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, @@ -38,7 +38,7 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 // This is a dummy write, we ignore the value written here. return &interpreter_state->CP15[CP15_DATA_MEMORY_BARRIER]; default: - return boost::blank{}; + return std::monostate{}; } } @@ -46,11 +46,11 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 return &interpreter_state->CP15[CP15_THREAD_UPRW]; } - return boost::blank{}; + return std::monostate{}; } CallbackOrAccessTwoWords DynarmicCP15::CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) { - return boost::blank{}; + return std::monostate{}; } CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, @@ -64,25 +64,23 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, case 3: return &interpreter_state->CP15[CP15_THREAD_URO]; default: - return boost::blank{}; + return std::monostate{}; } } - return boost::blank{}; + return std::monostate{}; } CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { - return boost::blank{}; + return std::monostate{}; } -boost::optional DynarmicCP15::CompileLoadWords(bool two, bool long_transfer, - CoprocReg CRd, - boost::optional option) { - return boost::none; +std::optional DynarmicCP15::CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) { + return std::nullopt; } -boost::optional DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, - CoprocReg CRd, - boost::optional option) { - return boost::none; +std::optional DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) { + return std::nullopt; } diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 66740ea71..923343864 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -17,19 +17,19 @@ public: explicit DynarmicCP15(const std::shared_ptr&); ~DynarmicCP15() override; - boost::optional CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, - CoprocReg CRn, CoprocReg CRm, - unsigned opc2) override; + std::optional CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, + CoprocReg CRn, CoprocReg CRm, + unsigned opc2) override; CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override; CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) override; CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override; CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) override; - boost::optional CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, - boost::optional option) override; - boost::optional CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, - boost::optional option) override; + std::optional CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) override; + std::optional CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) override; private: std::shared_ptr interpreter_state; From 8b7b6e9f74de6b8df1028caf367ded873fdde626 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 6 Apr 2020 17:31:12 +0100 Subject: [PATCH 2/3] arm_dynarmic: Remove dependence on interpreter --- src/citra_qt/debugger/registers.cpp | 11 --- src/core/arm/dynarmic/arm_dynarmic.cpp | 91 +++++++++++---------- src/core/arm/dynarmic/arm_dynarmic.h | 12 ++- src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | 14 ++-- src/core/arm/dynarmic/arm_dynarmic_cp15.h | 12 ++- src/core/core.cpp | 2 +- 6 files changed, 73 insertions(+), 69 deletions(-) diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index eb4d3d6dc..9c67073f3 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp @@ -103,8 +103,6 @@ void RegistersWidget::OnEmulationStopping() { vfp_system_registers->child(0)->setText(1, QString{}); vfp_system_registers->child(1)->setText(1, QString{}); - vfp_system_registers->child(2)->setText(1, QString{}); - vfp_system_registers->child(3)->setText(1, QString{}); setEnabled(false); } @@ -188,16 +186,12 @@ void RegistersWidget::CreateVFPSystemRegisterChildren() { vfp_system_registers->addChild(fpscr); vfp_system_registers->addChild(fpexc); - vfp_system_registers->addChild(new QTreeWidgetItem(QStringList(QStringLiteral("FPINST")))); - vfp_system_registers->addChild(new QTreeWidgetItem(QStringList(QStringLiteral("FPINST2")))); } void RegistersWidget::UpdateVFPSystemRegisterValues() { // Todo: handle all cores const u32 fpscr_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPSCR); const u32 fpexc_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPEXC); - const u32 fpinst_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPINST); - const u32 fpinst2_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPINST2); QTreeWidgetItem* const fpscr = vfp_system_registers->child(0); fpscr->setText(1, QStringLiteral("0x%1").arg(fpscr_val, 8, 16, QLatin1Char('0'))); @@ -237,9 +231,4 @@ void RegistersWidget::UpdateVFPSystemRegisterValues() { fpexc->child(5)->setText(1, QString::number((fpexc_val >> 28) & 1)); fpexc->child(6)->setText(1, QString::number((fpexc_val >> 30) & 1)); fpexc->child(7)->setText(1, QString::number((fpexc_val >> 31) & 1)); - - vfp_system_registers->child(2)->setText( - 1, QStringLiteral("0x%1").arg(fpinst_val, 8, 16, QLatin1Char('0'))); - vfp_system_registers->child(3)->setText( - 1, QStringLiteral("0x%1").arg(fpinst2_val, 8, 16, QLatin1Char('0'))); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index bb32f470c..55da53b14 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -9,7 +9,6 @@ #include "common/microprofile.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_cp15.h" -#include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/core.h" #include "core/core_timing.h" #include "core/gdbstub/gdbstub.h" @@ -102,24 +101,9 @@ public: } void InterpreterFallback(VAddr pc, std::size_t num_instructions) override { - parent.interpreter_state->Reg = parent.jit->Regs(); - parent.interpreter_state->Cpsr = parent.jit->Cpsr(); - parent.interpreter_state->Reg[15] = pc; - parent.interpreter_state->ExtReg = parent.jit->ExtRegs(); - parent.interpreter_state->VFP[VFP_FPSCR] = parent.jit->Fpscr(); - parent.interpreter_state->NumInstrsToExecute = num_instructions; - - InterpreterMainLoop(parent.interpreter_state.get()); - - bool is_thumb = (parent.interpreter_state->Cpsr & (1 << 5)) != 0; - parent.interpreter_state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC); - - parent.jit->Regs() = parent.interpreter_state->Reg; - parent.jit->SetCpsr(parent.interpreter_state->Cpsr); - parent.jit->ExtRegs() = parent.interpreter_state->ExtReg; - parent.jit->SetFpscr(parent.interpreter_state->VFP[VFP_FPSCR]); - - parent.interpreter_state->ServeBreak(); + // Should never happen. + UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}", + pc, MemoryReadCode(pc), num_instructions); } void CallSVC(std::uint32_t swi) override { @@ -135,11 +119,7 @@ public: if (GDBStub::IsConnected()) { parent.jit->HaltExecution(); parent.SetPC(pc); - Kernel::Thread* thread = - parent.system.Kernel().GetCurrentThreadManager().GetCurrentThread(); - parent.SaveContext(thread->context); - GDBStub::Break(); - GDBStub::SendTrap(thread, 5); + parent.ServeBreak(); return; } break; @@ -169,12 +149,10 @@ public: Memory::MemorySystem& memory; }; -ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, - PrivilegeMode initial_mode, u32 id, +ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id, std::shared_ptr timer) : ARM_Interface(id, timer), system(*system), memory(memory), cb(std::make_unique(*this)) { - interpreter_state = std::make_shared(system, memory, initial_mode); PageTableChanged(); } @@ -190,7 +168,11 @@ void ARM_Dynarmic::Run() { } void ARM_Dynarmic::Step() { - cb->InterpreterFallback(jit->Regs()[15], 1); + jit->Step(); + + if (GDBStub::IsConnected()) { + ServeBreak(); + } } void ARM_Dynarmic::SetPC(u32 pc) { @@ -218,21 +200,25 @@ void ARM_Dynarmic::SetVFPReg(int index, u32 value) { } u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const { - if (reg == VFP_FPSCR) { + switch (reg) { + case VFP_FPSCR: return jit->Fpscr(); + case VFP_FPEXC: + return fpexc; } - - // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state - return interpreter_state->VFP[reg]; + UNREACHABLE_MSG("Unknown VFP system register: {}", static_cast(reg)); } void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { - if (reg == VFP_FPSCR) { + switch (reg) { + case VFP_FPSCR: jit->SetFpscr(value); + return; + case VFP_FPEXC: + fpexc = value; + return; } - - // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state - interpreter_state->VFP[reg] = value; + UNREACHABLE_MSG("Unknown VFP system register: {}", static_cast(reg)); } u32 ARM_Dynarmic::GetCPSR() const { @@ -244,11 +230,25 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) { } u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) { - return interpreter_state->CP15[reg]; + switch (reg) { + case CP15_THREAD_UPRW: + return cp15_state.cp15_thread_uprw; + case CP15_THREAD_URO: + return cp15_state.cp15_thread_uro; + } + UNREACHABLE_MSG("Unknown CP15 register: {}", static_cast(reg)); } void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { - interpreter_state->CP15[reg] = value; + switch (reg) { + case CP15_THREAD_UPRW: + cp15_state.cp15_thread_uprw = value; + return; + case CP15_THREAD_URO: + cp15_state.cp15_thread_uro = value; + return; + } + UNREACHABLE_MSG("Unknown CP15 register: {}", static_cast(reg)); } std::unique_ptr ARM_Dynarmic::NewContext() const { @@ -260,7 +260,7 @@ void ARM_Dynarmic::SaveContext(const std::unique_ptr& arg) { ASSERT(ctx); jit->SaveContext(ctx->ctx); - ctx->fpexc = interpreter_state->VFP[VFP_FPEXC]; + ctx->fpexc = fpexc; } void ARM_Dynarmic::LoadContext(const std::unique_ptr& arg) { @@ -268,7 +268,7 @@ void ARM_Dynarmic::LoadContext(const std::unique_ptr& arg) { ASSERT(ctx); jit->LoadContext(ctx->ctx); - interpreter_state->VFP[VFP_FPEXC] = ctx->fpexc; + fpexc = ctx->fpexc; } void ARM_Dynarmic::PrepareReschedule() { @@ -278,11 +278,9 @@ void ARM_Dynarmic::PrepareReschedule() { } void ARM_Dynarmic::ClearInstructionCache() { - // TODO: Clear interpreter cache when appropriate. for (const auto& j : jits) { j.second->ClearCache(); } - interpreter_state->instruction_cache.clear(); } void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) { @@ -303,11 +301,18 @@ void ARM_Dynarmic::PageTableChanged() { jits.emplace(current_page_table, std::move(new_jit)); } +void ARM_Dynarmic::ServeBreak() { + Kernel::Thread* thread = system.Kernel().GetCurrentThreadManager().GetCurrentThread(); + SaveContext(thread->context); + GDBStub::Break(); + GDBStub::SendTrap(thread, 5); +} + std::unique_ptr ARM_Dynarmic::MakeJit() { Dynarmic::A32::UserConfig config; config.callbacks = cb.get(); config.page_table = ¤t_page_table->pointers; - config.coprocessors[15] = std::make_shared(interpreter_state); + config.coprocessors[15] = std::make_shared(cp15_state); config.define_unpredictable_behaviour = true; return std::make_unique(config); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 4aaec1bf1..c403f438e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -9,7 +9,7 @@ #include #include "common/common_types.h" #include "core/arm/arm_interface.h" -#include "core/arm/skyeye_common/armstate.h" +#include "core/arm/dynarmic/arm_dynarmic_cp15.h" namespace Memory { struct PageTable; @@ -24,8 +24,8 @@ class DynarmicUserCallbacks; class ARM_Dynarmic final : public ARM_Interface { public: - ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, PrivilegeMode initial_mode, - u32 id, std::shared_ptr timer); + ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id, + std::shared_ptr timer); ~ARM_Dynarmic() override; void Run() override; @@ -55,14 +55,18 @@ public: void PageTableChanged() override; private: + void ServeBreak(); + friend class DynarmicUserCallbacks; Core::System& system; Memory::MemorySystem& memory; std::unique_ptr cb; std::unique_ptr MakeJit(); + u32 fpexc = 0; + CP15State cp15_state; + Dynarmic::A32::Jit* jit = nullptr; Memory::PageTable* current_page_table = nullptr; std::map> jits; - std::shared_ptr interpreter_state; }; diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index 167f58e47..8f55fb54e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp @@ -10,7 +10,7 @@ using Callback = Dynarmic::A32::Coprocessor::Callback; using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; -DynarmicCP15::DynarmicCP15(const std::shared_ptr& state) : interpreter_state(state) {} +DynarmicCP15::DynarmicCP15(CP15State& state) : state(state) {} DynarmicCP15::~DynarmicCP15() = default; @@ -26,24 +26,24 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) { // This is a dummy write, we ignore the value written here. - return &interpreter_state->CP15[CP15_FLUSH_PREFETCH_BUFFER]; + return &state.cp15_flush_prefetch_buffer; } if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) { switch (opc2) { case 4: // This is a dummy write, we ignore the value written here. - return &interpreter_state->CP15[CP15_DATA_SYNC_BARRIER]; + return &state.cp15_data_sync_barrier; case 5: // This is a dummy write, we ignore the value written here. - return &interpreter_state->CP15[CP15_DATA_MEMORY_BARRIER]; + return &state.cp15_data_memory_barrier; default: return std::monostate{}; } } if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) { - return &interpreter_state->CP15[CP15_THREAD_UPRW]; + return &state.cp15_thread_uprw; } return std::monostate{}; @@ -60,9 +60,9 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) { switch (opc2) { case 2: - return &interpreter_state->CP15[CP15_THREAD_UPRW]; + return &state.cp15_thread_uprw; case 3: - return &interpreter_state->CP15[CP15_THREAD_URO]; + return &state.cp15_thread_uro; default: return std::monostate{}; } diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 923343864..30ab08ac8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -8,13 +8,19 @@ #include #include "common/common_types.h" -struct ARMul_State; +struct CP15State { + u32 cp15_thread_uprw = 0; + u32 cp15_thread_uro = 0; + u32 cp15_flush_prefetch_buffer = 0; ///< dummy value + u32 cp15_data_sync_barrier = 0; ///< dummy value + u32 cp15_data_memory_barrier = 0; ///< dummy value +}; class DynarmicCP15 final : public Dynarmic::A32::Coprocessor { public: using CoprocReg = Dynarmic::A32::CoprocReg; - explicit DynarmicCP15(const std::shared_ptr&); + explicit DynarmicCP15(CP15State&); ~DynarmicCP15() override; std::optional CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, @@ -32,5 +38,5 @@ public: std::optional option) override; private: - std::shared_ptr interpreter_state; + CP15State& state; }; diff --git a/src/core/core.cpp b/src/core/core.cpp index c1d635afe..bd9e93493 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -267,7 +267,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo #ifdef ARCHITECTURE_x86_64 for (std::size_t i = 0; i < num_cores; ++i) { cpu_cores.push_back( - std::make_shared(this, *memory, USER32MODE, i, timing->GetTimer(i))); + std::make_shared(this, *memory, i, timing->GetTimer(i))); } #else for (std::size_t i = 0; i < num_cores; ++i) { From f2499953c0d3b3c4ae4632d1c6b8785ea5b9b22f Mon Sep 17 00:00:00 2001 From: MerryMage Date: Tue, 7 Apr 2020 20:49:46 +0100 Subject: [PATCH 3/3] travis: Update xcode Update to 10.2 (required for CTAD to work correctly) --- .travis.yml | 2 +- src/common/ring_buffer.h | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index ba721464f..f1ddde4de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ matrix: - os: osx env: NAME="macos build" sudo: false - osx_image: xcode10 + osx_image: xcode10.2 install: "./.travis/macos/deps.sh" script: "./.travis/macos/build.sh" after_success: "./.travis/macos/upload.sh" diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 428d3095f..bb94b898b 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "common/common_types.h" @@ -29,7 +30,7 @@ class RingBuffer { static_assert(capacity < std::numeric_limits::max() / 2 / granularity); static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two"); // Ensure lock-free. - static_assert(std::atomic::is_always_lock_free); + static_assert(std::atomic_size_t::is_always_lock_free); public: /// Pushes slots into the ring buffer @@ -100,10 +101,22 @@ public: } private: - // It is important to align the below variables for performance reasons: + // It is important to separate the below atomics for performance reasons: // Having them on the same cache-line would result in false-sharing between them. - alignas(128) std::atomic m_read_index{0}; - alignas(128) std::atomic m_write_index{0}; + // TODO: Remove this ifdef whenever clang and GCC support + // std::hardware_destructive_interference_size. +#if defined(_MSC_VER) && _MSC_VER >= 1911 + static constexpr std::size_t padding_size = + std::hardware_destructive_interference_size - sizeof(std::atomic_size_t); +#else + static constexpr std::size_t padding_size = 128 - sizeof(std::atomic_size_t); +#endif + + std::atomic_size_t m_read_index{0}; + char padding1[padding_size]; + + std::atomic_size_t m_write_index{0}; + char padding2[padding_size]; std::array m_data; };