Browse Source
a64+a32 stubs (+some impls)
a64+a32 stubs (+some impls)
Signed-off-by: lizzie <lizzie@eden-emu.dev>dynarmic-ppc64
18 changed files with 5663 additions and 0 deletions
-
77src/dynarmic/src/dynarmic/backend/ppc64/a32_core.h
-
238src/dynarmic/src/dynarmic/backend/ppc64/a32_interface.cpp
-
79src/dynarmic/src/dynarmic/backend/ppc64/a64_core.h
-
350src/dynarmic/src/dynarmic/backend/ppc64/a64_interface.cpp
-
13src/dynarmic/src/dynarmic/backend/ppc64/abi.h
-
35src/dynarmic/src/dynarmic/backend/ppc64/code_block.h
-
24src/dynarmic/src/dynarmic/backend/ppc64/emit_context.h
-
128src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.cpp
-
56src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64.h
-
354src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a32.cpp
-
305src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_a64.cpp
-
969src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_data_processing.cpp
-
458src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_floating_point.cpp
-
380src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_misc.cpp
-
1810src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_vector.cpp
-
245src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.cpp
-
114src/dynarmic/src/dynarmic/backend/ppc64/reg_alloc.h
-
28src/dynarmic/src/dynarmic/backend/ppc64/stack_layout.h
@ -0,0 +1,77 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <powah_emit.hpp> |
|||
#include <ankerl/unordered_dense.h> |
|||
#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<u32, 64> vec{}; |
|||
std::array<u32, 16> 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<u64, CodePtr> block_entries; |
|||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> 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 |
|||
@ -0,0 +1,238 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
|
|||
#include <boost/icl/interval_set.hpp>
|
|||
#include "dynarmic/common/assert.h"
|
|||
#include <mcl/scope_exit.hpp>
|
|||
#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<u8*>(), 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<u32>::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<u32, 16>& Regs() { |
|||
return current_state.regs; |
|||
} |
|||
|
|||
const std::array<u32, 16>& Regs() const { |
|||
return current_state.regs; |
|||
} |
|||
|
|||
std::array<u32, 64>& ExtRegs() { |
|||
return current_state.ext_regs; |
|||
} |
|||
|
|||
const std::array<u32, 64>& 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<u32> invalid_cache_ranges; |
|||
bool invalidate_entire_cache = false; |
|||
}; |
|||
|
|||
Jit::Jit(UserConfig conf) : impl(std::make_unique<Impl>(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<u32, 16>& Jit::Regs() { |
|||
return impl->Regs(); |
|||
} |
|||
|
|||
const std::array<u32, 16>& Jit::Regs() const { |
|||
return impl->Regs(); |
|||
} |
|||
|
|||
std::array<u32, 64>& Jit::ExtRegs() { |
|||
return impl->ExtRegs(); |
|||
} |
|||
|
|||
const std::array<u32, 64>& 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
|
|||
@ -0,0 +1,79 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
|
|||
#include <powah_emit.hpp> |
|||
#include <ankerl/unordered_dense.h> |
|||
#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<u64, 64> vec{}; |
|||
std::array<u64, 31> 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<u64, CodePtr> block_entries; |
|||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> 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 |
|||
@ -0,0 +1,350 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
|
|||
#include <boost/icl/interval_set.hpp>
|
|||
#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<u8*>(), 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<u64>::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<u64, 31> GetRegisters() const { |
|||
return jit_state.reg; |
|||
} |
|||
|
|||
void SetRegisters(const std::array<u64, 31>& 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<Vector, 32> GetVectors() const { |
|||
std::array<Vector, 32> 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<Vector, 32>& 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<u64> invalid_cache_ranges; |
|||
std::mutex invalidation_mutex; |
|||
}; |
|||
|
|||
Jit::Jit(UserConfig conf) : impl(std::make_unique<Jit::Impl>(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<u64, 31> Jit::GetRegisters() const { |
|||
return impl->GetRegisters(); |
|||
} |
|||
|
|||
void Jit::SetRegisters(const std::array<u64, 31>& 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<Vector, 32> Jit::GetVectors() const { |
|||
return impl->GetVectors(); |
|||
} |
|||
|
|||
void Jit::SetVectors(const std::array<Vector, 32>& 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
|
|||
@ -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<u32> 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<u32> 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 |
|||
@ -0,0 +1,35 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <new> |
|||
#include <sys/mman.h> |
|||
|
|||
#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<typename T> |
|||
T ptr() const noexcept { |
|||
static_assert(std::is_pointer_v<T> || std::is_same_v<T, uintptr_t> || std::is_same_v<T, intptr_t>); |
|||
return reinterpret_cast<T>(mem); |
|||
} |
|||
protected: |
|||
u8* mem = nullptr; |
|||
size_t memsize = 0; |
|||
}; |
|||
|
|||
} // namespace Dynarmic::Backend::RV64 |
|||
@ -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 |
|||
@ -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 <bit>
|
|||
|
|||
#include <powah_emit.hpp>
|
|||
#include <fmt/ostream.h>
|
|||
#include <mcl/bit/bit_field.hpp>
|
|||
|
|||
#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<IR::Opcode::Void>(powah::Context&, EmitContext&, IR::Inst*) {} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::Identity>(powah::Context&, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::Breakpoint>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CallHostFunction>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PushRSB>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetCarryFromOp>(powah::Context&, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetOverflowFromOp>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetGEFromOp>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetNZCVFromOp>(powah::Context&, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetNZFromOp>(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetUpperFromOp>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetLowerFromOp>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::GetCFlagFromNZCV>(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::NZCVFromPackedFlags>(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<CodePtr>(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<IR::Opcode::name>(as, ctx, inst); \ |
|||
break; |
|||
#define A32OPC(name, type, ...) \
|
|||
case IR::Opcode::A32##name: \ |
|||
EmitIR<IR::Opcode::A32##name>(as, ctx, inst); \ |
|||
break; |
|||
#define A64OPC(name, type, ...) \
|
|||
case IR::Opcode::A64##name: \ |
|||
EmitIR<IR::Opcode::A64##name>(as, ctx, inst); \ |
|||
break; |
|||
#include "dynarmic/ir/opcodes.inc"
|
|||
#undef OPCODE
|
|||
#undef A32OPC
|
|||
#undef A64OPC
|
|||
default: |
|||
UNREACHABLE(); |
|||
} |
|||
} |
|||
//UNREACHABLE();
|
|||
//ebi.size = reinterpret_cast<CodePtr>(as.GetCursorPointer()) - ebi.entry_point;
|
|||
return ebi; |
|||
} |
|||
|
|||
void EmitRelocation(powah::Context& as, EmitContext& ctx, LinkTarget link_target) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
} // namespace Dynarmic::Backend::RV64
|
|||
@ -0,0 +1,56 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
|
|||
#include <powah_emit.hpp> |
|||
#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<Relocation> 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<IR::Opcode op> |
|||
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 |
|||
@ -0,0 +1,354 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <powah_emit.hpp>
|
|||
#include <fmt/ostream.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 { |
|||
|
|||
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<IR::Opcode::A32SetCheckBit>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetRegister>(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetExtendedRegister32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetExtendedRegister64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetVector>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetRegister>(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetExtendedRegister32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetExtendedRegister64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetVector>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetCpsr>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetCpsr>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetCpsrNZCV>(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetCpsrNZCVRaw>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetCpsrNZCVQ>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetCpsrNZ>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetCpsrNZC>(powah::Context& as, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetCFlag>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32OrQFlag>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetGEFlags>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetGEFlags>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetGEFlagsCompressed>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32BXWritePC>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CallSupervisor>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExceptionRaised>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetFpscr>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetFpscr>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32GetFpscrNZCV>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32SetFpscrNZCV>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
// Memory
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ClearExclusive>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32WriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32WriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32WriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32WriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
// Coprocesor
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocInternalOperation>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocSendOneWord>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocSendTwoWords>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocGetOneWord>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocGetTwoWords>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocLoadWords>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A32CoprocStoreWords>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
} // namespace Dynarmic::Backend::RV64
|
|||
@ -0,0 +1,305 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <powah_emit.hpp>
|
|||
#include <fmt/ostream.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<IR::Opcode::A64SetCheckBit>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetCFlag>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetNZCVRaw>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetNZCVRaw>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetNZCV>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetW>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetX>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetS>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetD>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetQ>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetSP>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetFPCR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetFPSR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetW>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetX>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetS>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetD>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetQ>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetSP>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetFPCR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetFPSR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetPC>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64CallSupervisor>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExceptionRaised>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64DataCacheOperationRaised>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64InstructionCacheOperationRaised>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64DataSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64DataMemoryBarrier>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64InstructionSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetCNTFRQ>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetCNTPCT>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetCTR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetDCZID>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetTPIDR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64GetTPIDRRO>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64SetTPIDR>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
// Memory
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ClearExclusive>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ReadMemory128>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory128>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64WriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64WriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64WriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64WriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64WriteMemory128>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory128>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
|
|||
} // namespace Dynarmic::Backend::RV64
|
|||
@ -0,0 +1,969 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <powah_emit.hpp>
|
|||
#include <fmt/ostream.h>
|
|||
|
|||
#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<IR::Opcode::Pack2x32To1x64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::Pack2x64To1x128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::LeastSignificantWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
/*
|
|||
uint64_t f(uint64_t a) { return (uint16_t)a; } |
|||
*/ |
|||
template<> |
|||
void EmitIR<IR::Opcode::LeastSignificantHalf>(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<IR::Opcode::LeastSignificantByte>(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<IR::Opcode::MostSignificantWord>(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<IR::Opcode::MostSignificantBit>(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<IR::Opcode::IsZero32>(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<IR::Opcode::IsZero64>(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<IR::Opcode::TestBit>(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<IR::Opcode::ConditionalSelect32>(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<IR::Opcode::ConditionalSelect64>(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<IR::Opcode::ConditionalSelectNZCV>(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<IR::Opcode::LogicalShiftLeft32>(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<IR::Opcode::LogicalShiftLeft64>(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<IR::Opcode::LogicalShiftRight32>(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<IR::Opcode::LogicalShiftRight64>(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<IR::Opcode::ArithmeticShiftRight32>(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<IR::Opcode::ArithmeticShiftRight64>(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<IR::Opcode::RotateRight32>(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<IR::Opcode::RotateRight64>(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<IR::Opcode::RotateRightExtended>(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<IR::Opcode::LogicalShiftLeftMasked32>(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<IR::Opcode::LogicalShiftLeftMasked64>(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<IR::Opcode::LogicalShiftRightMasked32>(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<IR::Opcode::LogicalShiftRightMasked64>(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<IR::Opcode::ArithmeticShiftRightMasked32>(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<IR::Opcode::ArithmeticShiftRightMasked64>(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<IR::Opcode::RotateRightMasked32>(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<IR::Opcode::RotateRightMasked64>(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<IR::Opcode::Add32>(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<IR::Opcode::Add64>(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<IR::Opcode::Sub32>(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<IR::Opcode::Sub64>(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<IR::Opcode::Mul32>(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<IR::Opcode::Mul64>(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<IR::Opcode::SignedMultiplyHigh64>(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<IR::Opcode::UnsignedMultiplyHigh64>(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<IR::Opcode::UnsignedDiv32>(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<IR::Opcode::UnsignedDiv64>(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<IR::Opcode::SignedDiv32>(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<IR::Opcode::SignedDiv64>(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<IR::Opcode::And32>(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<IR::Opcode::And64>(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<IR::Opcode::AndNot32>(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<IR::Opcode::AndNot64>(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<IR::Opcode::Eor32>(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<IR::Opcode::Eor64>(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<IR::Opcode::Or32>(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<IR::Opcode::Or64>(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<IR::Opcode::Not32>(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<IR::Opcode::Not64>(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<IR::Opcode::SignExtendByteToWord>(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<IR::Opcode::SignExtendHalfToWord>(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<IR::Opcode::SignExtendByteToLong>(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<IR::Opcode::SignExtendHalfToLong>(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<IR::Opcode::SignExtendWordToLong>(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<IR::Opcode::ZeroExtendByteToWord>(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<IR::Opcode::ZeroExtendHalfToWord>(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<IR::Opcode::ZeroExtendByteToLong>(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<IR::Opcode::ZeroExtendHalfToLong>(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<IR::Opcode::ZeroExtendWordToLong>(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<IR::Opcode::ZeroExtendLongToQuad>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
// __builtin_bswap32
|
|||
template<> |
|||
void EmitIR<IR::Opcode::ByteReverseWord>(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<IR::Opcode::ByteReverseHalf>(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<IR::Opcode::ByteReverseDual>(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<IR::Opcode::CountLeadingZeros32>(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<IR::Opcode::CountLeadingZeros64>(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<IR::Opcode::ExtractRegister32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::ExtractRegister64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::ReplicateBit32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::ReplicateBit64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::MaxSigned32>(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<IR::Opcode::MaxSigned64>(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<IR::Opcode::MaxUnsigned32>(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<IR::Opcode::MaxUnsigned64>(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<IR::Opcode::MinSigned32>(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<IR::Opcode::MinSigned64>(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<IR::Opcode::MinUnsigned32>(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<IR::Opcode::MinUnsigned64>(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
|
|||
@ -0,0 +1,458 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <powah_emit.hpp>
|
|||
#include <fmt/ostream.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<IR::Opcode::FPAbs16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPAbs32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPAbs64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPAdd32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPAdd64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPCompare32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPCompare64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDiv32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDiv64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMax32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMax64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMaxNumeric32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMaxNumeric64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMin32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMin64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMinNumeric32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMinNumeric64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMul32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMul64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulAdd16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulAdd32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulAdd64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulSub16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulSub32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulSub64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulX32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPMulX64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPNeg16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPNeg32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPNeg64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipEstimate16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipEstimate32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipEstimate64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipExponent16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipExponent32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipExponent64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipStepFused16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipStepFused32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRecipStepFused64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRoundInt16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRoundInt32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRoundInt64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRSqrtEstimate16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRSqrtEstimate32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRSqrtEstimate64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRSqrtStepFused16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRSqrtStepFused32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPRSqrtStepFused64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSqrt32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSqrt64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSub32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSub64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToHalf>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToHalf>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPDoubleToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPHalfToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPSingleToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedU16ToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedS16ToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedU16ToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedS16ToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedU32ToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedS32ToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedU32ToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedS32ToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedU64ToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedU64ToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedS64ToDouble>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::FPFixedS64ToSingle>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
} // namespace Dynarmic::Backend::RV64
|
|||
@ -0,0 +1,380 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include <powah_emit.hpp>
|
|||
#include <fmt/ostream.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<IR::Opcode::SignedSaturatedAddWithFlag32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedSubWithFlag32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturation>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturation>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedAdd8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedAdd16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedAdd32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedAdd64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedSub8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedSub16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedSub32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SignedSaturatedSub64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedSub8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedSub16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedSub32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::UnsignedSaturatedSub64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
// Packed
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAddU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAddS8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSubU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSubS8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAddU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAddS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSubU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSubS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAddSubU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAddSubS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSubAddU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSubAddS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingAddU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingAddS8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingSubU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingSubS8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingAddU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingAddS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingSubU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingSubS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingAddSubU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingAddSubS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingSubAddU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedHalvingSubAddS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedAddU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedAddS8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedSubU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedSubS8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedAddU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedAddS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedSubU16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSaturatedSubS16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedAbsDiffSumU8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::PackedSelect>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
// Crypto
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32Castagnoli8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32Castagnoli16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32Castagnoli32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32Castagnoli64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32ISO8>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32ISO16>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32ISO32>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::CRC32ISO64>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::AESDecryptSingleRound>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::AESEncryptSingleRound>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::AESInverseMixColumns>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::AESMixColumns>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SM4AccessSubstitutionBox>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SHA256Hash>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SHA256MessageSchedule0>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
template<> |
|||
void EmitIR<IR::Opcode::SHA256MessageSchedule1>(powah::Context&, EmitContext&, IR::Inst*) { |
|||
UNREACHABLE(); |
|||
} |
|||
|
|||
} // namespace Dynarmic::Backend::RV64
|
|||
1810
src/dynarmic/src/dynarmic/backend/ppc64/emit_ppc64_vector.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -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 <algorithm>
|
|||
#include <array>
|
|||
|
|||
#include "dynarmic/common/assert.h"
|
|||
#include <mcl/mp/metavalue/lift_value.hpp>
|
|||
#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<HostLocInfo, 32>& regs, const std::vector<u32>& 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<u32> 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<HostLoc> 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<u32>(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<u32>(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<u32>(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<std::initializer_list<HostLoc>> 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
|
|||
@ -0,0 +1,114 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <optional> |
|||
#include <random> |
|||
#include <utility> |
|||
#include <vector> |
|||
|
|||
#include <powah_emit.hpp> |
|||
#include "dynarmic/common/assert.h" |
|||
#include "dynarmic/common/common_types.h" |
|||
#include <ankerl/unordered_dense.h> |
|||
|
|||
#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<Argument>; |
|||
|
|||
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<const IR::Inst*> 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<Argument, IR::max_arg_count>; |
|||
|
|||
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<std::initializer_list<HostLoc>> 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<HostLocInfo, 32>& regs, const std::vector<u32>& order) const; |
|||
void SpillGpr(u32 index); |
|||
void SpillFpr(u32 index); |
|||
u32 FindFreeSpill() const; |
|||
|
|||
std::optional<HostLoc> ValueLocation(const IR::Inst* value) const; |
|||
HostLocInfo& ValueInfo(HostLoc host_loc); |
|||
HostLocInfo& ValueInfo(const IR::Inst* value); |
|||
|
|||
powah::Context& as; |
|||
std::array<HostLocInfo, 32> gprs; |
|||
std::array<HostLocInfo, 32> fprs; |
|||
std::array<HostLocInfo, SpillCount> spills; |
|||
}; |
|||
|
|||
} // namespace Dynarmic::Backend::RV64 |
|||
@ -0,0 +1,28 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
|
|||
#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<u64, SpillCount> spill; |
|||
|
|||
u32 save_host_fpcr; |
|||
u32 save_host_fpsr; |
|||
|
|||
bool check_bit; |
|||
}; |
|||
|
|||
static_assert(sizeof(StackLayout) % 16 == 0); |
|||
|
|||
} // namespace Dynarmic::Backend::RV64 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue