[dynarmic] lea over mov and other stuff (#24)

Co-authored-by: Esther1024 <danishreyjavik@outlook.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/24
Co-authored-by: Ghost <>
Co-committed-by: Ghost <>
This commit is contained in:
Ghost 2025-07-13 23:03:26 +02:00 • committed by crueter
commit fe4f5a3860
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
54 changed files with 3894 additions and 4269 deletions

1
.gitignore vendored
View file

@ -33,6 +33,7 @@ CMakeLists.txt.user*
# Visual Studio CMake settings
CMakeSettings.json
.cache/
# OSX global filetypes
# Created by Finder or Spotlight in directories for various OS functionality (indexing, etc)

View file

@ -98,8 +98,7 @@ else()
-Wextra
-Wcast-qual
-pedantic
-Wno-missing-braces
-Wstack-usage=4096)
-Wno-missing-braces)
if (ARCHITECTURE STREQUAL "x86_64")
list(APPEND DYNARMIC_CXX_FLAGS -mtune=core2)
@ -123,12 +122,15 @@ else()
# GCC knows that the variable is actually a Reg64. isMEM() will never return true for a
# Reg64, but GCC doesn't know that.
list(APPEND DYNARMIC_CXX_FLAGS -Wno-array-bounds)
list(APPEND DYNARMIC_CXX_FLAGS -Wstack-usage=4096)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
# And this in turns limits the size of a std::array.
list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024)
# Clang mistakenly blames CMake for using unused arguments during compilation
list(APPEND DYNARMIC_CXX_FLAGS -Wno-unused-command-line-argument)
endif()
endif()

View file

