Compare commits

..

2 Commits

Author SHA1 Message Date
lizzie fdb415fbdd fix span shit 2026-07-21 11:29:26 +02:00
lizzie b8c6085e5a [audio_core] remove dangling Core::System& references
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-07-21 11:29:26 +02:00
34 changed files with 373 additions and 464 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
namespace AudioCore {
AudioCore::AudioCore(Core::System& system) {
audio_manager.emplace();
audio_manager.emplace(system);
CreateSinks();
// Must be created after the sinks
adsp.emplace(system, *output_sink);
+12 -15
View File
@@ -15,12 +15,12 @@
namespace AudioCore::AudioIn {
Manager::Manager(Core::System& system_) : system{system_} {
Manager::Manager(Core::System& system) {
std::iota(session_ids.begin(), session_ids.end(), 0);
num_free_sessions = MaxInSessions;
}
Result Manager::AcquireSessionId(size_t& session_id) {
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
if (num_free_sessions == 0) {
LOG_ERROR(Service_Audio, "All 4 AudioIn sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions;
@@ -31,7 +31,7 @@ Result Manager::AcquireSessionId(size_t& session_id) {
return ResultSuccess;
}
void Manager::ReleaseSessionId(const size_t session_id) {
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
std::scoped_lock l{mutex};
LOG_DEBUG(Service_Audio, "Freeing AudioIn session {}", session_id);
session_ids[free_session_id] = session_id;
@@ -41,21 +41,20 @@ void Manager::ReleaseSessionId(const size_t session_id) {
applet_resource_user_ids[session_id] = 0;
}
Result Manager::LinkToManager() {
Result Manager::LinkToManager(Core::System& system) {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
system.AudioCore().GetAudioManager().SetInManager(&Manager::BufferReleaseAndRegister);
linked_to_manager = true;
}
return ResultSuccess;
}
void Manager::Start() {
void Manager::Start(Core::System& system) {
if (sessions_started) {
return;
}
std::scoped_lock l{mutex};
for (auto& session : sessions) {
if (session) {
@@ -66,21 +65,19 @@ void Manager::Start() {
sessions_started = true;
}
void Manager::BufferReleaseAndRegister() {
std::scoped_lock l{mutex};
for (auto& session : sessions) {
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept {
Manager* this_ = (Manager*)data;
std::scoped_lock l{this_->mutex};
for (auto& session : this_->sessions) {
if (session != nullptr) {
session->ReleaseAndRegisterBuffers();
}
}
}
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const bool filter) {
u32 Manager::GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, [[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex};
LinkToManager();
LinkToManager(system);
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (!input_devices.empty() && !names.empty()) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
+10 -11
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,31 +33,29 @@ public:
* @param session_id - Output session_id.
* @return Result code.
*/
Result AcquireSessionId(size_t& session_id);
Result AcquireSessionId(Core::System& system, size_t& session_id);
/**
* Release a session id on close.
*
* @param session_id - Session id to free.
*/
void ReleaseSessionId(size_t session_id);
void ReleaseSessionId(Core::System& system, const size_t session_id);
/**
* Link the audio in manager to the main audio manager.
*
* @return Result code.
*/
Result LinkToManager();
Result LinkToManager(Core::System& system);
/**
* Start the audio in manager.
*/
void Start();
void Start(Core::System& system);
/**
* Callback function, called by the audio manager when the audio in event is signalled.
*/
void BufferReleaseAndRegister();
/// @brief Callback function, called by the audio manager when the audio in event is signalled.
static void BufferReleaseAndRegister(void *data, Core::System& system) noexcept;
/**
* Get a list of audio in device names.
@@ -64,10 +65,8 @@ public:
*
* @return Number of names written.
*/
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
u32 GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
/// Core system
Core::System& system;
/// Array of session ids
std::array<size_t, MaxInSessions> session_ids{};
/// Array of resource user ids
+3 -3
View File
@@ -11,8 +11,8 @@
namespace AudioCore {
AudioManager::AudioManager() {
thread = std::jthread([this](std::stop_token stop_token) {
AudioManager::AudioManager(Core::System& system) {
thread = std::jthread([&](std::stop_token stop_token) {
Common::SetCurrentThreadName("AudioManager");
std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents();
@@ -25,7 +25,7 @@ AudioManager::AudioManager() {
const auto event_type = Event::Type(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i]();
buffer_events[i](this, system);
}
}
events.SetAudioEvent(event_type, false);
+6 -3
View File
@@ -16,6 +16,10 @@
#include "audio_core/audio_event.h"
namespace Core {
class System;
}
union Result;
namespace AudioCore {
@@ -34,10 +38,9 @@ namespace AudioCore {
* This is only used by audio in and audio out.
*/
class AudioManager {
using BufferEventFunc = std::function<void()>;
using BufferEventFunc = void (*)(void *data, Core::System& system) noexcept;
public:
explicit AudioManager();
explicit AudioManager(Core::System& system);
/**
* Shutdown the audio manager.
+10 -15
View File
@@ -14,12 +14,12 @@
namespace AudioCore::AudioOut {
Manager::Manager(Core::System& system_) : system{system_} {
Manager::Manager(Core::System& system) {
std::iota(session_ids.begin(), session_ids.end(), 0);
num_free_sessions = MaxOutSessions;
}
Result Manager::AcquireSessionId(size_t& session_id) {
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
if (num_free_sessions == 0) {
LOG_ERROR(Service_Audio, "All 12 Audio Out sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions;
@@ -30,7 +30,7 @@ Result Manager::AcquireSessionId(size_t& session_id) {
return ResultSuccess;
}
void Manager::ReleaseSessionId(const size_t session_id) {
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
std::scoped_lock l{mutex};
LOG_DEBUG(Service_Audio, "Freeing AudioOut session {}", session_id);
session_ids[free_session_id] = session_id;
@@ -40,17 +40,17 @@ void Manager::ReleaseSessionId(const size_t session_id) {
applet_resource_user_ids[session_id] = 0;
}
Result Manager::LinkToManager() {
Result Manager::LinkToManager(Core::System& system) {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
system.AudioCore().GetAudioManager().SetOutManager(&Manager::BufferReleaseAndRegister);
linked_to_manager = true;
}
return ResultSuccess;
}
void Manager::Start() {
void Manager::Start(Core::System& system) {
if (sessions_started) {
return;
}
@@ -65,19 +65,14 @@ void Manager::Start() {
sessions_started = true;
}
void Manager::BufferReleaseAndRegister() {
std::scoped_lock l{mutex};
for (auto& session : sessions) {
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept {
Manager* this_ = (Manager*)data;
std::scoped_lock l{this_->mutex};
for (auto& session : this_->sessions) {
if (session != nullptr) {
session->ReleaseAndRegisterBuffers();
}
}
}
u32 Manager::GetAudioOutDeviceNames(
std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const {
names.emplace_back("DeviceOut");
return 1;
}
} // namespace AudioCore::AudioOut
+8 -15
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -29,42 +32,32 @@ public:
* @param session_id - Output session_id.
* @return Result code.
*/
Result AcquireSessionId(size_t& session_id);
Result AcquireSessionId(Core::System& system, size_t& session_id);
/**
* Release a session id on close.
*
* @param session_id - Session id to free.
*/
void ReleaseSessionId(size_t session_id);
void ReleaseSessionId(Core::System& system, const size_t session_id);
/**
* Link this manager to the main audio manager.
*
* @return Result code.
*/
Result LinkToManager();
Result LinkToManager(Core::System& system);
/**
* Start the audio out manager.
*/
void Start();
void Start(Core::System& system);
/**
* Callback function, called by the audio manager when the audio out event is signalled.
*/
void BufferReleaseAndRegister();
static void BufferReleaseAndRegister(void* data, Core::System& system) noexcept;
/**
* Get a list of audio out device names.
*
* @param names - Output container to write names to.
* @return Number of names written.
*/
u32 GetAudioOutDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const;
/// Core system
Core::System& system;
/// Array of session ids
std::array<size_t, MaxOutSessions> session_ids{};
/// Array of resource user ids
+8 -3
View File
@@ -1,15 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/audio_render_manager.h"
#include "audio_core/common/audio_renderer_parameter.h"
#include "audio_core/renderer/system_manager.h"
#include "audio_core/common/feature_support.h"
#include "core/core.h"
namespace AudioCore::Renderer {
Manager::Manager(Core::System& system_)
: system{system_}, system_manager{std::make_unique<SystemManager>(system)} {
: system_manager{std::make_unique<SystemManager>(system_)}
{
std::iota(session_ids.begin(), session_ids.end(), 0);
}
@@ -59,11 +64,11 @@ u32 Manager::GetSessionCount() const {
return session_count;
}
bool Manager::AddSystem(System& system_) {
bool Manager::AddSystem(Renderer::System& system_) {
return system_manager->Add(system_);
}
bool Manager::RemoveSystem(System& system_) {
bool Manager::RemoveSystem(Renderer::System& system_) {
return system_manager->Remove(system_);
}
+5 -4
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -71,7 +74,7 @@ public:
* @param system - The system to add.
* @return True if the system was successfully added, otherwise false.
*/
bool AddSystem(System& system);
bool AddSystem(Renderer::System& system);
/**
* Remove a renderer system from the manager.
@@ -79,7 +82,7 @@ public:
* @param system - The system to remove.
* @return True if the system was successfully removed, otherwise false.
*/
bool RemoveSystem(System& system);
bool RemoveSystem(Renderer::System& system);
/**
* Free a session id when the system wants to shut down.
@@ -89,8 +92,6 @@ public:
void ReleaseSessionId(s32 session_id);
private:
/// Core system
Core::System& system;
/// Session ids, -1 when in use
std::array<s32, MaxRendererSessions> session_ids{};
/// Number of active renderers
+18 -22
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,8 +19,9 @@ namespace AudioCore {
*/
class WorkbufferAllocator {
public:
explicit WorkbufferAllocator(std::span<u8> buffer_, u64 size_)
: buffer{reinterpret_cast<u64>(buffer_.data())}, size{size_} {}
explicit WorkbufferAllocator(std::span<u8> buffer_)
: buffer{buffer_}
{}
/**
* Allocate the given count of T elements, aligned to alignment.
@@ -29,36 +33,31 @@ public:
template <typename T>
std::span<T> Allocate(u64 count, u64 alignment) {
u64 out{0};
u64 byte_size{count * sizeof(T)};
u64 byte_size = count * sizeof(T);
if (byte_size > 0) {
auto current{buffer + offset};
auto current{uintptr_t(buffer.data()) + offset};
auto aligned_buffer{Common::AlignUp(current, alignment)};
if (aligned_buffer + byte_size <= buffer + size) {
if (aligned_buffer + byte_size <= uintptr_t(buffer.data()) + buffer.size()) {
out = aligned_buffer;
offset = byte_size - buffer + aligned_buffer;
offset = byte_size - uintptr_t(buffer.data()) + aligned_buffer;
} else {
LOG_ERROR(
Service_Audio,
"Allocated buffer was too small to hold new alloc.\nAllocator size={:08X}, "
"offset={:08X}.\nAttempting to allocate {:08X} with alignment={:02X}",
size, offset, byte_size, alignment);
buffer.size(), offset, byte_size, alignment);
count = 0;
}
}
return std::span<T>(reinterpret_cast<T*>(out), count);
}
/**
* Align the current offset to the given alignment.
*
* @param alignment - The required starting alignment.
*/
/// @brief Align the current offset to the given alignment.
/// @param alignment - The required starting alignment.
void Align(u64 alignment) {
auto current{buffer + offset};
auto current{uintptr_t(buffer.data()) + offset};
auto aligned_buffer{Common::AlignUp(current, alignment)};
offset = 0 - buffer + aligned_buffer;
offset = 0 - uintptr_t(buffer.data()) + aligned_buffer;
}
/**
@@ -76,7 +75,7 @@ public:
* @return The size of the current buffer.
*/
u64 GetSize() const {
return size;
return buffer.size();
}
/**
@@ -85,14 +84,11 @@ public:
* @return The remaining size left in the buffer.
*/
u64 GetRemainingSize() const {
return size - offset;
return buffer.size() - offset;
}
private:
/// The buffer into which we are allocating.
u64 buffer;
/// Size of the buffer we're allocating to.
u64 size;
const std::span<u8> buffer;
/// Current offset into the buffer, an error will be thrown if it exceeds size.
u64 offset{};
};
+24 -20
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -8,42 +11,43 @@
namespace AudioCore::AudioIn {
In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
session_id_} {}
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}
, audio_system{system_, event, session_id_}
{}
void In::Free() {
void In::Free(Core::System& system) {
std::scoped_lock l{parent_mutex};
manager.ReleaseSessionId(system.GetSessionId());
manager.ReleaseSessionId(system, audio_system.GetSessionId());
}
System& In::GetSystem() {
return system;
return audio_system;
}
AudioIn::State In::GetState() {
std::scoped_lock l{parent_mutex};
return system.GetState();
return audio_system.GetState();
}
Result In::StartSystem() {
std::scoped_lock l{parent_mutex};
return system.Start();
return audio_system.Start();
}
void In::StartSession() {
std::scoped_lock l{parent_mutex};
system.StartSession();
audio_system.StartSession();
}
Result In::StopSystem() {
std::scoped_lock l{parent_mutex};
return system.Stop();
return audio_system.Stop();
}
Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
std::scoped_lock l{parent_mutex};
if (system.AppendBuffer(buffer, tag)) {
if (audio_system.AppendBuffer(buffer, tag)) {
return ResultSuccess;
}
return Service::Audio::ResultBufferCountReached;
@@ -51,20 +55,20 @@ Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
void In::ReleaseAndRegisterBuffers() {
std::scoped_lock l{parent_mutex};
if (system.GetState() == State::Started) {
system.ReleaseBuffers();
system.RegisterBuffers();
if (audio_system.GetState() == State::Started) {
audio_system.ReleaseBuffers();
audio_system.RegisterBuffers();
}
}
bool In::FlushAudioInBuffers() {
std::scoped_lock l{parent_mutex};
return system.FlushAudioInBuffers();
return audio_system.FlushAudioInBuffers();
}
u32 In::GetReleasedBuffers(std::span<u64> tags) {
std::scoped_lock l{parent_mutex};
return system.GetReleasedBuffers(tags);
return audio_system.GetReleasedBuffers(tags);
}
Kernel::KReadableEvent& In::GetBufferEvent() {
@@ -74,27 +78,27 @@ Kernel::KReadableEvent& In::GetBufferEvent() {
f32 In::GetVolume() const {
std::scoped_lock l{parent_mutex};
return system.GetVolume();
return audio_system.GetVolume();
}
void In::SetVolume(f32 volume) {
std::scoped_lock l{parent_mutex};
system.SetVolume(volume);
audio_system.SetVolume(volume);
}
bool In::ContainsAudioBuffer(u64 tag) const {
std::scoped_lock l{parent_mutex};
return system.ContainsAudioBuffer(tag);
return audio_system.ContainsAudioBuffer(tag);
}
u32 In::GetBufferCount() const {
std::scoped_lock l{parent_mutex};
return system.GetBufferCount();
return audio_system.GetBufferCount();
}
u64 In::GetPlayedSampleCount() const {
std::scoped_lock l{parent_mutex};
return system.GetPlayedSampleCount();
return audio_system.GetPlayedSampleCount();
}
} // namespace AudioCore::AudioIn
+5 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,7 +33,7 @@ public:
/**
* Free this audio in from the audio in manager.
*/
void Free();
void Free(Core::System& system);
/**
* Get this audio in's system.
@@ -141,7 +144,7 @@ private:
/// Buffer event, signalled when buffers are ready to be released
Kernel::KEvent* event;
/// Main audio in system
System system;
System audio_system;
};
} // namespace AudioCore::AudioIn
+24 -20
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -8,42 +11,43 @@
namespace AudioCore::AudioOut {
Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
session_id_} {}
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}
, audio_system{system_, event, session_id_}
{}
void Out::Free() {
void Out::Free(Core::System& system) {
std::scoped_lock l{parent_mutex};
manager.ReleaseSessionId(system.GetSessionId());
manager.ReleaseSessionId(system, audio_system.GetSessionId());
}
System& Out::GetSystem() {
return system;
return audio_system;
}
AudioOut::State Out::GetState() {
std::scoped_lock l{parent_mutex};
return system.GetState();
return audio_system.GetState();
}
Result Out::StartSystem() {
std::scoped_lock l{parent_mutex};
return system.Start();
return audio_system.Start();
}
void Out::StartSession() {
std::scoped_lock l{parent_mutex};
system.StartSession();
audio_system.StartSession();
}
Result Out::StopSystem() {
std::scoped_lock l{parent_mutex};
return system.Stop();
return audio_system.Stop();
}
Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
std::scoped_lock l{parent_mutex};
if (system.AppendBuffer(buffer, tag)) {
if (audio_system.AppendBuffer(buffer, tag)) {
return ResultSuccess;
}
return Service::Audio::ResultBufferCountReached;
@@ -51,20 +55,20 @@ Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
void Out::ReleaseAndRegisterBuffers() {
std::scoped_lock l{parent_mutex};
if (system.GetState() == State::Started) {
system.ReleaseBuffers();
system.RegisterBuffers();
if (audio_system.GetState() == State::Started) {
audio_system.ReleaseBuffers();
audio_system.RegisterBuffers();
}
}
bool Out::FlushAudioOutBuffers() {
std::scoped_lock l{parent_mutex};
return system.FlushAudioOutBuffers();
return audio_system.FlushAudioOutBuffers();
}
u32 Out::GetReleasedBuffers(std::span<u64> tags) {
std::scoped_lock l{parent_mutex};
return system.GetReleasedBuffers(tags);
return audio_system.GetReleasedBuffers(tags);
}
Kernel::KReadableEvent& Out::GetBufferEvent() {
@@ -74,27 +78,27 @@ Kernel::KReadableEvent& Out::GetBufferEvent() {
f32 Out::GetVolume() const {
std::scoped_lock l{parent_mutex};
return system.GetVolume();
return audio_system.GetVolume();
}
void Out::SetVolume(const f32 volume) {
std::scoped_lock l{parent_mutex};
system.SetVolume(volume);
audio_system.SetVolume(volume);
}
bool Out::ContainsAudioBuffer(const u64 tag) const {
std::scoped_lock l{parent_mutex};
return system.ContainsAudioBuffer(tag);
return audio_system.ContainsAudioBuffer(tag);
}
u32 Out::GetBufferCount() const {
std::scoped_lock l{parent_mutex};
return system.GetBufferCount();
return audio_system.GetBufferCount();
}
u64 Out::GetPlayedSampleCount() const {
std::scoped_lock l{parent_mutex};
return system.GetPlayedSampleCount();
return audio_system.GetPlayedSampleCount();
}
} // namespace AudioCore::AudioOut
+5 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,7 +33,7 @@ public:
/**
* Free this audio out from the audio out manager.
*/
void Free();
void Free(Core::System& system);
/**
* Get this audio out's system.
@@ -141,7 +144,7 @@ private:
/// Buffer event, signalled when buffers are ready to be released
Kernel::KEvent* event;
/// Main audio out system
System system;
System audio_system;
};
} // namespace AudioCore::AudioOut
+18 -23
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -13,56 +16,48 @@
namespace AudioCore::Renderer {
Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* rendered_event)
: core{system_}, manager{manager_}, system{system_, rendered_event} {}
: system{system_}, manager{manager_}
, audio_system{system_, rendered_event}
{}
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory,
const u64 transfer_memory_size, Kernel::KProcess* process_handle,
const u64 applet_resource_user_id, const s32 session_id) {
Result Renderer::Initialize(const AudioRendererParameterInternal& params, Kernel::KTransferMemory* transfer_memory, const u64 transfer_memory_size, Kernel::KProcess* process_handle, const u64 applet_resource_user_id, const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio,
"Both Audio Render sessions are in use, cannot create any more");
if (!manager.AddSystem(audio_system)) {
LOG_ERROR(Service_Audio, "Both Audio Render sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions;
}
system_registered = true;
}
initialized = true;
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id);
audio_system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, applet_resource_user_id, session_id);
return ResultSuccess;
}
void Renderer::Finalize() {
auto session_id{system.GetSessionId()};
system.Finalize();
auto const session_id{audio_system.GetSessionId()};
audio_system.Finalize();
if (system_registered) {
manager.RemoveSystem(system);
manager.RemoveSystem(audio_system);
system_registered = false;
}
manager.ReleaseSessionId(session_id);
}
System& Renderer::GetSystem() {
return system;
return audio_system;
}
void Renderer::Start() {
system.Start();
audio_system.Start();
}
void Renderer::Stop() {
system.Stop();
audio_system.Stop();
}
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance,
std::span<u8> output) {
return system.Update(input, performance, output);
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance, std::span<u8> output) {
return audio_system.Update(input, performance, output);
}
} // namespace AudioCore::Renderer
+5 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -84,7 +87,7 @@ public:
private:
/// System core
Core::System& core;
Core::System& system;
/// Manager this renderer is registered with
Manager& manager;
/// Is the audio renderer initialized?
@@ -92,7 +95,7 @@ private:
/// Is the system registered with the manager?
bool system_registered{};
/// Audio render system, main driver of audio rendering
System system;
System audio_system;
};
} // namespace Renderer
+1 -1
View File
@@ -145,7 +145,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
PoolMapper pool_mapper(process_handle, false);
pool_mapper.InitializeSystemPool(memory_pool_info, workbuffer.get(), workbuffer_size);
WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size}, workbuffer_size);
WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size});
samples_workbuffer =
allocator.Allocate<s32>((voice_channels + mix_buffer_count) * sample_count, 0x10);
+1 -1
View File
@@ -50,7 +50,7 @@ IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
}
IAudioIn::~IAudioIn() {
impl->Free();
impl->Free(system);
service_context.CloseEvent(event);
process->Close(system.Kernel());
}
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -65,7 +68,7 @@ Result IAudioInManager::OpenAudioInAuto(
Result IAudioInManager::ListAudioInsAutoFiltered(
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
LOG_DEBUG(Service_Audio, "called");
*out_count = impl->GetDeviceNames(out_audio_ins, true);
*out_count = impl->GetDeviceNames(system, out_audio_ins, true);
R_SUCCEED();
}
@@ -90,8 +93,8 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
size_t new_session_id{};
R_TRY(impl->LinkToManager());
R_TRY(impl->AcquireSessionId(new_session_id));
R_TRY(impl->LinkToManager(system));
R_TRY(impl->AcquireSessionId(system, new_session_id));
LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
impl->num_free_sessions);
+1 -1
View File
@@ -46,7 +46,7 @@ IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
}
IAudioOut::~IAudioOut() {
impl->Free();
impl->Free(system);
service_context.CloseEvent(event);
process->Close(system.Kernel());
}
@@ -77,8 +77,8 @@ Result IAudioOutManager::OpenAudioOutAuto(
}
size_t new_session_id{};
R_TRY(impl->LinkToManager());
R_TRY(impl->AcquireSessionId(new_session_id));
R_TRY(impl->LinkToManager(system));
R_TRY(impl->AcquireSessionId(system, new_session_id));
const auto device_name = Common::StringFromBuffer(name[0].name);
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
@@ -34,8 +34,7 @@ oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
return pass;
}
void EmitA32LeafTerminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
@@ -126,53 +125,31 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Fa
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
oaknut::Label pass = EmitA32Cond(code, ctx, terminal.if_);
EmitA32LeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
EmitA32Terminal(code, ctx, terminal.else_, initial_location, is_single_step);
code.l(pass);
EmitA32LeafTerminal(code, ctx, terminal.then_, initial_location, is_single_step);
EmitA32Terminal(code, ctx, terminal.then_, initial_location, is_single_step);
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
oaknut::Label fail;
code.LDRB(Wscratch0, SP, offsetof(StackLayout, check_bit));
code.CBZ(Wscratch0, fail);
EmitA32LeafTerminal(code, ctx, terminal.then_, initial_location, is_single_step);
EmitA32Terminal(code, ctx, terminal.then_, initial_location, is_single_step);
code.l(fail);
EmitA32LeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
EmitA32Terminal(code, ctx, terminal.else_, initial_location, is_single_step);
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
oaknut::Label fail;
code.LDAR(Wscratch0, Xhalt);
code.CBNZ(Wscratch0, fail);
EmitA32LeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
EmitA32Terminal(code, ctx, terminal.else_, initial_location, is_single_step);
code.l(fail);
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
}
void EmitA32LeafTerminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
UNREACHABLE();
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal))
return EmitA32LeafTerminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::If>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
return EmitA32Terminal(code, ctx, *x, initial_location, is_single_step);
UNREACHABLE();
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
boost::apply_visitor([&](const auto& t) { EmitA32Terminal(code, ctx, t, initial_location, is_single_step); }, terminal);
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
@@ -33,8 +33,7 @@ oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
return pass;
}
void EmitA64LeafTerminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
@@ -109,53 +108,31 @@ void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Fa
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
oaknut::Label pass = EmitA64Cond(code, ctx, terminal.if_);
EmitA64LeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
EmitA64Terminal(code, ctx, terminal.else_, initial_location, is_single_step);
code.l(pass);
EmitA64LeafTerminal(code, ctx, terminal.then_, initial_location, is_single_step);
EmitA64Terminal(code, ctx, terminal.then_, initial_location, is_single_step);
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
oaknut::Label fail;
code.LDRB(Wscratch0, SP, offsetof(StackLayout, check_bit));
code.CBZ(Wscratch0, fail);
EmitA64LeafTerminal(code, ctx, terminal.then_, initial_location, is_single_step);
EmitA64Terminal(code, ctx, terminal.then_, initial_location, is_single_step);
code.l(fail);
EmitA64LeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
EmitA64Terminal(code, ctx, terminal.else_, initial_location, is_single_step);
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
oaknut::Label fail;
code.LDAR(Wscratch0, Xhalt);
code.CBNZ(Wscratch0, fail);
EmitA64LeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
EmitA64Terminal(code, ctx, terminal.else_, initial_location, is_single_step);
code.l(fail);
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
}
void EmitA64LeafTerminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
UNREACHABLE();
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal))
return EmitA64LeafTerminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::If>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
return EmitA64Terminal(code, ctx, *x, initial_location, is_single_step);
UNREACHABLE();
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
boost::apply_visitor([&](const auto& t) { EmitA64Terminal(code, ctx, t, initial_location, is_single_step); }, terminal);
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
@@ -112,7 +112,6 @@ void EmitA32Cond(biscuit::Assembler& as, EmitContext&, IR::Cond cond, biscuit::L
}
}
void EmitA32LeafTerminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::LeafTerminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
@@ -171,18 +170,18 @@ void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::FastDis
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
biscuit::Label pass;
EmitA32Cond(as, ctx, terminal.if_, &pass);
EmitA32LeafTerminal(as, ctx, terminal.else_, initial_location, is_single_step);
EmitA32Terminal(as, ctx, terminal.else_, initial_location, is_single_step);
as.Bind(&pass);
EmitA32LeafTerminal(as, ctx, terminal.then_, initial_location, is_single_step);
EmitA32Terminal(as, ctx, terminal.then_, initial_location, is_single_step);
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
biscuit::Label fail;
as.LBU(Xscratch0, offsetof(StackLayout, check_bit), Xstate);
as.BEQZ(Xscratch0, &fail);
EmitA32LeafTerminal(as, ctx, terminal.then_, initial_location, is_single_step);
EmitA32Terminal(as, ctx, terminal.then_, initial_location, is_single_step);
as.Bind(&fail);
EmitA32LeafTerminal(as, ctx, terminal.else_, initial_location, is_single_step);
EmitA32Terminal(as, ctx, terminal.else_, initial_location, is_single_step);
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
@@ -190,35 +189,13 @@ void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::CheckHa
as.LWU(Xscratch0, 0, Xhalt);
as.FENCE(biscuit::FenceOrder::RW, biscuit::FenceOrder::RW);
as.BNEZ(Xscratch0, &fail);
EmitA32LeafTerminal(as, ctx, terminal.else_, initial_location, is_single_step);
EmitA32Terminal(as, ctx, terminal.else_, initial_location, is_single_step);
as.Bind(&fail);
EmitRelocation(as, ctx, LinkTarget::ReturnFromRunCode);
}
void EmitA32LeafTerminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::LeafTerminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step);
UNREACHABLE();
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal))
return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::If>(&terminal))
return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step);
UNREACHABLE();
boost::apply_visitor([&](const auto& t) { EmitA32Terminal(as, ctx, t, initial_location, is_single_step); }, terminal);
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx) {
@@ -175,7 +175,7 @@ finish_this_inst:
if (conf.enable_cycle_counting)
EmitAddCycles(block.CycleCount());
code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]);
EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.int3();
for (auto& deferred_emit : ctx.deferred_emits)
@@ -219,7 +219,7 @@ void A32EmitX64::EmitCondPrelude(const A32EmitContext& ctx) {
if (conf.enable_cycle_counting) {
EmitAddCycles(ctx.block.ConditionFailedCycleCount());
}
EmitLeafTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.L(pass);
}
@@ -1155,12 +1155,11 @@ void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat
}
namespace {
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
e.code.ReturnFromRunCode();
return true;
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
e.EmitSetUpperLocationDescriptor(terminal.next, initial_location);
if (!e.conf.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) {
e.code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC());
@@ -1187,10 +1186,9 @@ bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
e.PushRSBHelper(rax, rbx, terminal.next);
e.code.ForceReturnFromRunCode();
}
return true;
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
e.EmitSetUpperLocationDescriptor(terminal.next, initial_location);
if (!e.conf.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) {
e.code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC());
@@ -1203,78 +1201,55 @@ bool EmitTerminalImpl(A32EmitX64& e, IR::Term::LinkBlockFast terminal, IR::Locat
e.EmitPatchJmp(terminal.next);
}
}
return true;
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) {
if (!e.conf.HasOptimization(OptimizationFlag::ReturnStackBuffer) || is_single_step) {
e.code.ReturnFromRunCode();
} else {
e.code.jmp(e.terminal_handler_pop_rsb_hint);
}
return true;
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) {
if (!e.conf.HasOptimization(OptimizationFlag::FastDispatch) || is_single_step) {
e.code.ReturnFromRunCode();
} else {
e.code.jmp(e.terminal_handler_fast_dispatch_hint);
}
return true;
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
Xbyak::Label pass = e.EmitCond(terminal.if_);
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step);
e.EmitTerminal(terminal.else_, initial_location, is_single_step);
e.code.L(pass);
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step);
return true;
e.EmitTerminal(terminal.then_, initial_location, is_single_step);
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
Xbyak::Label fail;
e.code.cmp(e.code.byte[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, check_bit)], u8(0));
e.code.jz(fail);
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step);
e.EmitTerminal(terminal.then_, initial_location, is_single_step);
e.code.L(fail);
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step);
return true;
e.EmitTerminal(terminal.else_, initial_location, is_single_step);
}
bool EmitTerminalImpl(A32EmitX64& e, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
e.code.cmp(dword[e.code.ABI_JIT_PTR + offsetof(A32JitState, halt_reason)], 0);
e.code.jne(e.code.GetForceReturnFromRunCodeAddress());
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step);
return true;
e.EmitTerminal(terminal.else_, initial_location, is_single_step);
}
}
bool A32EmitX64::EmitLeafTerminal(IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept {
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
void EmitTerminalImpl(A32EmitX64&, IR::Term::Invalid, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
}
bool A32EmitX64::EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept {
if (auto const e = std::get_if<IR::Term::LeafTerminal>(&terminal))
return EmitLeafTerminal(*e, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::If>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
UNREACHABLE();
void A32EmitX64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept {
boost::apply_visitor([this, initial_location, is_single_step](auto x) {
EmitTerminalImpl(*this, x, initial_location, is_single_step);
}, terminal);
}
void A32EmitX64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
@@ -112,8 +112,7 @@ public:
// Terminal instruction emitters
void EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location);
bool EmitLeafTerminal(IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept override;
bool EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept override;
void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept override;
// Patching
void Unpatch(const IR::LocationDescriptor& target_desc) override;
@@ -12,7 +12,6 @@
#include <fmt/ostream.h>
#include "common/assert.h"
#include "common/common_types.h"
#include "dynarmic/ir/terminal.h"
#include "dynarmic/mcl/integer_of_size.hpp"
#include <boost/container/static_vector.hpp>
@@ -148,7 +147,7 @@ finish_this_inst:
if (conf.enable_cycle_counting)
EmitAddCycles(block.CycleCount());
code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]);
EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.int3();
for (auto& deferred_emit : ctx.deferred_emits)
deferred_emit();
@@ -618,12 +617,11 @@ std::string A64EmitX64::LocationDescriptorToFriendlyName(const IR::LocationDescr
}
namespace {
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
e.code.ReturnFromRunCode();
return true;
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationDescriptor, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationDescriptor, bool is_single_step) {
// Used for patches and linking
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) {
if (e.conf.enable_cycle_counting) {
@@ -651,10 +649,9 @@ bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax);
e.code.ReturnFromRunCode();
}
return true;
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) {
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) {
e.patch_information[terminal.next].jmp.push_back(e.code.getCurr());
if (auto next_bb = e.GetBasicBlock(terminal.next)) {
@@ -667,86 +664,63 @@ bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::Locat
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax);
e.code.ReturnFromRunCode();
}
return true;
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) {
if (e.conf.HasOptimization(OptimizationFlag::ReturnStackBuffer) && !is_single_step) {
e.code.jmp(e.terminal_handler_pop_rsb_hint);
} else {
e.code.ReturnFromRunCode();
}
return true;
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) {
if (!e.conf.HasOptimization(OptimizationFlag::FastDispatch) || is_single_step) {
e.code.ReturnFromRunCode();
} else {
e.code.jmp(e.terminal_handler_fast_dispatch_hint);
}
return true;
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
switch (terminal.if_) {
case IR::Cond::AL:
case IR::Cond::NV:
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step);
e.EmitTerminal(terminal.then_, initial_location, is_single_step);
break;
default:
Xbyak::Label pass = e.EmitCond(terminal.if_);
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step);
e.EmitTerminal(terminal.else_, initial_location, is_single_step);
e.code.L(pass);
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step);
e.EmitTerminal(terminal.then_, initial_location, is_single_step);
break;
}
return true;
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
Xbyak::Label fail;
e.code.cmp(e.code.byte[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, check_bit)], u8(0));
e.code.jz(fail);
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step);
e.EmitTerminal(terminal.then_, initial_location, is_single_step);
e.code.L(fail);
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step);
return true;
e.EmitTerminal(terminal.else_, initial_location, is_single_step);
}
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
e.code.cmp(dword[e.code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], 0);
e.code.jne(e.code.GetForceReturnFromRunCodeAddress());
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step);
return true;
e.EmitTerminal(terminal.else_, initial_location, is_single_step);
}
}
bool A64EmitX64::EmitLeafTerminal(IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept {
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
void EmitTerminalImpl(A64EmitX64&, IR::Term::Invalid, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
}
bool A64EmitX64::EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept {
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal))
return EmitLeafTerminal(*x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::If>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
return EmitTerminalImpl(*this, *x, initial_location, is_single_step);
UNREACHABLE();
void A64EmitX64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept {
boost::apply_visitor([this, initial_location, is_single_step](auto x) {
EmitTerminalImpl(*this, x, initial_location, is_single_step);
}, terminal);
}
void A64EmitX64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
@@ -107,8 +107,7 @@ public:
void EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* inst);
// Terminal instruction emitters
bool EmitLeafTerminal(IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept override;
bool EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept override;
void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept override;
// Patching
void Unpatch(const IR::LocationDescriptor& target_desc) override;
@@ -111,8 +111,7 @@ public:
#ifndef NDEBUG
void EmitVerboseDebuggingOutput(RegAlloc& reg_alloc);
#endif
virtual bool EmitLeafTerminal(IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept = 0;
virtual bool EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept = 0;
virtual void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept = 0;
// Patching
struct PatchInformation {
+32 -33
View File
@@ -66,44 +66,43 @@ void Block::Reset(LocationDescriptor location_) noexcept {
location = location_;
end_location = location_;
cond = Cond::AL;
terminal = std::monostate{};
terminal = Term::Invalid{};
cond_failed_cycle_count = 0;
cycle_count = 0;
ASSERT(instructions.size() == 0);
}
static std::string TerminalToString(const Term::Terminal& terminal_variant) noexcept {
// struct : boost::static_visitor<std::string> {
// std::string operator()(const std::monostate&) const {
// return "<invalid>";
// }
// std::string operator()(const Term::ReturnToDispatch&) const {
// return "ReturnToDispatch{}";
// }
// std::string operator()(const Term::LinkBlock& terminal) const {
// return fmt::format("LinkBlock{{{}}}", terminal.next);
// }
// std::string operator()(const Term::LinkBlockFast& terminal) const {
// return fmt::format("LinkBlockFast{{{}}}", terminal.next);
// }
// std::string operator()(const Term::PopRSBHint&) const {
// return "PopRSBHint{}";
// }
// std::string operator()(const Term::FastDispatchHint&) const {
// return "FastDispatchHint{}";
// }
// std::string operator()(const Term::If& terminal) const {
// return fmt::format("If{{{}, {}, {}}}", A64::CondToString(terminal.if_), TerminalToString(terminal.then_), TerminalToString(terminal.else_));
// }
// std::string operator()(const Term::CheckBit& terminal) const {
// return fmt::format("CheckBit{{{}, {}}}", TerminalToString(terminal.then_), TerminalToString(terminal.else_));
// }
// std::string operator()(const Term::CheckHalt& terminal) const {
// return fmt::format("CheckHalt{{{}}}", TerminalToString(terminal.else_));
// }
// } visitor;
// return boost::apply_visitor(visitor, terminal_variant);
return "";
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
struct : boost::static_visitor<std::string> {
std::string operator()(const Term::Invalid&) const {
return "<invalid terminal>";
}
std::string operator()(const Term::ReturnToDispatch&) const {
return "ReturnToDispatch{}";
}
std::string operator()(const Term::LinkBlock& terminal) const {
return fmt::format("LinkBlock{{{}}}", terminal.next);
}
std::string operator()(const Term::LinkBlockFast& terminal) const {
return fmt::format("LinkBlockFast{{{}}}", terminal.next);
}
std::string operator()(const Term::PopRSBHint&) const {
return "PopRSBHint{}";
}
std::string operator()(const Term::FastDispatchHint&) const {
return "FastDispatchHint{}";
}
std::string operator()(const Term::If& terminal) const {
return fmt::format("If{{{}, {}, {}}}", A64::CondToString(terminal.if_), TerminalToString(terminal.then_), TerminalToString(terminal.else_));
}
std::string operator()(const Term::CheckBit& terminal) const {
return fmt::format("CheckBit{{{}, {}}}", TerminalToString(terminal.then_), TerminalToString(terminal.else_));
}
std::string operator()(const Term::CheckHalt& terminal) const {
return fmt::format("CheckHalt{{{}}}", TerminalToString(terminal.else_));
}
} visitor;
return boost::apply_visitor(visitor, terminal_variant);
}
std::string DumpBlock(const IR::Block& block) noexcept {
+5 -5
View File
@@ -114,22 +114,22 @@ public:
}
/// Gets the terminal instruction for this basic block.
inline Term::Terminal GetTerminal() const noexcept {
inline Terminal GetTerminal() const noexcept {
return terminal;
}
/// Sets the terminal instruction for this basic block.
inline void SetTerminal(Term::Terminal term) noexcept {
inline void SetTerminal(Terminal term) noexcept {
ASSERT(!HasTerminal() && "Terminal has already been set.");
terminal = std::move(term);
}
/// Replaces the terminal instruction for this basic block.
inline void ReplaceTerminal(Term::Terminal term) noexcept {
inline void ReplaceTerminal(Terminal term) noexcept {
ASSERT(HasTerminal() && "Terminal has not been set.");
terminal = std::move(term);
}
/// Determines whether or not this basic block has a terminal instruction.
inline bool HasTerminal() const noexcept {
return !std::holds_alternative<std::monostate>(terminal);
return terminal.which() != 0;
}
/// Gets a mutable reference to the cycle count for this basic block.
@@ -156,7 +156,7 @@ public:
/// Conditional to pass in order to execute this block
Cond cond = Cond::AL;
/// Terminal instruction of this block.
Term::Terminal terminal = std::monostate{};
Terminal terminal = Term::Invalid{};
/// Number of cycles this block takes to execute if the conditional fails.
size_t cond_failed_cycle_count = 0;
/// Number of cycles this block takes to execute.
+1 -1
View File
@@ -2943,7 +2943,7 @@ public:
Inst(Opcode::CallHostFunction, Imm64(std::bit_cast<u64>(fn)), arg1, arg2, arg3);
}
void SetTerm(const Term::Terminal& terminal) {
void SetTerm(const Terminal& terminal) {
block.SetTerminal(terminal);
}
+69 -52
View File
@@ -8,7 +8,7 @@
#pragma once
#include <variant>
#include <boost/variant.hpp>
#include "common/common_types.h"
#include "dynarmic/ir/cond.h"
@@ -17,89 +17,106 @@
namespace Dynarmic::IR {
namespace Term {
/// This terminal instruction returns control to the dispatcher.
/// The dispatcher will use the current cpu state to determine what comes next.
struct Invalid {};
/**
* This terminal instruction returns control to the dispatcher.
* The dispatcher will use the current cpu state to determine what comes next.
*/
struct ReturnToDispatch {};
/// This terminal instruction jumps to the basic block described by `next` if we have enough
/// cycles remaining. If we do not have enough cycles remaining, we return to the
/// dispatcher, which will return control to the host.
/**
* This terminal instruction jumps to the basic block described by `next` if we have enough
* cycles remaining. If we do not have enough cycles remaining, we return to the
* dispatcher, which will return control to the host.
*/
struct LinkBlock {
explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {}
explicit LinkBlock(const LocationDescriptor& next_)
: next(next_) {}
LocationDescriptor next; ///< Location descriptor for next block.
};
/// This terminal instruction jumps to the basic block described by `next` unconditionally.
/// This is an optimization and MUST only be emitted when this is guaranteed not to result
/// in hanging, even in the face of other optimizations. (In practice, this means that only
/// forward jumps to short-ish blocks would use this instruction.)
/// A backend that doesn't support this optimization may choose to implement this exactly
/// as LinkBlock.
/**
* This terminal instruction jumps to the basic block described by `next` unconditionally.
* This is an optimization and MUST only be emitted when this is guaranteed not to result
* in hanging, even in the face of other optimizations. (In practice, this means that only
* forward jumps to short-ish blocks would use this instruction.)
* A backend that doesn't support this optimization may choose to implement this exactly
* as LinkBlock.
*/
struct LinkBlockFast {
explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {}
explicit LinkBlockFast(const LocationDescriptor& next_)
: next(next_) {}
LocationDescriptor next; ///< Location descriptor for next block.
};
/// This terminal instruction checks the top of the Return Stack Buffer against the current
/// location descriptor. If RSB lookup fails, control is returned to the dispatcher.
/// This is an optimization for faster function calls. A backend that doesn't support
/// this optimization or doesn't have a RSB may choose to implement this exactly as
/// ReturnToDispatch.
/**
* This terminal instruction checks the top of the Return Stack Buffer against the current
* location descriptor. If RSB lookup fails, control is returned to the dispatcher.
* This is an optimization for faster function calls. A backend that doesn't support
* this optimization or doesn't have a RSB may choose to implement this exactly as
* ReturnToDispatch.
*/
struct PopRSBHint {};
/// This terminal instruction performs a lookup of the current location descriptor in the
/// fast dispatch lookup table. A backend that doesn't support this optimization may choose
/// to implement this exactly as ReturnToDispatch.
/**
* This terminal instruction performs a lookup of the current location descriptor in the
* fast dispatch lookup table. A backend that doesn't support this optimization may choose
* to implement this exactly as ReturnToDispatch.
*/
struct FastDispatchHint {};
struct If;
struct CheckBit;
struct CheckHalt;
/// Non recursive kind of terminal
using LeafTerminal = std::variant<
std::monostate,
/// A Terminal is the terminal instruction in a MicroBlock.
using Terminal = boost::variant<
Invalid,
ReturnToDispatch,
LinkBlock,
LinkBlockFast,
PopRSBHint,
FastDispatchHint
>;
FastDispatchHint,
boost::recursive_wrapper<If>,
boost::recursive_wrapper<CheckBit>,
boost::recursive_wrapper<CheckHalt>>;
/// A Terminal is the terminal instruction in a MicroBlock.
using Terminal = std::variant<
std::monostate,
LeafTerminal,
If,
CheckBit,
CheckHalt
>;
/// This terminal instruction conditionally executes one terminal or another depending
/// on the run-time state of the ARM flags.
/**
* This terminal instruction conditionally executes one terminal or another depending
* on the run-time state of the ARM flags.
*/
struct If {
explicit If(Cond if_, LeafTerminal then_, LeafTerminal else_) : if_(if_), then_(std::move(then_)), else_(std::move(else_)) {}
If(Cond if_, Terminal then_, Terminal else_)
: if_(if_), then_(std::move(then_)), else_(std::move(else_)) {}
Cond if_;
LeafTerminal then_;
LeafTerminal else_;
Terminal then_;
Terminal else_;
};
/// This terminal instruction conditionally executes one terminal or another depending
/// on the run-time state of the check bit.
/// then_ is executed if the check bit is non-zero, otherwise else_ is executed.
/**
* This terminal instruction conditionally executes one terminal or another depending
* on the run-time state of the check bit.
* then_ is executed if the check bit is non-zero, otherwise else_ is executed.
*/
struct CheckBit {
explicit CheckBit(LeafTerminal then_, LeafTerminal else_) : then_(std::move(then_)), else_(std::move(else_)) {}
LeafTerminal then_;
LeafTerminal else_;
CheckBit(Terminal then_, Terminal else_)
: then_(std::move(then_)), else_(std::move(else_)) {}
Terminal then_;
Terminal else_;
};
/// This terminal instruction checks if a halt was requested. If it wasn't, else_ is
/// executed.
/**
* This terminal instruction checks if a halt was requested. If it wasn't, else_ is
* executed.
*/
struct CheckHalt {
explicit CheckHalt(LeafTerminal else_) : else_(std::move(else_)) {}
LeafTerminal else_;
explicit CheckHalt(Terminal else_)
: else_(std::move(else_)) {}
Terminal else_;
};
} // namespace Term
using Term::Terminal;
} // namespace Dynarmic::IR
+26 -14
View File
@@ -43,20 +43,32 @@ namespace {
using namespace Dynarmic;
template<typename Fn>
bool AnyLocationDescriptorForTerminalHas(IR::Term::Terminal terminal, Fn fn) {
if (auto const e = std::get_if<IR::Term::LeafTerminal>(&terminal)) {
if (auto const x = std::get_if<IR::Term::LinkBlock>(e))
return fn(x->next);
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(e))
return fn(x->next);
}
if (auto const x = std::get_if<IR::Term::If>(&terminal))
return AnyLocationDescriptorForTerminalHas(x->then_, fn) || AnyLocationDescriptorForTerminalHas(x->else_, fn);
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
return AnyLocationDescriptorForTerminalHas(x->then_, fn) || AnyLocationDescriptorForTerminalHas(x->else_, fn);
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
return AnyLocationDescriptorForTerminalHas(x->else_, fn);
return false;
bool AnyLocationDescriptorForTerminalHas(IR::Terminal terminal, Fn fn) {
return boost::apply_visitor([&](auto t) -> bool {
using T = std::decay_t<decltype(t)>;
if constexpr (std::is_same_v<T, IR::Term::Invalid>) {
return false;
} else if constexpr (std::is_same_v<T, IR::Term::ReturnToDispatch>) {
return false;
} else if constexpr (std::is_same_v<T, IR::Term::LinkBlock>) {
return fn(t.next);
} else if constexpr (std::is_same_v<T, IR::Term::LinkBlockFast>) {
return fn(t.next);
} else if constexpr (std::is_same_v<T, IR::Term::PopRSBHint>) {
return false;
} else if constexpr (std::is_same_v<T, IR::Term::FastDispatchHint>) {
return false;
} else if constexpr (std::is_same_v<T, IR::Term::If>) {
return AnyLocationDescriptorForTerminalHas(t.then_, fn) || AnyLocationDescriptorForTerminalHas(t.else_, fn);
} else if constexpr (std::is_same_v<T, IR::Term::CheckBit>) {
return AnyLocationDescriptorForTerminalHas(t.then_, fn) || AnyLocationDescriptorForTerminalHas(t.else_, fn);
} else if constexpr (std::is_same_v<T, IR::Term::CheckHalt>) {
return AnyLocationDescriptorForTerminalHas(t.else_, fn);
} else {
ASSERT(false && "Invalid terminal type");
return false;
}
}, terminal);
}
bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A32::ITState it_state = {}) {