From 762e8d010bf561bd591f058edc09bf53e382cc03 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 2 Nov 2025 10:29:37 +0000 Subject: [PATCH] a64+a32 stubs (+some impls) Signed-off-by: lizzie --- .../src/dynarmic/backend/ppc64/a32_core.h | 77 + .../dynarmic/backend/ppc64/a32_interface.cpp | 238 +++ .../src/dynarmic/backend/ppc64/a64_core.h | 79 + .../dynarmic/backend/ppc64/a64_interface.cpp | 350 ++++ src/dynarmic/src/dynarmic/backend/ppc64/abi.h | 13 + .../src/dynarmic/backend/ppc64/code_block.h | 35 + .../src/dynarmic/backend/ppc64/emit_context.h | 24 + .../src/dynarmic/backend/ppc64/emit_ppc64.cpp | 128 ++ .../src/dynarmic/backend/ppc64/emit_ppc64.h | 56 + .../dynarmic/backend/ppc64/emit_ppc64_a32.cpp | 354 ++++ .../dynarmic/backend/ppc64/emit_ppc64_a64.cpp | 305 +++ .../ppc64/emit_ppc64_data_processing.cpp | 969 +++++++++ .../ppc64/emit_ppc64_floating_point.cpp | 458 +++++ .../backend/ppc64/emit_ppc64_misc.cpp | 380 ++++ .../backend/ppc64/emit_ppc64_vector.cpp | 1810 +++++++++++++++++ .../src/dynarmic/backend/ppc64/reg_alloc.cpp | 245 +++ .../src/dynarmic/backend/ppc64/reg_alloc.h | 114 ++ .../src/dynarmic/backend/ppc64/stack_layout.h | 28 + 18 files changed, 5663 insertions(+) create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/a32_core.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/a32_interface.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/a64_core.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/a64_interface.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/abi.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/code_block.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_context.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a32.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a64.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_data_processing.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_floating_point.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_misc.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_vector.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.h create mode 100644 src/dynarmic/src/dynarmic/backend/ppc64/stack_layout.h diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/a32_core.h b/src/dynarmic/src/dynarmic/backend/ppc64/a32_core.h new file mode 100644 index 0000000000..e90b7b203b --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/a32_core.h @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include "dynarmic/backend/ppc64/code_block.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/frontend/A32/a32_location_descriptor.h" +#include "dynarmic/interface/A32/a32.h" +#include "dynarmic/interface/A32/config.h" +#include "dynarmic/ir/terminal.h" +#include "dynarmic/ir/basic_block.h" + +namespace Dynarmic::Backend::PPC64 { + +struct A32JitState { + alignas(16) std::array vec{}; + std::array regs{}; + u32 upper_location_descriptor; + u32 exclusive_state = 0; + u32 cpsr_nzcv = 0; + u32 fpsr = 0; + IR::LocationDescriptor GetLocationDescriptor() const { + return IR::LocationDescriptor{regs[15] | (u64(upper_location_descriptor) << 32)}; + } +}; + +class A32AddressSpace final { +public: + explicit A32AddressSpace(const A32::UserConfig& conf); + + IR::Block GenerateIR(IR::LocationDescriptor) const; + + CodePtr Get(IR::LocationDescriptor descriptor); + + CodePtr GetOrEmit(IR::LocationDescriptor descriptor); + + void ClearCache(); + +private: + friend class A32Core; + + void EmitPrelude(); + EmittedBlockInfo Emit(IR::Block ir_block); + void Link(EmittedBlockInfo& block); + + const A32::UserConfig conf; + + CodeBlock cb; + powah::Context as; + + ankerl::unordered_dense::map block_entries; + ankerl::unordered_dense::map block_infos; + + struct PreludeInfo { + CodePtr end_of_prelude; + + using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A32JitState* context, volatile u32* halt_reason); + RunCodeFuncType run_code; + CodePtr return_from_run_code; + } prelude_info; +}; + +class A32Core final { +public: + explicit A32Core(const A32::UserConfig&) {} + + HaltReason Run(A32AddressSpace& process, A32JitState& thread_ctx, volatile u32* halt_reason) { + const auto location_descriptor = thread_ctx.GetLocationDescriptor(); + const auto entry_point = process.GetOrEmit(location_descriptor); + return process.prelude_info.run_code(entry_point, &thread_ctx, halt_reason); + } +}; + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/a32_interface.cpp new file mode 100644 index 0000000000..025fc0c989 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/a32_interface.cpp @@ -0,0 +1,238 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include "dynarmic/common/assert.h" +#include +#include "dynarmic/common/common_types.h" + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/common/atomic.h" +#include "dynarmic/interface/A32/a32.h" + +namespace Dynarmic::Backend::PPC64 { + +A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) + : conf(conf) + , cb(conf.code_cache_size) + , as(cb.ptr(), conf.code_cache_size) { + EmitPrelude(); +} + +IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const { + IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + Optimization::Optimize(ir_block, conf, {}); + return ir_block; +} + +CodePtr A32AddressSpace::Get(IR::LocationDescriptor descriptor) { + if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) + return iter->second; + return nullptr; +} + +CodePtr A32AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { + if (CodePtr block_entry = Get(descriptor)) { + return block_entry; + } + + IR::Block ir_block = GenerateIR(descriptor); + const EmittedBlockInfo block_info = Emit(std::move(ir_block)); + + block_infos.insert_or_assign(descriptor.Value(), block_info); + block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point); + return block_info.entry_point; +} + +void A32AddressSpace::ClearCache() { + block_entries.clear(); + block_infos.clear(); +} + +void A32AddressSpace::EmitPrelude() { + UNREACHABLE(); +} + +EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { + EmittedBlockInfo block_info = EmitPPC64(as, std::move(block), { + .enable_cycle_counting = conf.enable_cycle_counting, + .always_little_endian = conf.always_little_endian, + }); + Link(block_info); + return block_info; +} + +void A32AddressSpace::Link(EmittedBlockInfo& block_info) { + UNREACHABLE(); +} + +namespace Dynarmic::A32 { + +struct Jit::Impl final { + Impl(Jit* jit_interface, A32::UserConfig conf) + : jit_interface(jit_interface) + , conf(conf) + , current_address_space(conf) + , core(conf) {} + + HaltReason Run() { + HaltReason hr = core.Run(current_address_space, current_state, &halt_reason); + RequestCacheInvalidation(); + return hr; + } + + HaltReason Step() { + RequestCacheInvalidation(); + return HaltReason{}; + } + + void ClearCache() { + std::unique_lock lock{invalidation_mutex}; + invalidate_entire_cache = true; + HaltExecution(HaltReason::CacheInvalidation); + } + + void InvalidateCacheRange(u32 start_address, size_t length) { + std::unique_lock lock{invalidation_mutex}; + invalid_cache_ranges.add(boost::icl::discrete_interval::closed(start_address, u32(start_address + length - 1))); + HaltExecution(HaltReason::CacheInvalidation); + } + + void Reset() { + current_state = {}; + } + + void HaltExecution(HaltReason hr) { + Atomic::Or(&halt_reason, ~u32(hr)); + } + + void ClearHalt(HaltReason hr) { + Atomic::And(&halt_reason, ~u32(hr)); + } + + std::array& Regs() { + return current_state.regs; + } + + const std::array& Regs() const { + return current_state.regs; + } + + std::array& ExtRegs() { + return current_state.ext_regs; + } + + const std::array& ExtRegs() const { + return current_state.ext_regs; + } + + u32 Cpsr() const { + return current_state.Cpsr(); + } + + void SetCpsr(u32 value) { + current_state.SetCpsr(value); + } + + u32 Fpscr() const { + return current_state.Fpscr(); + } + + void SetFpscr(u32 value) { + current_state.SetFpscr(value); + } + + void ClearExclusiveState() { + current_state.exclusive_state = false; + } + +private: + void RequestCacheInvalidation() { + // UNREACHABLE(); + + invalidate_entire_cache = false; + invalid_cache_ranges.clear(); + } + + Jit* jit_interface; + A32::UserConfig conf; + A32JitState current_state{}; + A32AddressSpace current_address_space; + A32Core core; + volatile u32 halt_reason = 0; + std::mutex invalidation_mutex; + boost::icl::interval_set invalid_cache_ranges; + bool invalidate_entire_cache = false; +}; + +Jit::Jit(UserConfig conf) : impl(std::make_unique(this, conf)) {} +Jit::~Jit() = default; + +HaltReason Jit::Run() { + return impl->Run(); +} + +HaltReason Jit::Step() { + return impl->Step(); +} + +void Jit::ClearCache() { + impl->ClearCache(); +} + +void Jit::InvalidateCacheRange(u32 start_address, std::size_t length) { + impl->InvalidateCacheRange(start_address, length); +} + +void Jit::Reset() { + impl->Reset(); +} + +void Jit::HaltExecution(HaltReason hr) { + impl->HaltExecution(hr); +} + +void Jit::ClearHalt(HaltReason hr) { + impl->ClearHalt(hr); +} + +std::array& Jit::Regs() { + return impl->Regs(); +} + +const std::array& Jit::Regs() const { + return impl->Regs(); +} + +std::array& Jit::ExtRegs() { + return impl->ExtRegs(); +} + +const std::array& Jit::ExtRegs() const { + return impl->ExtRegs(); +} + +u32 Jit::Cpsr() const { + return impl->Cpsr(); +} + +void Jit::SetCpsr(u32 value) { + impl->SetCpsr(value); +} + +u32 Jit::Fpscr() const { + return impl->Fpscr(); +} + +void Jit::SetFpscr(u32 value) { + impl->SetFpscr(value); +} + +void Jit::ClearExclusiveState() { + impl->ClearExclusiveState(); +} + +} // namespace Dynarmic::A32 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/a64_core.h b/src/dynarmic/src/dynarmic/backend/ppc64/a64_core.h new file mode 100644 index 0000000000..5e3edabe48 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/a64_core.h @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + + +#include +#include +#include "dynarmic/backend/ppc64/code_block.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/frontend/A64/a64_location_descriptor.h" +#include "dynarmic/interface/A64/a64.h" +#include "dynarmic/interface/A64/config.h" +#include "dynarmic/ir/terminal.h" +#include "dynarmic/ir/basic_block.h" + +namespace Dynarmic::Backend::PPC64 { + +struct A64JitState { + using ProgramCounterType = u32; + alignas(16) std::array vec{}; + std::array regs{}; + u32 upper_location_descriptor; + u32 exclusive_state = 0; + u32 cpsr_nzcv = 0; + u32 fpsr = 0; + IR::LocationDescriptor GetLocationDescriptor() const { + return IR::LocationDescriptor{regs[15] | (u64(upper_location_descriptor) << 32)}; + } +}; + +class A64AddressSpace final { +public: + explicit A64AddressSpace(const A64::UserConfig& conf); + + IR::Block GenerateIR(IR::LocationDescriptor) const; + + CodePtr Get(IR::LocationDescriptor descriptor); + + CodePtr GetOrEmit(IR::LocationDescriptor descriptor); + + void ClearCache(); + +private: + friend class A64Core; + + void EmitPrelude(); + EmittedBlockInfo Emit(IR::Block ir_block); + void Link(EmittedBlockInfo& block); + + const A64::UserConfig conf; + + CodeBlock cb; + powah::Context as; + + ankerl::unordered_dense::map block_entries; + ankerl::unordered_dense::map block_infos; + + struct PreludeInfo { + CodePtr end_of_prelude; + + using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A64JitState* context, volatile u32* halt_reason); + RunCodeFuncType run_code; + CodePtr return_from_run_code; + } prelude_info; +}; + +class A64Core final { +public: + explicit A64Core(const A64::UserConfig&) {} + + HaltReason Run(A64AddressSpace& process, A64JitState& thread_ctx, volatile u32* halt_reason) { + const auto location_descriptor = thread_ctx.GetLocationDescriptor(); + const auto entry_point = process.GetOrEmit(location_descriptor); + return process.prelude_info.run_code(entry_point, &thread_ctx, halt_reason); + } +}; + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/a64_interface.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/a64_interface.cpp new file mode 100644 index 0000000000..a0232a6ced --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/a64_interface.cpp @@ -0,0 +1,350 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include "dynarmic/common/assert.h" +#include "dynarmic/common/common_types.h" + +#include "dynarmic/backend/ppc64/a64_core.h" +#include "dynarmic/backend/ppc64/a64_core.h" +#include "dynarmic/common/atomic.h" +#include "dynarmic/interface/A64/a64.h" + +namespace Dynarmic::Backend::PPC64 { + +A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf) + : conf(conf) + , cb(conf.code_cache_size) + , as(cb.ptr(), conf.code_cache_size) { + EmitPrelude(); +} + +IR::Block A64AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const { + IR::Block ir_block = A64::Translate(A64::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + Optimization::Optimize(ir_block, conf, {}); + return ir_block; +} + +CodePtr A64AddressSpace::Get(IR::LocationDescriptor descriptor) { + if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) + return iter->second; + return nullptr; +} + +CodePtr A64AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { + if (CodePtr block_entry = Get(descriptor)) { + return block_entry; + } + + IR::Block ir_block = GenerateIR(descriptor); + const EmittedBlockInfo block_info = Emit(std::move(ir_block)); + + block_infos.insert_or_assign(descriptor.Value(), block_info); + block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point); + return block_info.entry_point; +} + +void A64AddressSpace::ClearCache() { + block_entries.clear(); + block_infos.clear(); +} + +void A64AddressSpace::EmitPrelude() { + UNREACHABLE(); +} + +EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) { + EmittedBlockInfo block_info = EmitPPC64(as, std::move(block), { + .enable_cycle_counting = conf.enable_cycle_counting, + .always_little_endian = conf.always_little_endian, + }); + Link(block_info); + return block_info; +} + +void A64AddressSpace::Link(EmittedBlockInfo& block_info) { + UNREACHABLE(); +} +} + +namespace Dynarmic::A64 { + +struct Jit::Impl final { + Impl(Jit* jit_interface, A64::UserConfig conf) + : jit_interface(jit_interface) + , conf(conf) + , current_address_space(conf) + , core(conf) {} + + HaltReason Run() { + ASSERT(!is_executing); + //PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&jit_state.halt_reason))); + is_executing = true; + const HaltReason hr = block_of_code.RunCode(&jit_state, current_code_ptr); + //PerformRequestedCacheInvalidation(hr); + is_executing = false; + return hr; + } + + HaltReason Step() { + ASSERT(!is_executing); + //PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&jit_state.halt_reason))); + is_executing = true; + const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep()); + //PerformRequestedCacheInvalidation(hr); + is_executing = false; + return hr; + } + + void ClearCache() { + std::unique_lock lock{invalidation_mutex}; + invalidate_entire_cache = true; + HaltExecution(HaltReason::CacheInvalidation); + } + + void InvalidateCacheRange(u64 start_address, size_t length) { + std::unique_lock lock{invalidation_mutex}; + const auto end_address = u64(start_address + length - 1); + invalid_cache_ranges.add(boost::icl::discrete_interval::closed(start_address, end_address)); + HaltExecution(HaltReason::CacheInvalidation); + } + + void Reset() { + ASSERT(!is_executing); + jit_state = {}; + } + + void HaltExecution(HaltReason hr) { + Atomic::Or(&jit_state.halt_reason, u32(hr)); + } + + void ClearHalt(HaltReason hr) { + Atomic::And(&jit_state.halt_reason, ~u32(hr)); + } + + u64 GetSP() const { + return jit_state.sp; + } + + void SetSP(u64 value) { + jit_state.sp = value; + } + + u64 GetPC() const { + return jit_state.pc; + } + + void SetPC(u64 value) { + jit_state.pc = value; + } + + u64 GetRegister(size_t index) const { + if (index == 31) + return GetSP(); + return jit_state.reg.at(index); + } + + void SetRegister(size_t index, u64 value) { + if (index == 31) + return SetSP(value); + jit_state.reg.at(index) = value; + } + + std::array GetRegisters() const { + return jit_state.reg; + } + + void SetRegisters(const std::array& value) { + jit_state.reg = value; + } + + Vector GetVector(size_t index) const { + return {jit_state.vec.at(index * 2), jit_state.vec.at(index * 2 + 1)}; + } + + void SetVector(size_t index, Vector value) { + jit_state.vec.at(index * 2) = value[0]; + jit_state.vec.at(index * 2 + 1) = value[1]; + } + + std::array GetVectors() const { + std::array ret; + static_assert(sizeof(ret) == sizeof(jit_state.vec)); + std::memcpy(ret.data(), jit_state.vec.data(), sizeof(jit_state.vec)); + return ret; + } + + void SetVectors(const std::array& value) { + static_assert(sizeof(value) == sizeof(jit_state.vec)); + std::memcpy(jit_state.vec.data(), value.data(), sizeof(jit_state.vec)); + } + + u32 GetFpcr() const { + return jit_state.GetFpcr(); + } + + void SetFpcr(u32 value) { + jit_state.SetFpcr(value); + } + + u32 GetFpsr() const { + return jit_state.GetFpsr(); + } + + void SetFpsr(u32 value) { + jit_state.SetFpsr(value); + } + + u32 GetPstate() const { + return jit_state.GetPstate(); + } + + void SetPstate(u32 value) { + jit_state.SetPstate(value); + } + + void ClearExclusiveState() { + jit_state.exclusive_state = 0; + } + + bool IsExecuting() const { + return is_executing; + } + +private: + void RequestCacheInvalidation() { + // UNREACHABLE(); + invalidate_entire_cache = false; + invalid_cache_ranges.clear(); + } + + bool is_executing = false; + const UserConfig conf; + A64JitState jit_state; + A64AddressSpace emitter; + BlockOfCode block_of_code; + Optimization::PolyfillOptions polyfill_options; + bool invalidate_entire_cache = false; + boost::icl::interval_set invalid_cache_ranges; + std::mutex invalidation_mutex; +}; + +Jit::Jit(UserConfig conf) : impl(std::make_unique(this, conf)) {} +Jit::~Jit() = default; + +HaltReason Jit::Run() { + return impl->Run(); +} + +HaltReason Jit::Step() { + return impl->Step(); +} + +void Jit::ClearCache() { + impl->ClearCache(); +} + +void Jit::InvalidateCacheRange(u64 start_address, size_t length) { + impl->InvalidateCacheRange(start_address, length); +} + +void Jit::Reset() { + impl->Reset(); +} + +void Jit::HaltExecution(HaltReason hr) { + impl->HaltExecution(hr); +} + +void Jit::ClearHalt(HaltReason hr) { + impl->ClearHalt(hr); +} + +u64 Jit::GetSP() const { + return impl->GetSP(); +} + +void Jit::SetSP(u64 value) { + impl->SetSP(value); +} + +u64 Jit::GetPC() const { + return impl->GetPC(); +} + +void Jit::SetPC(u64 value) { + impl->SetPC(value); +} + +u64 Jit::GetRegister(size_t index) const { + return impl->GetRegister(index); +} + +void Jit::SetRegister(size_t index, u64 value) { + impl->SetRegister(index, value); +} + +std::array Jit::GetRegisters() const { + return impl->GetRegisters(); +} + +void Jit::SetRegisters(const std::array& value) { + impl->SetRegisters(value); +} + +Vector Jit::GetVector(size_t index) const { + return impl->GetVector(index); +} + +void Jit::SetVector(size_t index, Vector value) { + impl->SetVector(index, value); +} + +std::array Jit::GetVectors() const { + return impl->GetVectors(); +} + +void Jit::SetVectors(const std::array& value) { + impl->SetVectors(value); +} + +u32 Jit::GetFpcr() const { + return impl->GetFpcr(); +} + +void Jit::SetFpcr(u32 value) { + impl->SetFpcr(value); +} + +u32 Jit::GetFpsr() const { + return impl->GetFpsr(); +} + +void Jit::SetFpsr(u32 value) { + impl->SetFpsr(value); +} + +u32 Jit::GetPstate() const { + return impl->GetPstate(); +} + +void Jit::SetPstate(u32 value) { + impl->SetPstate(value); +} + +void Jit::ClearExclusiveState() { + impl->ClearExclusiveState(); +} + +bool Jit::IsExecuting() const { + return impl->IsExecuting(); +} + +std::string Jit::Disassemble() const { + return impl->Disassemble(); +} + +} // namespace Dynarmic::A64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/abi.h b/src/dynarmic/src/dynarmic/backend/ppc64/abi.h new file mode 100644 index 0000000000..e47be9fe6a --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/abi.h @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +namespace Dynarmic::Backend::PPC64 { + +constexpr powah::GPR RJIT = powah::R31; + +constexpr std::initializer_list GPR_ORDER{8, 9, 18, 19, 20, 21, 22, 23, 24, 25, 5, 6, 7, 28, 29, 10, 11, 12, 13, 14, 15, 16, 17}; +constexpr std::initializer_list FPR_ORDER{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/code_block.h b/src/dynarmic/src/dynarmic/backend/ppc64/code_block.h new file mode 100644 index 0000000000..3877b9c13f --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/code_block.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +#include "dynarmic/common/common_types.h" +#include "dynarmic/common/assert.h" + +namespace Dynarmic::Backend::PPC64 { + +class CodeBlock { +public: + explicit CodeBlock(std::size_t size) noexcept : memsize(size) { + mem = (u8*)mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); + ASSERT(mem != nullptr); + } + ~CodeBlock() noexcept { + if (mem != nullptr) + munmap(mem, memsize); + } + template + T ptr() const noexcept { + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); + return reinterpret_cast(mem); + } +protected: + u8* mem = nullptr; + size_t memsize = 0; +}; + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_context.h b/src/dynarmic/src/dynarmic/backend/ppc64/emit_context.h new file mode 100644 index 0000000000..25c1562785 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_context.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" + +namespace Dynarmic::IR { +class Block; +} // namespace Dynarmic::IR + +namespace Dynarmic::Backend::PPC64 { + +struct EmitConfig; + +struct EmitContext { + IR::Block& block; + RegAlloc& reg_alloc; + const EmitConfig& emit_conf; + EmittedBlockInfo& ebi; +}; + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.cpp new file mode 100644 index 0000000000..140e9a2d40 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.cpp @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dynarmic/backend/ppc64/emit_ppc64.h" + +#include + +#include +#include +#include + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) {} + +template<> +void EmitIR(powah::Context&, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +EmittedBlockInfo EmitPPC64(powah::Context& as, IR::Block block, const EmitConfig& emit_conf) { + EmittedBlockInfo ebi; + RegAlloc reg_alloc{as}; + EmitContext ctx{block, reg_alloc, emit_conf, ebi}; + //ebi.entry_point = reinterpret_cast(as.GetCursorPointer()); + for (auto iter = block.begin(); iter != block.end(); ++iter) { + IR::Inst* inst = &*iter; + + switch (inst->GetOpcode()) { +#define OPCODE(name, type, ...) \ + case IR::Opcode::name: \ + EmitIR(as, ctx, inst); \ + break; +#define A32OPC(name, type, ...) \ + case IR::Opcode::A32##name: \ + EmitIR(as, ctx, inst); \ + break; +#define A64OPC(name, type, ...) \ + case IR::Opcode::A64##name: \ + EmitIR(as, ctx, inst); \ + break; +#include "dynarmic/ir/opcodes.inc" +#undef OPCODE +#undef A32OPC +#undef A64OPC + default: + UNREACHABLE(); + } + } + //UNREACHABLE(); + //ebi.size = reinterpret_cast(as.GetCursorPointer()) - ebi.entry_point; + return ebi; +} + +void EmitRelocation(powah::Context& as, EmitContext& ctx, LinkTarget link_target) { + UNREACHABLE(); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.h b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.h new file mode 100644 index 0000000000..aad9d0dd63 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.h @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include +#include "dynarmic/common/common_types.h" + +namespace biscuit { +class Assembler; +} // namespace biscuit + +namespace Dynarmic::IR { +class Block; +class Inst; +enum class Cond; +enum class Opcode; +} // namespace Dynarmic::IR + +namespace Dynarmic::Backend::PPC64 { + +using CodePtr = std::byte*; + +enum class LinkTarget { + ReturnFromRunCode, +}; + +struct Relocation { + std::ptrdiff_t code_offset; + LinkTarget target; +}; + +struct EmittedBlockInfo { + CodePtr entry_point; + size_t size; + std::vector relocations; +}; + +struct EmitConfig { + bool enable_cycle_counting; + bool always_little_endian; +}; + +struct EmitContext; + +EmittedBlockInfo EmitPPC64(powah::Context& as, IR::Block block, const EmitConfig& emit_conf); + +template +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst); +void EmitRelocation(powah::Context& as, EmitContext& ctx, LinkTarget link_target); +void EmitA32Cond(powah::Context& as, EmitContext& ctx, IR::Cond cond, powah::Label* label); +void EmitA32Terminal(powah::Context& as, EmitContext& ctx); + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a32.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a32.cpp new file mode 100644 index 0000000000..f851882c4e --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a32.cpp @@ -0,0 +1,354 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +void EmitA32Cond(powah::Context& as, EmitContext&, IR::Cond cond, powah::Label* label) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step); + +void EmitA32Terminal(powah::Context&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { + EmitRelocation(as, ctx, LinkTarget::ReturnFromRunCode); +} + +void EmitSetUpperLocationDescriptor(powah::Context& as, EmitContext& ctx, IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::PopRSBHint, IR::LocationDescriptor, bool) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) { + UNREACHABLE(); +} + +void EmitA32Terminal(powah::Context& as, EmitContext& ctx) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Memory +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Coprocesor +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a64.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a64.cpp new file mode 100644 index 0000000000..2729d145f9 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a64.cpp @@ -0,0 +1,305 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Memory +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_data_processing.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_data_processing.cpp new file mode 100644 index 0000000000..80aa9a13d5 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_data_processing.cpp @@ -0,0 +1,969 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "dynarmic/common/assert.h" +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +/* +uint64_t f(uint64_t a) { return (uint16_t)a; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 0, 0xffff); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a) { return (uint8_t)a; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 0, 0xff); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a) { return (uint32_t)(a >> 32); } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SRDI(result, source, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a) { return ((uint32_t)a) >> 31; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 1, 31, 31); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a) { return a == 0; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.CNTLZD(result, source); + code.SRDI(result, result, 6); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a) { return (uint32_t)a == 0; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.CNTLZW(result, source); + code.SRWI(result, result, 5); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a) { return (a & 1) != 0; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + if (args[1].IsImmediate()) { + auto const shift = args[1].GetImmediateU8(); + if (shift > 0) { + code.RLDICL(result, source, (64 - shift - 1) & 0x3f, 63); + } + } else { + UNREACHABLE(); + } + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +struct jit { + uint64_t t; + uint64_t a; +}; +uint64_t f(jit *p, uint64_t a, uint64_t b) { + bool n = (p->a & 0b1000) != 0; + bool z = (p->a & 0b0100) != 0; + bool c = (p->a & 0b0010) != 0; + bool v = (p->a & 0b0001) != 0; + return (p->a & 0b0001) == 0 ? a : b; +} +*/ +static powah::GPR EmitConditionalSelectX(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const nzcv = ctx.reg_alloc.ScratchGpr(); + powah::GPR const then_ = ctx.reg_alloc.UseScratchGpr(args[1]); + powah::GPR const else_ = ctx.reg_alloc.UseScratchGpr(args[2]); + switch (args[0].GetImmediateCond()) { + case IR::Cond::EQ: // Z == 1 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 4); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::NE: // Z == 0 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 4); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::CS: // C == 1 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 2); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::CC: // C == 0 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 2); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::MI: // N == 1 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 8); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::PL: // N == 0 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 8); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::VS: // V == 1 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 1); + code.ISELGT(nzcv, then_, else_); + break; + case IR::Cond::VC: // V == 0 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(nzcv, nzcv, 1); + code.ISELGT(nzcv, else_, then_); + break; + case IR::Cond::HI: // Z == 0 && C == 1 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.RLWINM(nzcv, nzcv, 0, 29, 30); + code.CMPLDI(nzcv, 2); + code.ISELEQ(nzcv, then_, else_); + break; + case IR::Cond::LS: // Z == 1 || C == 0 + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.RLWINM(nzcv, nzcv, 0, 29, 30); + code.CMPLDI(nzcv, 2); + code.ISELEQ(nzcv, else_, then_); + break; + case IR::Cond::GE: { // N == V + powah::GPR const tmp = ctx.reg_alloc.ScratchGpr(); + code.LWZ(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.SRWI(tmp, nzcv, 3); + code.XOR(nzcv, tmp, nzcv); + code.ANDI_(nzcv, nzcv, 1); + code.ISELGT(nzcv, else_, then_); + } break; + case IR::Cond::LT: { // N != V + powah::GPR const tmp = ctx.reg_alloc.ScratchGpr(); + code.LWZ(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.SRWI(tmp, nzcv, 3); + code.XOR(nzcv, tmp, nzcv); + code.ANDI_(nzcv, nzcv, 1); + code.ISELGT(nzcv, then_, else_); + } break; + case IR::Cond::GT: { // Z == 0 && N == V + powah::GPR const tmp = ctx.reg_alloc.ScratchGpr(); + powah::Label const l_ne = code.DefineLabel(); + powah::Label const l_cc = code.DefineLabel(); + powah::Label const l_fi = code.DefineLabel(); + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(tmp, nzcv, 4); + code.BNE(powah::CR0, l_ne); + code.SRWI(tmp, nzcv, 3); + code.XOR(nzcv, tmp, nzcv); + code.ANDI_(nzcv, nzcv, 1); + code.CMPLDI(nzcv, 0); + code.BGT(powah::CR0, l_fi); + code.LABEL(l_ne); + code.MR(then_, else_); + code.LABEL(l_cc); + code.MR(nzcv, then_); + code.LABEL(l_fi); + } break; + case IR::Cond::LE: { // Z == 1 || N != V + powah::GPR const tmp = ctx.reg_alloc.ScratchGpr(); + powah::Label const l_ne = code.DefineLabel(); + code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv)); + code.ANDI_(tmp, nzcv, 4); + code.BNE(powah::CR0, l_ne); + code.SRWI(tmp, nzcv, 3); + code.XOR(nzcv, tmp, nzcv); + code.ANDI_(nzcv, nzcv, 1); + code.ISELGT(then_, then_, else_); + code.LABEL(l_ne); + code.MR(nzcv, then_); + } break; + default: + UNREACHABLE(); + } + return nzcv; +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + powah::GPR const result = EmitConditionalSelectX(code, ctx, inst); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + powah::GPR const result = EmitConditionalSelectX(code, ctx, inst); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + powah::GPR const result = EmitConditionalSelectX(code, ctx, inst); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const shift = ctx.reg_alloc.UseGpr(args[1]); + code.SLW(result, source, shift); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const shift = ctx.reg_alloc.UseGpr(args[1]); + code.SLD(result, source, shift); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const shift = ctx.reg_alloc.UseGpr(args[1]); + code.SRW(result, source, shift); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +/* +uint64_t f(uint64_t a, uint64_t s) { return a >> s; } +*/ +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const shift = ctx.reg_alloc.UseGpr(args[1]); + code.SRD(result, source, shift); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const shift = ctx.reg_alloc.UseGpr(args[1]); + code.SRAW(result, source, shift); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const shift = ctx.reg_alloc.UseGpr(args[1]); + code.SRAD(result, source, shift); + ctx.reg_alloc.DefineValue(inst, result); +} + +// __builtin_rotateright32 +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.NEG(result, src_a, powah::R0); + code.ROTLW(result, result, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.NEG(result, src_a, powah::R0); + code.ROTLD(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.NEG(result, src_a, powah::R0); + code.ROTLD(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SLW(result, source, source); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SLD(result, source, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SRW(result, source, source); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SRD(result, source, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SRAW(result, source, source); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.SRAL(result, source, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.NEG(result, src_a, powah::R0); + code.ROTLD(result, result, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.NEG(result, src_a, powah::R0); + code.ROTLD(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.ADD(result, src_a, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.ADD(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.SUBF(result, src_b, src_a); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.SUBF(result, src_b, src_a); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.MULLW(result, src_a, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.MULLD(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.MULLD(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.MULLD(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.DIVDU(result, src_a, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.DIVDU(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.DIVW(result, src_a, src_b); + code.EXTSW(result, result); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.DIVD(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.AND(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.AND(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.NAND(result, src_a, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.NAND(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.XOR(result, src_a, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.XOR(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.OR(result, src_a, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[1]); + code.OR(result, src_a, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.NOT(result, source); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.NOT(result, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.EXTSB(result, source); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.EXTSH(result, source); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.EXTSH(result, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.EXTSB(result, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.EXTSW(result, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 0, 0xff); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 0, 0xffff); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 0, 0xff); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLWINM(result, source, 0, 0xffff); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +// __builtin_bswap32 +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + if (false) { + //code.BRW(result, source); + code.RLDICL(result, result, 0, 32); + } else { + code.ROTLWI(result, source, 8); + code.RLWIMI(result, source, 24, 16, 23); + code.RLWIMI(result, source, 24, 0, 7); + } + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + if (false) { + //code.BRH(result, source); + code.RLWINM(result, source, 0, 0xff); + } else { + code.ROTLWI(result, source, 24); + code.RLWIMI(result, source, 8, 0, 23); + code.CLRLDI(result, result, 48); + } + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + if (false) { + //code.BRD(result, source); + } else { + powah::GPR const tmp = ctx.reg_alloc.ScratchGpr(); + code.ROTLDI(tmp, source, 16); + code.ROTLDI(result, source, 8); + code.RLDIMI(result, tmp, 8, 48); + code.ROTLDI(tmp, source, 24); + code.RLDIMI(result, tmp, 16, 40); + code.ROTLDI(tmp, source, 32); + code.RLDIMI(result, tmp, 24, 32); + code.ROTLDI(tmp, source, 48); + code.RLDIMI(result, tmp, 40, 16); + code.ROTLDI(tmp, source, 56); + code.RLDIMI(result, tmp, 48, 8); + code.RLDIMI(result, source, 56, 0); + } + ctx.reg_alloc.DefineValue(inst, result); +} + +// __builtin_clz +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.CNTLZW(result, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +// __builtin_clz +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const source = ctx.reg_alloc.UseGpr(args[0]); + code.CNTLZD(result, source); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPD(powah::CR0, result, src_a); + code.ISELGT(result, result, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPD(powah::CR0, result, src_a); + code.ISELGT(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPLW(result, src_a); + code.ISELGT(result, result, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPLD(result, src_a); + code.ISELGT(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPW(powah::CR0, result, src_a); + code.ISELGT(result, result, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPD(powah::CR0, result, src_a); + code.ISELGT(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPLW(result, src_a); + code.ISELGT(result, result, src_b); + code.RLDICL(result, result, 0, 32); + ctx.reg_alloc.DefineValue(inst, result); +} + +template<> +void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + powah::GPR const result = ctx.reg_alloc.ScratchGpr(); + powah::GPR const src_a = ctx.reg_alloc.UseGpr(args[0]); + powah::GPR const src_b = ctx.reg_alloc.UseGpr(args[0]); + code.CMPLD(result, src_a); + code.ISELGT(result, result, src_b); + ctx.reg_alloc.DefineValue(inst, result); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_floating_point.cpp new file mode 100644 index 0000000000..b50f5027cd --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_floating_point.cpp @@ -0,0 +1,458 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_misc.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_misc.cpp new file mode 100644 index 0000000000..89d925e465 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_misc.cpp @@ -0,0 +1,380 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Packed +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Crypto +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_vector.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_vector.cpp new file mode 100644 index 0000000000..ccc4daf4b1 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_vector.cpp @@ -0,0 +1,1810 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "dynarmic/backend/ppc64/a32_core.h" +#include "dynarmic/backend/ppc64/abi.h" +#include "dynarmic/backend/ppc64/emit_context.h" +#include "dynarmic/backend/ppc64/emit_ppc64.h" +#include "dynarmic/backend/ppc64/reg_alloc.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/opcodes.h" + +namespace Dynarmic::Backend::PPC64 { + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Vector saturation +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +// Vector VFP +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +template<> +void EmitIR(powah::Context&, EmitContext&, IR::Inst*) { + UNREACHABLE(); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.cpp new file mode 100644 index 0000000000..a0c752fded --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.cpp @@ -0,0 +1,245 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dynarmic/backend/ppc64/reg_alloc.h" + +#include +#include + +#include "dynarmic/common/assert.h" +#include +#include "dynarmic/common/common_types.h" + +#include "dynarmic/common/always_false.h" + +namespace Dynarmic::Backend::PPC64 { + +constexpr size_t spill_offset = offsetof(StackLayout, spill); +constexpr size_t spill_slot_size = sizeof(decltype(StackLayout::spill)::value_type); + +static bool IsValuelessType(IR::Type type) { + return type == IR::Type::Table; +} + +IR::Type Argument::GetType() const { + return value.GetType(); +} + +bool Argument::IsImmediate() const { + return value.IsImmediate(); +} + +bool Argument::GetImmediateU1() const { + return value.GetU1(); +} + +u8 Argument::GetImmediateU8() const { + const u64 imm = value.GetImmediateAsU64(); + ASSERT(imm < 0x100); + return u8(imm); +} + +u16 Argument::GetImmediateU16() const { + const u64 imm = value.GetImmediateAsU64(); + ASSERT(imm < 0x10000); + return u16(imm); +} + +u32 Argument::GetImmediateU32() const { + const u64 imm = value.GetImmediateAsU64(); + ASSERT(imm < 0x100000000); + return u32(imm); +} + +u64 Argument::GetImmediateU64() const { + return value.GetImmediateAsU64(); +} + +IR::Cond Argument::GetImmediateCond() const { + ASSERT(IsImmediate() && GetType() == IR::Type::Cond); + return value.GetCond(); +} + +IR::AccType Argument::GetImmediateAccType() const { + ASSERT(IsImmediate() && GetType() == IR::Type::AccType); + return value.GetAccType(); +} + +bool HostLocInfo::Contains(const IR::Inst* value) const { + return std::find(values.begin(), values.end(), value) != values.end(); +} + +void HostLocInfo::SetupScratchLocation() { + ASSERT(IsCompletelyEmpty()); + realized = true; +} + +bool HostLocInfo::IsCompletelyEmpty() const { + return values.empty() && !locked && !realized && !accumulated_uses && !expected_uses && !uses_this_inst; +} + +void HostLocInfo::UpdateUses() { + accumulated_uses += uses_this_inst; + uses_this_inst = 0; + + if (accumulated_uses == expected_uses) { + values.clear(); + accumulated_uses = 0; + expected_uses = 0; + } +} + +RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { + ArgumentInfo ret = {Argument{*this}, Argument{*this}, Argument{*this}, Argument{*this}}; + for (size_t i = 0; i < inst->NumArgs(); i++) { + const IR::Value arg = inst->GetArg(i); + ret[i].value = arg; + if (!arg.IsImmediate() && !IsValuelessType(arg.GetType())) { + ASSERT(ValueLocation(arg.GetInst()) && "argument must already been defined"); + ValueInfo(arg.GetInst()).uses_this_inst++; + } + } + return ret; +} + +bool RegAlloc::IsValueLive(IR::Inst* inst) const { + return !!ValueLocation(inst); +} + +void RegAlloc::UpdateAllUses() { + for (auto& gpr : gprs) { + gpr.UpdateUses(); + } + for (auto& fpr : fprs) { + fpr.UpdateUses(); + } + for (auto& spill : spills) { + spill.UpdateUses(); + } +} + +void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) { + ASSERT(!ValueLocation(inst)); + + if (arg.value.IsImmediate()) { + inst->ReplaceUsesWith(arg.value); + return; + } + + auto& info = ValueInfo(arg.value.GetInst()); + info.values.emplace_back(inst); + info.expected_uses += inst->UseCount(); +} + +void RegAlloc::AssertNoMoreUses() const { + const auto is_empty = [](const auto& i) { return i.IsCompletelyEmpty(); }; + ASSERT(std::all_of(gprs.begin(), gprs.end(), is_empty)); + ASSERT(std::all_of(fprs.begin(), fprs.end(), is_empty)); + ASSERT(std::all_of(spills.begin(), spills.end(), is_empty)); +} + +u32 RegAlloc::AllocateRegister(const std::array& regs, const std::vector& order) const { + const auto empty = std::find_if(order.begin(), order.end(), [&](u32 i) { return regs[i].values.empty() && !regs[i].locked; }); + if (empty != order.end()) + return *empty; + + std::vector candidates; + std::copy_if(order.begin(), order.end(), std::back_inserter(candidates), [&](u32 i) { return !regs[i].locked; }); + // TODO: LRU + return candidates[0]; +} + +void RegAlloc::SpillGpr(u32 index) { + ASSERT(!gprs[index].locked && !gprs[index].realized); + if (gprs[index].values.empty()) + return; + const u32 new_location_index = FindFreeSpill(); + //as.SD(powah::GPR{index}, spill_offset + new_location_index * spill_slot_size, powah::sp); + spills[new_location_index] = std::exchange(gprs[index], {}); +} + +void RegAlloc::SpillFpr(u32 index) { + ASSERT(!fprs[index].locked && !fprs[index].realized); + if (fprs[index].values.empty()) { + return; + } + const u32 new_location_index = FindFreeSpill(); + //as.FSD(powah::FPR{index}, spill_offset + new_location_index * spill_slot_size, powah::sp); + spills[new_location_index] = std::exchange(fprs[index], {}); +} + +u32 RegAlloc::FindFreeSpill() const { + const auto iter = std::find_if(spills.begin(), spills.end(), [](const HostLocInfo& info) { return info.values.empty(); }); + ASSERT(iter != spills.end() && "All spill locations are full"); + return u32(iter - spills.begin()); +} + +std::optional RegAlloc::ValueLocation(const IR::Inst* value) const { + const auto contains_value = [value](const HostLocInfo& info) { + return info.Contains(value); + }; + if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) { + return HostLoc{HostLoc::Kind::Gpr, static_cast(iter - gprs.begin())}; + } else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != fprs.end()) { + return HostLoc{HostLoc::Kind::Fpr, static_cast(iter - fprs.begin())}; + } else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != spills.end()) { + return HostLoc{HostLoc::Kind::Spill, static_cast(iter - spills.begin())}; + } + return std::nullopt; +} + +HostLocInfo& RegAlloc::ValueInfo(HostLoc host_loc) { + switch (host_loc.kind) { + case HostLoc::Kind::Gpr: + return gprs[size_t(host_loc.index)]; + case HostLoc::Kind::Fpr: + return fprs[size_t(host_loc.index)]; + case HostLoc::Kind::Spill: + return spills[size_t(host_loc.index)]; + } + UNREACHABLE(); +} + +HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) { + const auto contains_value = [value](const HostLocInfo& info) { + return info.Contains(value); + }; + if (const auto iter = std::find_if(gprs.begin(), gprs.end(), contains_value); iter != gprs.end()) { + return *iter; + } else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), contains_value); iter != gprs.end()) { + return *iter; + } else if (const auto iter = std::find_if(spills.begin(), spills.end(), contains_value); iter != gprs.end()) { + return *iter; + } + UNREACHABLE(); +} + +powah::GPR RegAlloc::ScratchGpr(std::optional> desired_locations) { + UNREACHABLE(); +} + +void RegAlloc::Use(Argument& arg, HostLoc host_loc) { + UNREACHABLE(); +} + +void RegAlloc::UseScratch(Argument& arg, HostLoc host_loc) { + UNREACHABLE(); +} + +powah::GPR RegAlloc::UseGpr(Argument& arg) { + UNREACHABLE(); +} + +powah::GPR RegAlloc::UseScratchGpr(Argument& arg) { + UNREACHABLE(); +} + +void RegAlloc::DefineValue(IR::Inst* inst, powah::GPR const gpr) noexcept { + UNREACHABLE(); +} + +void RegAlloc::DefineValue(IR::Inst* inst, Argument& arg) noexcept { + UNREACHABLE(); +} + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.h new file mode 100644 index 0000000000..5e73513d14 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.h @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include "dynarmic/common/assert.h" +#include "dynarmic/common/common_types.h" +#include + +#include "dynarmic/backend/ppc64/stack_layout.h" +#include "dynarmic/ir/cond.h" +#include "dynarmic/ir/microinstruction.h" +#include "dynarmic/ir/value.h" + +namespace Dynarmic::Backend::PPC64 { + +class RegAlloc; + +enum class HostLoc : uint8_t { + R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, + R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, + R30, R31, + VR0, VR1, VR2, VR3, VR4, VR5, VR6, VR7, VR8, VR9, + VR10, VR11, VR12, VR13, VR14, VR15, VR16, VR17, VR18, VR19, + VR20, VR21, VR22, VR23, VR24, VR25, VR26, VR27, VR28, VR29, + VR30, VR31, + FirstSpill, +}; + +struct Argument { +public: + using copyable_reference = std::reference_wrapper; + + IR::Type GetType() const; + bool IsImmediate() const; + + bool GetImmediateU1() const; + u8 GetImmediateU8() const; + u16 GetImmediateU16() const; + u32 GetImmediateU32() const; + u64 GetImmediateU64() const; + IR::Cond GetImmediateCond() const; + IR::AccType GetImmediateAccType() const; + +private: + friend class RegAlloc; + explicit Argument(RegAlloc& reg_alloc) + : reg_alloc{reg_alloc} {} + + bool allocated = false; + RegAlloc& reg_alloc; + IR::Value value; +}; + +struct HostLocInfo final { + std::vector values; + size_t locked = 0; + size_t uses_this_inst = 0; + size_t accumulated_uses = 0; + size_t expected_uses = 0; + bool realized = false; + + bool Contains(const IR::Inst*) const; + void SetupScratchLocation(); + bool IsCompletelyEmpty() const; + void UpdateUses(); +}; + +class RegAlloc { +public: + using ArgumentInfo = std::array; + + explicit RegAlloc(powah::Context& as) : as{as} {} + + ArgumentInfo GetArgumentInfo(IR::Inst* inst); + bool IsValueLive(IR::Inst* inst) const; + void DefineAsExisting(IR::Inst* inst, Argument& arg); + + void SpillAll(); + void UpdateAllUses(); + void AssertNoMoreUses() const; + + powah::GPR ScratchGpr(std::optional> desired_locations = {}); + void Use(Argument& arg, HostLoc host_loc); + void UseScratch(Argument& arg, HostLoc host_loc); + powah::GPR UseGpr(Argument& arg); + powah::GPR UseScratchGpr(Argument& arg); + void DefineValue(IR::Inst* inst, powah::GPR const gpr) noexcept; + void DefineValue(IR::Inst* inst, Argument& arg) noexcept; +private: + u32 AllocateRegister(const std::array& regs, const std::vector& order) const; + void SpillGpr(u32 index); + void SpillFpr(u32 index); + u32 FindFreeSpill() const; + + std::optional ValueLocation(const IR::Inst* value) const; + HostLocInfo& ValueInfo(HostLoc host_loc); + HostLocInfo& ValueInfo(const IR::Inst* value); + + powah::Context& as; + std::array gprs; + std::array fprs; + std::array spills; +}; + +} // namespace Dynarmic::Backend::RV64 diff --git a/src/dynarmic/src/dynarmic/backend/ppc64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/ppc64/stack_layout.h new file mode 100644 index 0000000000..bb70a359a9 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/ppc64/stack_layout.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "dynarmic/common/common_types.h" + +namespace Dynarmic::Backend::PPC64 { + +constexpr size_t SpillCount = 64; + +struct alignas(16) StackLayout { + s64 cycles_remaining; + s64 cycles_to_run; + + std::array spill; + + u32 save_host_fpcr; + u32 save_host_fpsr; + + bool check_bit; +}; + +static_assert(sizeof(StackLayout) % 16 == 0); + +} // namespace Dynarmic::Backend::RV64