@ -125,52 +125,6 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/translate/a32_translate.h
frontend/A32/translate/conditional_state.cpp
frontend/A32/translate/conditional_state.h
frontend/A32/translate/impl/a32_branch.cpp
frontend/A32/translate/impl/a32_crc32.cpp
frontend/A32/translate/impl/a32_exception_generating.cpp
frontend/A32/translate/impl/a32_translate_impl.cpp
frontend/A32/translate/impl/a32_translate_impl.h
frontend/A32/translate/impl/asimd_load_store_structures.cpp
frontend/A32/translate/impl/asimd_misc.cpp
frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp
frontend/A32/translate/impl/asimd_three_regs.cpp
frontend/A32/translate/impl/asimd_two_regs_misc.cpp
frontend/A32/translate/impl/asimd_two_regs_scalar.cpp
frontend/A32/translate/impl/asimd_two_regs_shift.cpp
frontend/A32/translate/impl/barrier.cpp
frontend/A32/translate/impl/coprocessor.cpp
frontend/A32/translate/impl/data_processing.cpp
frontend/A32/translate/impl/divide.cpp
frontend/A32/translate/impl/extension.cpp
frontend/A32/translate/impl/hint.cpp
frontend/A32/translate/impl/load_store.cpp
frontend/A32/translate/impl/misc.cpp
frontend/A32/translate/impl/multiply.cpp
frontend/A32/translate/impl/packing.cpp
frontend/A32/translate/impl/parallel.cpp
frontend/A32/translate/impl/reversal.cpp
frontend/A32/translate/impl/saturated.cpp
frontend/A32/translate/impl/status_register_access.cpp
frontend/A32/translate/impl/synchronization.cpp
frontend/A32/translate/impl/thumb16.cpp
frontend/A32/translate/impl/thumb32_branch.cpp
frontend/A32/translate/impl/thumb32_control.cpp
frontend/A32/translate/impl/thumb32_coprocessor.cpp
frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp
frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp
frontend/A32/translate/impl/thumb32_data_processing_register.cpp
frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp
frontend/A32/translate/impl/thumb32_load_byte.cpp
frontend/A32/translate/impl/thumb32_load_halfword.cpp
frontend/A32/translate/impl/thumb32_load_store_dual.cpp
frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
frontend/A32/translate/impl/thumb32_load_word.cpp
frontend/A32/translate/impl/thumb32_long_multiply.cpp
frontend/A32/translate/impl/thumb32_misc.cpp
frontend/A32/translate/impl/thumb32_multiply.cpp
frontend/A32/translate/impl/thumb32_parallel.cpp
frontend/A32/translate/impl/thumb32_store_single_data_item.cpp
frontend/A32/translate/impl/vfp.cpp
frontend/A32/translate/translate_arm.cpp
frontend/A32/translate/translate_thumb.cpp
interface/A32/a32.h
@ -194,65 +148,6 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS)
frontend/A64/decoder/a64.inc
frontend/A64/translate/a64_translate.cpp
frontend/A64/translate/a64_translate.h
frontend/A64/translate/impl/a64_branch.cpp
frontend/A64/translate/impl/a64_exception_generating.cpp
frontend/A64/translate/impl/data_processing_addsub.cpp
frontend/A64/translate/impl/data_processing_bitfield.cpp
frontend/A64/translate/impl/data_processing_conditional_compare.cpp
frontend/A64/translate/impl/data_processing_conditional_select.cpp
frontend/A64/translate/impl/data_processing_crc32.cpp
frontend/A64/translate/impl/data_processing_logical.cpp
frontend/A64/translate/impl/data_processing_multiply.cpp
frontend/A64/translate/impl/data_processing_pcrel.cpp
frontend/A64/translate/impl/data_processing_register.cpp
frontend/A64/translate/impl/data_processing_shift.cpp
frontend/A64/translate/impl/floating_point_compare.cpp
frontend/A64/translate/impl/floating_point_conditional_compare.cpp
frontend/A64/translate/impl/floating_point_conditional_select.cpp
frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp
frontend/A64/translate/impl/floating_point_conversion_integer.cpp
frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp
frontend/A64/translate/impl/floating_point_data_processing_three_register.cpp
frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp
frontend/A64/translate/impl/impl.cpp
frontend/A64/translate/impl/impl.h
frontend/A64/translate/impl/load_store_exclusive.cpp
frontend/A64/translate/impl/load_store_load_literal.cpp
frontend/A64/translate/impl/load_store_multiple_structures.cpp
frontend/A64/translate/impl/load_store_no_allocate_pair.cpp
frontend/A64/translate/impl/load_store_register_immediate.cpp
frontend/A64/translate/impl/load_store_register_pair.cpp
frontend/A64/translate/impl/load_store_register_register_offset.cpp
frontend/A64/translate/impl/load_store_register_unprivileged.cpp
frontend/A64/translate/impl/load_store_single_structure.cpp
frontend/A64/translate/impl/move_wide.cpp
frontend/A64/translate/impl/simd_across_lanes.cpp
frontend/A64/translate/impl/simd_aes.cpp
frontend/A64/translate/impl/simd_copy.cpp
frontend/A64/translate/impl/simd_crypto_four_register.cpp
frontend/A64/translate/impl/simd_crypto_three_register.cpp
frontend/A64/translate/impl/simd_extract.cpp
frontend/A64/translate/impl/simd_modified_immediate.cpp
frontend/A64/translate/impl/simd_permute.cpp
frontend/A64/translate/impl/simd_scalar_pairwise.cpp
frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp
frontend/A64/translate/impl/simd_scalar_three_same.cpp
frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp
frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp
frontend/A64/translate/impl/simd_sha.cpp
frontend/A64/translate/impl/simd_sha512.cpp
frontend/A64/translate/impl/simd_shift_by_immediate.cpp
frontend/A64/translate/impl/simd_table_lookup.cpp
frontend/A64/translate/impl/simd_three_different.cpp
frontend/A64/translate/impl/simd_three_same.cpp
frontend/A64/translate/impl/simd_three_same_extra.cpp
frontend/A64/translate/impl/simd_two_register_misc.cpp
frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp
frontend/A64/translate/impl/sys_dc.cpp
frontend/A64/translate/impl/sys_ic.cpp
frontend/A64/translate/impl/system.cpp
frontend/A64/translate/impl/system_flag_format.cpp
frontend/A64/translate/impl/system_flag_manipulation.cpp
interface/A64/a64.h
interface/A64/config.h
ir/opt/a64_callback_config_pass.cpp

View file

@ -59,13 +59,12 @@ constexpr RegisterList ToRegList(oaknut::Reg reg) {
}
if (reg.index() == 31) {
throw std::out_of_range("ZR not allowed in reg list");
ASSERT_FALSE("ZR not allowed in reg list");
}
if (reg.index() == -1) {
return RegisterList{1} << 31;
}
return RegisterList{1} << reg.index();
}

View file

@ -14,29 +14,26 @@ namespace Dynarmic::Backend::RV64 {
class CodeBlock {
public:
explicit CodeBlock(std::size_t size)
: memsize(size) {
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);
if (mem == nullptr)
throw std::bad_alloc{};
ASSERT_FALSE("out of memory");
}
~CodeBlock() {
~CodeBlock() noexcept {
if (mem == nullptr)
return;
munmap(mem, memsize);
}
template<typename T>
T ptr() const {
T ptr() const noexcept {
static_assert(std::is_pointer_v<T> || std::is_same_v<T, uptr> || std::is_same_v<T, sptr>);
return reinterpret_cast<T>(mem);
}
protected:
u8* mem;
u8* mem = nullptr;
size_t memsize = 0;
};
} // namespace Dynarmic::Backend::RV64

View file

@ -124,35 +124,36 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
EmitCondPrelude(ctx);
for (auto iter = block.begin(); iter != block.end(); ++iter) {
IR::Inst* inst = &*iter;
// Call the relevant Emit* member function.
switch (inst->GetOpcode()) {
#define OPCODE(name, type, ...) \
case IR::Opcode::name: \
A32EmitX64::Emit##name(ctx, inst); \
break;
#define A32OPC(name, type, ...) \
case IR::Opcode::A32##name: \
A32EmitX64::EmitA32##name(ctx, inst); \
break;
auto const loop_all_inst = [this, &block, &ctx](auto const func) {
for (auto iter = block.begin(); iter != block.end(); ++iter) [[likely]] {
auto* inst = &*iter;
// Call the relevant Emit* member function.
switch (inst->GetOpcode()) {
#define OPCODE(name, type, ...) \
case IR::Opcode::name: \
A32EmitX64::Emit##name(ctx, inst); \
break;
#define A32OPC(name, type, ...) \
case IR::Opcode::A32##name: \
A32EmitX64::EmitA32##name(ctx, inst);\
break;
#define A64OPC(...)
#include "dynarmic/ir/opcodes.inc"
#undef OPCODE
#undef A32OPC
#undef A64OPC
default:
ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode());
break;
default: [[unlikely]] ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode());
}
reg_alloc.EndOfAllocScope();
func(reg_alloc);
}
reg_alloc.EndOfAllocScope();
if (conf.very_verbose_debugging_output) {
};
if (!conf.very_verbose_debugging_output) [[likely]] {
loop_all_inst([](auto&) { /*noop*/ });
} else [[unlikely]] {
loop_all_inst([this](auto& reg_alloc) {
EmitVerboseDebuggingOutput(reg_alloc);
}
});
}
reg_alloc.AssertNoMoreUses();
@ -229,7 +230,7 @@ void A32EmitX64::GenTerminalHandlers() {
terminal_handler_pop_rsb_hint = code.getCurr<const void*>();
calculate_location_descriptor();
code.mov(eax, dword[r15 + offsetof(A32JitState, rsb_ptr)]);
code.sub(eax, 1);
code.dec(eax);
code.and_(eax, u32(A32JitState::RSBPtrMask));
code.mov(dword[r15 + offsetof(A32JitState, rsb_ptr)], eax);
code.cmp(rbx, qword[r15 + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]);

View file

@ -198,18 +198,19 @@ void A64EmitX64::GenTerminalHandlers() {
code.or_(rbx, rcx);
};
Xbyak::Label fast_dispatch_cache_miss, rsb_cache_miss;
Xbyak::Label fast_dispatch_cache_miss;
Xbyak::Label rsb_cache_miss;
code.align();
terminal_handler_pop_rsb_hint = code.getCurr<const void*>();
calculate_location_descriptor();
code.mov(eax, dword[r15 + offsetof(A64JitState, rsb_ptr)]);
code.sub(eax, 1);
code.dec(eax);
code.and_(eax, u32(A64JitState::RSBPtrMask));
code.mov(dword[r15 + offsetof(A64JitState, rsb_ptr)], eax);
code.cmp(rbx, qword[r15 + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]);
if (conf.HasOptimization(OptimizationFlag::FastDispatch)) {
code.jne(rsb_cache_miss);
code.jne(rsb_cache_miss, code.T_NEAR);
} else {
code.jne(code.GetReturnFromRunCodeAddress());
}

View file

@ -33,13 +33,13 @@ void A64EmitX64::GenMemory128Accessors() {
#ifdef _WIN32
Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCallWithReturnPointer(code, [&](Xbyak::Reg64 return_value_ptr, [[maybe_unused]] RegList args) {
code.mov(code.ABI_PARAM3, code.ABI_PARAM2);
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (8 + 16 + ABI_SHADOW_SPACE)]);
code.lea(return_value_ptr, ptr[rsp + ABI_SHADOW_SPACE]);
});
code.movups(xmm1, xword[code.ABI_RETURN]);
code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE);
#else
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCall(code);
if (code.HasHostFeature(HostFeature::SSE41)) {
code.movq(xmm1, code.ABI_RETURN);
@ -57,13 +57,13 @@ void A64EmitX64::GenMemory128Accessors() {
code.align();
memory_write_128 = code.getCurr<void (*)()>();
#ifdef _WIN32
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (8 + 16 + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
code.movaps(xword[code.ABI_PARAM3], xmm1);
Devirtualize<&A64::UserCallbacks::MemoryWrite128>(conf.callbacks).EmitCall(code);
code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE);
#else
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
if (code.HasHostFeature(HostFeature::SSE41)) {
code.movq(code.ABI_PARAM3, xmm1);
code.pextrq(code.ABI_PARAM4, xmm1, 1);
@ -81,7 +81,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.align();
memory_exclusive_write_128 = code.getCurr<void (*)()>();
#ifdef _WIN32
code.sub(rsp, 8 + 32 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (8 + 32 + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
code.lea(code.ABI_PARAM4, ptr[rsp + ABI_SHADOW_SPACE + 16]);
code.movaps(xword[code.ABI_PARAM3], xmm1);
@ -89,7 +89,7 @@ void A64EmitX64::GenMemory128Accessors() {
Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive128>(conf.callbacks).EmitCall(code);
code.add(rsp, 8 + 32 + ABI_SHADOW_SPACE);
#else
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
if (code.HasHostFeature(HostFeature::SSE41)) {
code.movq(code.ABI_PARAM3, xmm1);
code.pextrq(code.ABI_PARAM4, xmm1, 1);
@ -131,8 +131,8 @@ void A64EmitX64::GenFastmemFallbacks() {
{64, Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive64>(conf.callbacks)},
}};
for (bool ordered : {false, true}) {
for (int vaddr_idx : idxes) {
for (auto const ordered : {false, true}) {
for (auto const vaddr_idx : idxes) {
if (vaddr_idx == 4 || vaddr_idx == 15) {
continue;
}

View file

@ -63,7 +63,8 @@ public:
uint8_t* alloc(size_t size) override {
void* p = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
if (p == nullptr) {
throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC);
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
}
return static_cast<uint8_t*>(p);
}
@ -95,7 +96,8 @@ public:
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0);
if (p == MAP_FAILED) {
throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC);
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
}
std::memcpy(p, &size, sizeof(size_t));
return static_cast<uint8_t*>(p) + DYNARMIC_PAGE_SIZE;
@ -514,7 +516,8 @@ size_t BlockOfCode::GetTotalCodeSize() const {
void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) {
if (size_ + alloc_size >= maxSize_) {
throw Xbyak::Error(Xbyak::ERR_CODE_IS_TOO_BIG);
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CODE_IS_TOO_BIG);
}
EnsureMemoryCommitted(alloc_size);

View file

@ -104,7 +104,7 @@ void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, I
}
void EmitX64::EmitVerboseDebuggingOutput(RegAlloc& reg_alloc) {
code.sub(rsp, sizeof(RegisterData));
code.lea(rsp, ptr[rsp - sizeof(RegisterData)]);
code.stmxcsr(dword[rsp + offsetof(RegisterData, mxcsr)]);
for (int i = 0; i < 16; i++) {
if (rsp.getIdx() == i) {
@ -223,7 +223,7 @@ void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize);
code.test(value, value);
code.lahf();
code.mov(al, 0);
code.xor_(al, al);
ctx.reg_alloc.DefineValue(inst, nzcv);
}
@ -270,7 +270,6 @@ void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) {
code.shr(nzcv, 28);
code.imul(nzcv, nzcv, NZCV::to_x64_multiplier);
code.and_(nzcv, NZCV::x64_mask);
ctx.reg_alloc.DefineValue(inst, nzcv);
}
}
@ -331,10 +330,8 @@ Xbyak::Label EmitX64::EmitCond(IR::Cond cond) {
code.jle(pass);
break;
default:
ASSERT_MSG(false, "Unknown cond {}", static_cast<size_t>(cond));
break;
UNREACHABLE();
}
return pass;
}

View file

@ -992,7 +992,6 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
code.seto(overflow);
ctx.reg_alloc.DefineValue(overflow_inst, overflow);
}
ctx.reg_alloc.DefineValue(inst, result);
}

View file

@ -33,6 +33,23 @@
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
@ -60,23 +77,6 @@ constexpr u64 f64_max_s32 = 0x41dfffffffc00000u; // 2147483647 as a double
constexpr u64 f64_max_u32 = 0x41efffffffe00000u; // 4294967295 as a double
constexpr u64 f64_max_s64_lim = 0x43e0000000000000u; // 2^63 as a double (actual maximum unrepresentable)
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
template<size_t fsize>
void ForceDenormalsToZero(BlockOfCode& code, std::initializer_list<Xbyak::Xmm> to_daz) {
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
@ -473,7 +473,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
}
template<size_t fsize, bool is_max>
static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) noexcept {
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT default_nan = FP::FPInfo<FPT>::DefaultNaN();
@ -701,15 +701,14 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
// x64 rounds before flushing to zero
// AArch64 rounds after flushing to zero
// This difference of behaviour is noticable if something would round to a smallest normalized number
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
code.movq(code.ABI_PARAM3, operand3);
code.mov(code.ABI_PARAM4.cvt32(), ctx.FPCR().Value());
#ifdef _WIN32
code.sub(rsp, 16 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (16 + ABI_SHADOW_SPACE)]);
code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.mov(qword[rsp + ABI_SHADOW_SPACE], rax);
code.CallFunction(fallback_fn);
@ -735,13 +734,13 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.vmovaps(xmm0, code.Const(xword, FP::FPInfo<FPT>::mantissa_msb));
FCODE(ucomis)(operand2, operand3);
code.jp(has_nan);
code.jp(has_nan, code.T_NEAR);
FCODE(ucomis)(operand1, operand1);
code.jnp(indeterminate);
code.jnp(indeterminate, code.T_NEAR);
// AArch64 specifically emits a default NaN for the case when the addend is a QNaN and the two other arguments are {inf, zero}
code.ptest(operand1, xmm0);
code.jz(op1_snan);
code.jz(op1_snan, code.T_NEAR);
FCODE(vmuls)(xmm0, operand2, operand3); // check if {op2, op3} are {inf, zero}/{zero, inf}
FCODE(ucomis)(xmm0, xmm0);
code.jnp(*end);
@ -753,10 +752,10 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.L(has_nan);
FCODE(ucomis)(operand1, operand1);
code.jnp(op1_done);
code.jnp(op1_done, code.T_NEAR);
code.movaps(result, operand1); // this is done because of NaN behavior of vfmadd231s (priority of op2, op3, op1)
code.ptest(operand1, xmm0);
code.jnz(op1_done);
code.jnz(op1_done, code.T_NEAR);
code.L(op1_snan);
code.vorps(result, operand1, xmm0);
code.jmp(*end);
@ -774,9 +773,9 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.L(op2_done);
FCODE(ucomis)(operand3, operand3);
code.jnp(op3_done);
code.jnp(op3_done, code.T_NEAR);
code.ptest(operand3, xmm0);
code.jnz(op3_done);
code.jnz(op3_done, code.T_NEAR);
code.vorps(result, operand3, xmm0);
code.jmp(*end);
code.L(op3_done);
@ -1019,7 +1018,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
@ -1204,9 +1203,9 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
}
// a > 0 && a < 0x00800000;
code.sub(tmp, 1);
code.dec(tmp);
code.cmp(tmp, 0x007FFFFF);
code.jb(fallback);
code.jb(fallback, code.T_NEAR); //within -127,128
needs_fallback = true;
}
@ -1235,17 +1234,17 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
code.ucomisd(value, result);
if (ctx.FPCR().DN()) {
code.jc(default_nan);
code.je(zero);
code.jc(default_nan, code.T_NEAR);
code.je(zero, code.T_NEAR);
} else {
code.jp(nan);
code.je(zero);
code.jc(default_nan);
code.jp(nan, code.T_NEAR);
code.je(zero, code.T_NEAR);
code.jc(default_nan, code.T_NEAR);
}
if (!ctx.FPCR().FZ()) {
needs_fallback = true;
code.jmp(fallback);
code.jmp(fallback, code.T_NEAR);
} else {
// result = 0
code.jmp(*end, code.T_NEAR);
@ -1278,7 +1277,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
code.L(fallback);
if (needs_fallback) {
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
@ -1361,7 +1360,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
@ -2132,3 +2131,6 @@ void EmitX64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
} // namespace Dynarmic::Backend::X64
#undef FCODE
#undef ICODE

View file

@ -161,8 +161,7 @@ template<>
template<>
[[maybe_unused]] Xbyak::RegExp EmitFastmemVAddr<A64EmitContext>(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling, std::optional<Xbyak::Reg64> tmp) {
const size_t unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits;
auto const unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits;
if (unused_top_bits == 0) {
return r13 + vaddr;
} else if (ctx.conf.silently_mirror_fastmem) {
@ -306,7 +305,7 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int
code.L(loop);
code.lock();
code.cmpxchg16b(xword[addr]);
code.jnz(loop);
code.jnz(loop, code.T_NEAR);
break;
}
default:
@ -373,7 +372,7 @@ void EmitExclusiveTestAndClear(BlockOfCode& code, const UserConfig& conf, Xbyak:
Xbyak::Label ok;
code.mov(pointer, mcl::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, processor_index)));
code.cmp(qword[pointer], vaddr);
code.jne(ok);
code.jne(ok, code.T_NEAR);
code.mov(qword[pointer], tmp);
code.L(ok);
}

View file

@ -33,13 +33,6 @@
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
namespace mp = mcl::mp;
namespace {
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
@ -57,6 +50,13 @@ namespace {
} \
}
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
namespace mp = mcl::mp;
namespace {
template<typename Lambda>
void MaybeStandardFPSCRValue(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, Lambda lambda) {
const bool switch_mxcsr = ctx.FPCR(fpcr_controlled) != ctx.FPCR();
@ -122,11 +122,11 @@ void HandleNaNs(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, std::
const Xbyak::Xmm result = xmms[0];
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
const size_t stack_space = xmms.size() * 16;
code.sub(rsp, static_cast<u32>(stack_space + ABI_SHADOW_SPACE));
code.lea(rsp, ptr[rsp - static_cast<u32>(stack_space + ABI_SHADOW_SPACE)]);
for (size_t i = 0; i < xmms.size(); ++i) {
code.movaps(xword[rsp + ABI_SHADOW_SPACE + i * 16], xmms[i]);
}
@ -443,7 +443,7 @@ void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak
const u32 fpcr = ctx.FPCR(fpcr_controlled).Value();
constexpr u32 stack_space = 2 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.mov(code.ABI_PARAM3.cvt32(), fpcr);
@ -479,7 +479,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby
#ifdef _WIN32
constexpr u32 stack_space = 4 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]);
@ -488,7 +488,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby
code.mov(qword[rsp + ABI_SHADOW_SPACE + 0], rax);
#else
constexpr u32 stack_space = 3 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
@ -536,7 +536,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya
#ifdef _WIN32
constexpr u32 stack_space = 5 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]);
@ -546,7 +546,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya
code.mov(qword[rsp + ABI_SHADOW_SPACE + 8], rax);
#else
constexpr u32 stack_space = 4 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
@ -1371,7 +1371,7 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
if (needs_rounding_correction && needs_nan_correction) {
EmitFourOpFallbackWithoutRegAlloc<LoadPreviousResult::Yes>(code, ctx, result, xmm_a, xmm_b, xmm_c, EmitFPVectorMulAddFallback<FPT, true, true>, fpcr_controlled);
@ -1635,7 +1635,7 @@ static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
@ -1812,7 +1812,7 @@ static void EmitRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* ins
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*bad_values);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitTwoOpFallbackWithoutRegAlloc(code, ctx, result, operand, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
@ -1898,7 +1898,7 @@ static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
@ -2180,3 +2180,6 @@ void EmitX64::EmitFPVectorToUnsignedFixed64(EmitContext& ctx, IR::Inst* inst) {
}
} // namespace Dynarmic::Backend::X64
#undef FCODE
#undef ICODE

View file

@ -338,3 +338,6 @@ void EmitX64::EmitVectorUnsignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst)
}
} // namespace Dynarmic::Backend::X64
#undef FCODE
#undef ICODE

View file

@ -186,7 +186,7 @@ struct ExceptionHandler::Impl final {
code.cmp(code.rax, static_cast<u32>(code.GetTotalCodeSize()));
code.ja(exception_handler_without_cb);
code.sub(code.rsp, 8);
code.lea(code.rsp, code.ptr[code.rsp - 8]);
code.mov(code.ABI_PARAM1, mcl::bit_cast<u64>(&cb));
code.mov(code.ABI_PARAM2, code.ABI_PARAM3);
code.CallLambda(

View file

@ -15,7 +15,7 @@
namespace Dynarmic::A32 {
enum class ArchVersion;
enum class ArchVersion : std::uint8_t;
enum class CoprocReg;
enum class Exception;
enum class ExtReg;
@ -27,12 +27,11 @@ enum class Reg;
* The user of this class updates `current_location` as appropriate.
*/
class IREmitter : public IR::IREmitter {
IR::U64 ImmCurrentLocationDescriptor();
public:
IREmitter(IR::Block& block, LocationDescriptor descriptor, ArchVersion arch_version)
: IR::IREmitter(block), current_location(descriptor), arch_version(arch_version) {}
LocationDescriptor current_location;
size_t ArchVersion() const;
u32 PC() const;
@ -107,10 +106,9 @@ public:
IR::U64 CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm);
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
private:
public:
LocationDescriptor current_location;
enum ArchVersion arch_version;
IR::U64 ImmCurrentLocationDescriptor();
};
} // namespace Dynarmic::A32

View file

@ -33,13 +33,11 @@ inline size_t ToFastLookupIndexArm(u32 instruction) {
} // namespace detail
template<typename V>
ArmDecodeTable<V> GetArmDecodeTable() {
constexpr ArmDecodeTable<V> GetArmDecodeTable() {
std::vector<ArmMatcher<V>> list = {
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./arm.inc"
#undef INST
};
// If a matcher has more bits in its mask it is more specific, so it should come first.
@ -62,9 +60,10 @@ ArmDecodeTable<V> GetArmDecodeTable() {
template<typename V>
std::optional<std::reference_wrapper<const ArmMatcher<V>>> DecodeArm(u32 instruction) {
static const auto table = GetArmDecodeTable<V>();
const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); };
alignas(64) static const auto table = GetArmDecodeTable<V>();
const auto matches_instruction = [instruction](const auto& matcher) {
return matcher.Matches(instruction);
};
const auto& subtable = table[detail::ToFastLookupIndexArm(instruction)];
auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction);

View file

@ -25,3 +25,51 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
}
} // namespace Dynarmic::A32
// ls -l | awk '{print "#include \"dynarmic/frontend/A32/translate/impl/" $9 "\""}'
#include "dynarmic/frontend/A32/translate/impl/a32_branch.cpp"
#include "dynarmic/frontend/A32/translate/impl/a32_crc32.cpp"
#include "dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp"
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp"
//#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp"
#include "dynarmic/frontend/A32/translate/impl/barrier.cpp"
#include "dynarmic/frontend/A32/translate/impl/coprocessor.cpp"
#include "dynarmic/frontend/A32/translate/impl/data_processing.cpp"
#include "dynarmic/frontend/A32/translate/impl/divide.cpp"
#include "dynarmic/frontend/A32/translate/impl/extension.cpp"
#include "dynarmic/frontend/A32/translate/impl/hint.cpp"
#include "dynarmic/frontend/A32/translate/impl/load_store.cpp"
#include "dynarmic/frontend/A32/translate/impl/misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/multiply.cpp"
#include "dynarmic/frontend/A32/translate/impl/packing.cpp"
#include "dynarmic/frontend/A32/translate/impl/parallel.cpp"
#include "dynarmic/frontend/A32/translate/impl/reversal.cpp"
#include "dynarmic/frontend/A32/translate/impl/saturated.cpp"
#include "dynarmic/frontend/A32/translate/impl/status_register_access.cpp"
#include "dynarmic/frontend/A32/translate/impl/synchronization.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb16.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_control.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_long_multiply.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_store_single_data_item.cpp"
#include "dynarmic/frontend/A32/translate/impl/vfp.cpp"

View file

@ -11,6 +11,10 @@
namespace Dynarmic::A32 {
bool TranslatorVisitor::arm_NOP() {
return true;
}
bool TranslatorVisitor::ArmConditionPassed(Cond cond) {
return IsConditionPassed(*this, cond);
}

Some files were not shown because too many files have changed in this diff Show more