[dynarmic] lea over mov and other stuff (#24)
Some checks failed
eden-build / source (push) Successful in 6m48s
eden-build / android (push) Failing after 19m13s
eden-build / windows (msvc) (push) Failing after 23m32s
eden-build / linux (push) Successful in 27m51s

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
parent a0a208db57
commit fe4f5a3860
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
54 changed files with 3874 additions and 4249 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);
}

View file

@ -258,7 +258,7 @@ struct TranslatorVisitor final {
bool arm_CLZ(Cond cond, Reg d, Reg m);
bool arm_MOVT(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12);
bool arm_MOVW(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12);
bool arm_NOP() { return true; }
bool arm_NOP();
bool arm_RBIT(Cond cond, Reg d, Reg m);
bool arm_SBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n);
bool arm_SEL(Cond cond, Reg n, Reg d, Reg m);

View file

@ -6,6 +6,7 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
namespace {
@ -17,11 +18,6 @@ enum class Comparison {
AbsoluteGT,
};
enum class AccumulateBehavior {
None,
Accumulate,
};
enum class WidenBehaviour {
Second,
Both,

View file

@ -8,10 +8,11 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
namespace {
enum class Comparison {
enum class ComparisonATRM {
EQ,
GE,
GT,
@ -19,7 +20,7 @@ enum class Comparison {
LT,
};
bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, Comparison type) {
bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, ComparisonATRM type) {
if (sz == 0b11 || (F && sz != 0b10)) {
return v.UndefinedInstruction();
}
@ -36,15 +37,15 @@ bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F,
if (F) {
switch (type) {
case Comparison::EQ:
case ComparisonATRM::EQ:
return v.ir.FPVectorEqual(32, reg_m, zero, false);
case Comparison::GE:
case ComparisonATRM::GE:
return v.ir.FPVectorGreaterEqual(32, reg_m, zero, false);
case Comparison::GT:
case ComparisonATRM::GT:
return v.ir.FPVectorGreater(32, reg_m, zero, false);
case Comparison::LE:
case ComparisonATRM::LE:
return v.ir.FPVectorGreaterEqual(32, zero, reg_m, false);
case Comparison::LT:
case ComparisonATRM::LT:
return v.ir.FPVectorGreater(32, zero, reg_m, false);
}
@ -67,11 +68,6 @@ bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F,
return true;
}
enum class AccumulateBehavior {
None,
Accumulate,
};
bool PairedAddOperation(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool op, bool Q, bool M, size_t Vm, AccumulateBehavior accumulate) {
if (sz == 0b11) {
return v.UndefinedInstruction();
@ -385,23 +381,23 @@ bool TranslatorVisitor::asimd_VQNEG(bool D, size_t sz, size_t Vd, bool Q, bool M
}
bool TranslatorVisitor::asimd_VCGT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GT);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::GT);
}
bool TranslatorVisitor::asimd_VCGE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GE);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::GE);
}
bool TranslatorVisitor::asimd_VCEQ_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::EQ);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::EQ);
}
bool TranslatorVisitor::asimd_VCLE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LE);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::LE);
}
bool TranslatorVisitor::asimd_VCLT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LT);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::LT);
}
bool TranslatorVisitor::asimd_VABS(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {

View file

@ -16,7 +16,7 @@ enum class Accumulating {
Accumulate
};
enum class Rounding {
enum class RoundingATRS {
None,
Round,
};
@ -32,7 +32,7 @@ enum class Signedness {
Unsigned
};
IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) {
IR::U128 PerformRoundingATRSCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) {
const auto round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value));
const auto round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(original, round_const), round_const);
return v.ir.VectorSub(esize, shifted, round_correction);
@ -58,7 +58,7 @@ std::pair<size_t, size_t> ElementSizeAndShiftAmount(bool right_shift, bool L, si
}
}
bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, Accumulating accumulate, Rounding rounding) {
bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, Accumulating accumulate, RoundingATRS RoundingATRS) {
if (!L && mcl::bit::get_bits<3, 5>(imm6) == 0) {
return v.DecodeError();
}
@ -75,9 +75,9 @@ bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bo
auto result = U ? v.ir.VectorLogicalShiftRight(esize, reg_m, static_cast<u8>(shift_amount))
: v.ir.VectorArithmeticShiftRight(esize, reg_m, static_cast<u8>(shift_amount));
if (rounding == Rounding::Round) {
if (RoundingATRS == RoundingATRS::Round) {
const u64 round_value = 1ULL << (shift_amount - 1);
result = PerformRoundingCorrection(v, esize, round_value, reg_m, result);
result = PerformRoundingATRSCorrection(v, esize, round_value, reg_m, result);
}
if (accumulate == Accumulating::Accumulate) {
@ -89,7 +89,7 @@ bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bo
return true;
}
bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, bool M, size_t Vm, Rounding rounding, Narrowing narrowing, Signedness signedness) {
bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, bool M, size_t Vm, RoundingATRS RoundingATRS, Narrowing narrowing, Signedness signedness) {
if (mcl::bit::get_bits<3, 5>(imm6) == 0) {
return v.DecodeError();
}
@ -113,9 +113,9 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, b
return v.ir.VectorLogicalShiftRight(source_esize, reg_m, shift_amount);
}();
if (rounding == Rounding::Round) {
if (RoundingATRS == RoundingATRS::Round) {
const u64 round_value = 1ULL << (shift_amount - 1);
wide_result = PerformRoundingCorrection(v, source_esize, round_value, reg_m, wide_result);
wide_result = PerformRoundingATRSCorrection(v, source_esize, round_value, reg_m, wide_result);
}
const auto result = [&] {
@ -141,22 +141,22 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, b
bool TranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::None, Rounding::None);
Accumulating::None, RoundingATRS::None);
}
bool TranslatorVisitor::asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::Accumulate, Rounding::None);
Accumulating::Accumulate, RoundingATRS::None);
}
bool TranslatorVisitor::asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::None, Rounding::Round);
Accumulating::None, RoundingATRS::Round);
}
bool TranslatorVisitor::asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::Accumulate, Rounding::Round);
Accumulating::Accumulate, RoundingATRS::Round);
}
bool TranslatorVisitor::asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
@ -271,32 +271,32 @@ bool TranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool
bool TranslatorVisitor::asimd_VSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::None, Narrowing::Truncation, Signedness::Unsigned);
RoundingATRS::None, Narrowing::Truncation, Signedness::Unsigned);
}
bool TranslatorVisitor::asimd_VRSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::Round, Narrowing::Truncation, Signedness::Unsigned);
RoundingATRS::Round, Narrowing::Truncation, Signedness::Unsigned);
}
bool TranslatorVisitor::asimd_VQRSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Signed);
RoundingATRS::Round, Narrowing::SaturateToUnsigned, Signedness::Signed);
}
bool TranslatorVisitor::asimd_VQSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Signed);
RoundingATRS::None, Narrowing::SaturateToUnsigned, Signedness::Signed);
}
bool TranslatorVisitor::asimd_VQSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::None, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
RoundingATRS::None, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
}
bool TranslatorVisitor::asimd_VQRSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::Round, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
RoundingATRS::Round, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
}
bool TranslatorVisitor::asimd_VSHLL(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {

View file

@ -0,0 +1,31 @@
#pragma once
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 {
static inline IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) noexcept {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static inline IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) noexcept {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
static inline IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) noexcept {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
static inline bool ITBlockCheck(const A32::IREmitter& ir) noexcept {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
using ExtensionFunctionU16 = IR::U32 (IREmitter::*)(const IR::U16&);
enum class AccumulateBehavior {
None,
Accumulate,
};
}

View file

@ -4,14 +4,10 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
// SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
bool TranslatorVisitor::arm_SXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
if (d == Reg::PC || m == Reg::PC) {

View file

@ -4,17 +4,10 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
// Saturation instructions
// SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}

View file

@ -7,15 +7,9 @@
#include <mcl/bitsizeof.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
using SaturationFunction = IR::ResultAndOverflow<IR::U32> (IREmitter::*)(const IR::U32&, size_t);

View file

@ -4,13 +4,10 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
namespace {
IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
using ShiftFunction = IR::ResultAndCarry<IR::U32> (IREmitter::*)(const IR::U32&, const IR::U8&, const IR::U1&);

View file

@ -25,9 +25,9 @@ static bool PLIHandler(TranslatorVisitor& v) {
return v.RaiseException(Exception::PreloadInstruction);
}
using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U8&);
using ExtensionFunctionU8 = IR::U32 (IREmitter::*)(const IR::U8&);
static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunctionU8 ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const u32 base = v.ir.AlignPC(4);
const u32 address = U ? (base + imm32) : (base - imm32);
@ -37,7 +37,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
return true;
}
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunctionU8 ext_fn) {
if (m == Reg::PC) {
return v.UnpredictableInstruction();
}
@ -52,7 +52,7 @@ static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
return true;
}
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunctionU8 ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const IR::U32 reg_n = v.ir.GetRegister(n);
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))

View file

@ -4,12 +4,11 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U16&);
static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunctionU16 ext_fn) {
const auto imm32 = imm12.ZeroExtend();
const auto base = v.ir.AlignPC(4);
const auto address = U ? (base + imm32) : (base - imm32);
@ -19,7 +18,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
return true;
}
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunctionU16 ext_fn) {
if (m == Reg::PC) {
return v.UnpredictableInstruction();
}
@ -34,7 +33,7 @@ static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
return true;
}
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunctionU16 ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const IR::U32 reg_n = v.ir.GetRegister(n);
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))

View file

@ -6,11 +6,9 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) {
if (m == Reg::PC) {

View file

@ -6,11 +6,9 @@
#include <mcl/bit/bit_count.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
auto address = start_address;

View file

@ -4,11 +4,9 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) {
if (t == Reg::PC && ITBlockCheck(ir)) {

View file

@ -4,15 +4,9 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
bool TranslatorVisitor::thumb32_SADD8(Reg n, Reg d, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {

View file

@ -5,261 +5,7 @@
#include "dynarmic/frontend/A64/a64_ir_emitter.h"
#include <mcl/assert.hpp>
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::A64 {
using Opcode = IR::Opcode;
u64 IREmitter::PC() const {
return current_location->PC();
}
u64 IREmitter::AlignPC(size_t alignment) const {
const u64 pc = PC();
return static_cast<u64>(pc - pc % alignment);
}
void IREmitter::SetCheckBit(const IR::U1& value) {
Inst(Opcode::A64SetCheckBit, value);
}
IR::U1 IREmitter::GetCFlag() {
return Inst<IR::U1>(Opcode::A64GetCFlag);
}
IR::U32 IREmitter::GetNZCVRaw() {
return Inst<IR::U32>(Opcode::A64GetNZCVRaw);
}
void IREmitter::SetNZCVRaw(IR::U32 value) {
Inst(Opcode::A64SetNZCVRaw, value);
}
void IREmitter::SetNZCV(const IR::NZCV& nzcv) {
Inst(Opcode::A64SetNZCV, nzcv);
}
void IREmitter::CallSupervisor(u32 imm) {
Inst(Opcode::A64CallSupervisor, Imm32(imm));
}
void IREmitter::ExceptionRaised(Exception exception) {
Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast<u64>(exception)));
}
void IREmitter::DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) {
Inst(Opcode::A64DataCacheOperationRaised, ImmCurrentLocationDescriptor(), Imm64(static_cast<u64>(op)), value);
}
void IREmitter::InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) {
Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast<u64>(op)), value);
}
void IREmitter::DataSynchronizationBarrier() {
Inst(Opcode::A64DataSynchronizationBarrier);
}
void IREmitter::DataMemoryBarrier() {
Inst(Opcode::A64DataMemoryBarrier);
}
void IREmitter::InstructionSynchronizationBarrier() {
Inst(Opcode::A64InstructionSynchronizationBarrier);
}
IR::U32 IREmitter::GetCNTFRQ() {
return Inst<IR::U32>(Opcode::A64GetCNTFRQ);
}
IR::U64 IREmitter::GetCNTPCT() {
return Inst<IR::U64>(Opcode::A64GetCNTPCT);
}
IR::U32 IREmitter::GetCTR() {
return Inst<IR::U32>(Opcode::A64GetCTR);
}
IR::U32 IREmitter::GetDCZID() {
return Inst<IR::U32>(Opcode::A64GetDCZID);
}
IR::U64 IREmitter::GetTPIDR() {
return Inst<IR::U64>(Opcode::A64GetTPIDR);
}
void IREmitter::SetTPIDR(const IR::U64& value) {
Inst(Opcode::A64SetTPIDR, value);
}
IR::U64 IREmitter::GetTPIDRRO() {
return Inst<IR::U64>(Opcode::A64GetTPIDRRO);
}
void IREmitter::ClearExclusive() {
Inst(Opcode::A64ClearExclusive);
}
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A64ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U16>(Opcode::A64ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U64>(Opcode::A64ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U128>(Opcode::A64ReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::GetW(Reg reg) {
if (reg == Reg::ZR)
return Imm32(0);
return Inst<IR::U32>(Opcode::A64GetW, IR::Value(reg));
}
IR::U64 IREmitter::GetX(Reg reg) {
if (reg == Reg::ZR)
return Imm64(0);
return Inst<IR::U64>(Opcode::A64GetX, IR::Value(reg));
}
IR::U128 IREmitter::GetS(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetS, IR::Value(vec));
}
IR::U128 IREmitter::GetD(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetD, IR::Value(vec));
}
IR::U128 IREmitter::GetQ(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetQ, IR::Value(vec));
}
IR::U64 IREmitter::GetSP() {
return Inst<IR::U64>(Opcode::A64GetSP);
}
IR::U32 IREmitter::GetFPCR() {
return Inst<IR::U32>(Opcode::A64GetFPCR);
}
IR::U32 IREmitter::GetFPSR() {
return Inst<IR::U32>(Opcode::A64GetFPSR);
}
void IREmitter::SetW(const Reg reg, const IR::U32& value) {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetW, IR::Value(reg), value);
}
void IREmitter::SetX(const Reg reg, const IR::U64& value) {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetX, IR::Value(reg), value);
}
void IREmitter::SetS(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetS, IR::Value(vec), value);
}
void IREmitter::SetD(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetD, IR::Value(vec), value);
}
void IREmitter::SetQ(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetQ, IR::Value(vec), value);
}
void IREmitter::SetSP(const IR::U64& value) {
Inst(Opcode::A64SetSP, value);
}
void IREmitter::SetFPCR(const IR::U32& value) {
Inst(Opcode::A64SetFPCR, value);
}
void IREmitter::SetFPSR(const IR::U32& value) {
Inst(Opcode::A64SetFPSR, value);
}
void IREmitter::SetPC(const IR::U64& value) {
Inst(Opcode::A64SetPC, value);
}
IR::U64 IREmitter::ImmCurrentLocationDescriptor() {
return Imm64(IR::LocationDescriptor{*current_location}.Value());
}
} // namespace Dynarmic::A64

View file

@ -8,12 +8,14 @@
#include <optional>
#include <mcl/stdint.hpp>
#include <mcl/assert.hpp>
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/ir_emitter.h"
#include "dynarmic/ir/value.h"
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::A64 {
@ -24,79 +26,262 @@ namespace Dynarmic::A64 {
*/
class IREmitter : public IR::IREmitter {
public:
explicit IREmitter(IR::Block& block)
: IR::IREmitter(block) {}
explicit IREmitter(IR::Block& block, LocationDescriptor descriptor)
: IR::IREmitter(block), current_location(descriptor) {}
explicit IREmitter(IR::Block& block) : IR::IREmitter(block) {}
explicit IREmitter(IR::Block& block, LocationDescriptor descriptor) : IR::IREmitter(block), current_location(descriptor) {}
std::optional<LocationDescriptor> current_location;
u64 PC() const;
u64 AlignPC(size_t alignment) const;
using Opcode = IR::Opcode;
void SetCheckBit(const IR::U1& value);
IR::U1 GetCFlag();
IR::U32 GetNZCVRaw();
void SetNZCVRaw(IR::U32 value);
void SetNZCV(const IR::NZCV& nzcv);
u64 PC() const noexcept {
return current_location->PC();
}
void CallSupervisor(u32 imm);
void ExceptionRaised(Exception exception);
void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value);
void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value);
void DataSynchronizationBarrier();
void DataMemoryBarrier();
void InstructionSynchronizationBarrier();
IR::U32 GetCNTFRQ();
IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this.
IR::U32 GetCTR();
IR::U32 GetDCZID();
IR::U64 GetTPIDR();
IR::U64 GetTPIDRRO();
void SetTPIDR(const IR::U64& value);
u64 AlignPC(size_t alignment) const noexcept {
const u64 pc = PC();
return static_cast<u64>(pc - pc % alignment);
}
void ClearExclusive();
IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type);
IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type);
IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type);
IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type);
IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type);
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type);
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type);
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type);
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type);
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type);
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type);
void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type);
void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type);
void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type);
void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type);
void SetCheckBit(const IR::U1& value) noexcept {
Inst(Opcode::A64SetCheckBit, value);
}
IR::U32 GetW(Reg source_reg);
IR::U64 GetX(Reg source_reg);
IR::U128 GetS(Vec source_vec);
IR::U128 GetD(Vec source_vec);
IR::U128 GetQ(Vec source_vec);
IR::U64 GetSP();
IR::U32 GetFPCR();
IR::U32 GetFPSR();
void SetW(Reg dest_reg, const IR::U32& value);
void SetX(Reg dest_reg, const IR::U64& value);
void SetS(Vec dest_vec, const IR::U128& value);
void SetD(Vec dest_vec, const IR::U128& value);
void SetQ(Vec dest_vec, const IR::U128& value);
void SetSP(const IR::U64& value);
void SetFPCR(const IR::U32& value);
void SetFPSR(const IR::U32& value);
void SetPC(const IR::U64& value);
IR::U1 GetCFlag() noexcept {
return Inst<IR::U1>(Opcode::A64GetCFlag);
}
IR::U32 GetNZCVRaw() noexcept {
return Inst<IR::U32>(Opcode::A64GetNZCVRaw);
}
void SetNZCVRaw(IR::U32 value) noexcept {
Inst(Opcode::A64SetNZCVRaw, value);
}
void SetNZCV(const IR::NZCV& nzcv) noexcept {
Inst(Opcode::A64SetNZCV, nzcv);
}
void CallSupervisor(u32 imm) noexcept {
Inst(Opcode::A64CallSupervisor, Imm32(imm));
}
void ExceptionRaised(Exception exception) noexcept {
Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast<u64>(exception)));
}
void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) noexcept {
Inst(Opcode::A64DataCacheOperationRaised, ImmCurrentLocationDescriptor(), Imm64(static_cast<u64>(op)), value);
}
void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) noexcept {
Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast<u64>(op)), value);
}
void DataSynchronizationBarrier() noexcept {
Inst(Opcode::A64DataSynchronizationBarrier);
}
void DataMemoryBarrier() noexcept {
Inst(Opcode::A64DataMemoryBarrier);
}
void InstructionSynchronizationBarrier() noexcept {
Inst(Opcode::A64InstructionSynchronizationBarrier);
}
IR::U32 GetCNTFRQ() noexcept {
return Inst<IR::U32>(Opcode::A64GetCNTFRQ);
}
IR::U64 GetCNTPCT() noexcept {
return Inst<IR::U64>(Opcode::A64GetCNTPCT);
}
IR::U32 GetCTR() noexcept {
return Inst<IR::U32>(Opcode::A64GetCTR);
}
IR::U32 GetDCZID() noexcept {
return Inst<IR::U32>(Opcode::A64GetDCZID);
}
IR::U64 GetTPIDR() noexcept {
return Inst<IR::U64>(Opcode::A64GetTPIDR);
}
void SetTPIDR(const IR::U64& value) noexcept {
Inst(Opcode::A64SetTPIDR, value);
}
IR::U64 GetTPIDRRO() noexcept {
return Inst<IR::U64>(Opcode::A64GetTPIDRRO);
}
void ClearExclusive() noexcept {
Inst(Opcode::A64ClearExclusive);
}
IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U8>(Opcode::A64ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U16>(Opcode::A64ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U64>(Opcode::A64ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U128>(Opcode::A64ReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 GetW(Reg reg) noexcept {
if (reg == Reg::ZR)
return Imm32(0);
return Inst<IR::U32>(Opcode::A64GetW, IR::Value(reg));
}
IR::U64 GetX(Reg reg) noexcept {
if (reg == Reg::ZR)
return Imm64(0);
return Inst<IR::U64>(Opcode::A64GetX, IR::Value(reg));
}
IR::U128 GetS(Vec vec) noexcept {
return Inst<IR::U128>(Opcode::A64GetS, IR::Value(vec));
}
IR::U128 GetD(Vec vec) noexcept {
return Inst<IR::U128>(Opcode::A64GetD, IR::Value(vec));
}
IR::U128 GetQ(Vec vec) noexcept {
return Inst<IR::U128>(Opcode::A64GetQ, IR::Value(vec));
}
IR::U64 GetSP() noexcept {
return Inst<IR::U64>(Opcode::A64GetSP);
}
IR::U32 GetFPCR() noexcept {
return Inst<IR::U32>(Opcode::A64GetFPCR);
}
IR::U32 GetFPSR() noexcept {
return Inst<IR::U32>(Opcode::A64GetFPSR);
}
void SetW(const Reg reg, const IR::U32& value) noexcept {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetW, IR::Value(reg), value);
}
void SetX(const Reg reg, const IR::U64& value) noexcept {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetX, IR::Value(reg), value);
}
void SetS(const Vec vec, const IR::U128& value) noexcept {
Inst(Opcode::A64SetS, IR::Value(vec), value);
}
void SetD(const Vec vec, const IR::U128& value) noexcept {
Inst(Opcode::A64SetD, IR::Value(vec), value);
}
void SetQ(const Vec vec, const IR::U128& value) noexcept {
Inst(Opcode::A64SetQ, IR::Value(vec), value);
}
void SetSP(const IR::U64& value) noexcept {
Inst(Opcode::A64SetSP, value);
}
void SetFPCR(const IR::U32& value) noexcept {
Inst(Opcode::A64SetFPCR, value);
}
void SetFPSR(const IR::U32& value) noexcept {
Inst(Opcode::A64SetFPSR, value);
}
void SetPC(const IR::U64& value) noexcept {
Inst(Opcode::A64SetPC, value);
}
private:
IR::U64 ImmCurrentLocationDescriptor();
IR::U64 ImmCurrentLocationDescriptor() noexcept {
return Imm64(IR::LocationDescriptor{*current_location}.Value());
}
};
} // namespace Dynarmic::A64

View file

@ -33,27 +33,26 @@ inline size_t ToFastLookupIndex(u32 instruction) {
} // namespace detail
template<typename V>
DecodeTable<V> GetDecodeTable() {
constexpr DecodeTable<V> GetDecodeTable() {
std::vector<Matcher<V>> list = {
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./a64.inc"
#undef INST
};
// If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) {
// If a matcher has more bits in its mask it is more specific, so it should come first.
return mcl::bit::count_ones(matcher1.GetMask()) > mcl::bit::count_ones(matcher2.GetMask());
});
// Exceptions to the above rule of thumb.
const std::set<std::string> comes_first{
"MOVI, MVNI, ORR, BIC (vector, immediate)",
"FMOV (vector, immediate)",
"Unallocated SIMD modified immediate",
};
std::stable_partition(list.begin(), list.end(), [&](const auto& matcher) {
return comes_first.count(matcher.GetName()) > 0;
return std::set<std::string>{
"MOVI, MVNI, ORR, BIC (vector, immediate)",
"FMOV (vector, immediate)",
"Unallocated SIMD modified immediate",
}.count(matcher.GetName()) > 0;
});
DecodeTable<V> table{};
@ -75,7 +74,6 @@ std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction)
const auto matches_instruction = [instruction](const auto& matcher) {
return matcher.Matches(instruction);
};
const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction);
return iter != subtable.end() ? std::optional<std::reference_wrapper<const Matcher<V>>>(*iter) : std::nullopt;

View file

@ -67,3 +67,64 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
}
} // namespace Dynarmic::A64
// ls -l | awk '{print "#include \"dynarmic/frontend/A64/translate/impl/" $9 "\""}'
#include "dynarmic/frontend/A64/translate/impl/a64_branch.cpp"
#include "dynarmic/frontend/A64/translate/impl/a64_exception_generating.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_addsub.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_bitfield.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_conditional_compare.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_conditional_select.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_crc32.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_logical.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_multiply.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_pcrel.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_shift.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_compare.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conditional_compare.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conditional_select.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conversion_integer.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_three_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/impl.cpp"
#include "dynarmic/frontend/A64/translate/impl/impl.h"
#include "dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_load_literal.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_multiple_structures.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_no_allocate_pair.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_pair.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_register_offset.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_unprivileged.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_single_structure.cpp"
#include "dynarmic/frontend/A64/translate/impl/move_wide.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_across_lanes.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_aes.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_copy.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_crypto_four_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_crypto_three_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_extract.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_permute.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_sha512.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_sha.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_table_lookup.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_three_different.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_three_same.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_three_same_extra.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp"
#include "dynarmic/frontend/A64/translate/impl/sys_dc.cpp"
#include "dynarmic/frontend/A64/translate/impl/sys_ic.cpp"
#include "dynarmic/frontend/A64/translate/impl/system.cpp"
#include "dynarmic/frontend/A64/translate/impl/system_flag_format.cpp"
#include "dynarmic/frontend/A64/translate/impl/system_flag_manipulation.cpp"

View file

@ -7,14 +7,14 @@
namespace Dynarmic::A64 {
namespace {
enum class MinMaxOperation {
enum class MinMaxOperationSSPW {
Max,
MaxNumeric,
Min,
MinNumeric,
};
bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOperation operation) {
bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOperationSSPW operation) {
const size_t esize = sz ? 64 : 32;
const IR::U128 operand = v.V(128, Vn);
@ -22,13 +22,13 @@ bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOpera
const IR::U32U64 element2 = v.ir.VectorGetElement(esize, operand, 1);
const IR::U32U64 result = [&] {
switch (operation) {
case MinMaxOperation::Max:
case MinMaxOperationSSPW::Max:
return v.ir.FPMax(element1, element2);
case MinMaxOperation::MaxNumeric:
case MinMaxOperationSSPW::MaxNumeric:
return v.ir.FPMaxNumeric(element1, element2);
case MinMaxOperation::Min:
case MinMaxOperationSSPW::Min:
return v.ir.FPMin(element1, element2);
case MinMaxOperation::MinNumeric:
case MinMaxOperationSSPW::MinNumeric:
return v.ir.FPMinNumeric(element1, element2);
default:
UNREACHABLE();
@ -63,18 +63,18 @@ bool TranslatorVisitor::FADDP_pair_2(bool size, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FMAXNMP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::MaxNumeric);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::MaxNumeric);
}
bool TranslatorVisitor::FMAXP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::Max);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::Max);
}
bool TranslatorVisitor::FMINNMP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::MinNumeric);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::MinNumeric);
}
bool TranslatorVisitor::FMINP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::Min);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::Min);
}
} // namespace Dynarmic::A64

View file

@ -27,7 +27,7 @@ enum class ShiftExtraBehavior {
Accumulate,
};
enum class Signedness {
enum class SignednessSSSBI {
Signed,
Unsigned,
};
@ -63,7 +63,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
return true;
}
bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, Signedness signedness) {
bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, SignednessSSSBI SignednessSSSBI) {
if (!immh.Bit<3>()) {
return v.ReservedValue();
}
@ -73,7 +73,7 @@ bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd,
const IR::U64 operand = v.V_scalar(esize, Vn);
IR::U64 result = [&]() -> IR::U64 {
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.ArithmeticShiftRight(operand, v.ir.Imm8(shift_amount));
}
return v.ir.LogicalShiftRight(operand, v.ir.Imm8(shift_amount));
@ -88,7 +88,7 @@ bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd,
return true;
}
bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, Signedness signedness) {
bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, SignednessSSSBI SignednessSSSBI) {
if (!immh.Bit<3>()) {
return v.ReservedValue();
}
@ -100,7 +100,7 @@ bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
const IR::U64 round_bit = v.ir.LogicalShiftRight(v.ir.LogicalShiftLeft(operand, v.ir.Imm8(64 - shift_amount)), v.ir.Imm8(63));
const IR::U64 result = [&] {
const IR::U64 shifted = [&]() -> IR::U64 {
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.ArithmeticShiftRight(operand, v.ir.Imm8(shift_amount));
}
return v.ir.LogicalShiftRight(operand, v.ir.Imm8(shift_amount));
@ -163,7 +163,7 @@ bool ShiftAndInsert(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec
return true;
}
bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Narrowing narrowing, Signedness signedness) {
bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Narrowing narrowing, SignednessSSSBI SignednessSSSBI) {
if (immh == 0b0000) {
return v.ReservedValue();
}
@ -179,7 +179,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
const IR::U128 operand = v.ir.ZeroExtendToQuad(v.ir.VectorGetElement(source_esize, v.V(128, Vn), 0));
IR::U128 wide_result = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.VectorArithmeticShiftRight(source_esize, operand, shift_amount);
}
return v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount);
@ -190,12 +190,12 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
case Narrowing::Truncation:
return v.ir.VectorNarrow(source_esize, wide_result);
case Narrowing::SaturateToUnsigned:
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.VectorSignedSaturatedNarrowToUnsigned(source_esize, wide_result);
}
return v.ir.VectorUnsignedSaturatedNarrow(source_esize, wide_result);
case Narrowing::SaturateToSigned:
ASSERT(signedness == Signedness::Signed);
ASSERT(SignednessSSSBI == SignednessSSSBI::Signed);
return v.ir.VectorSignedSaturatedNarrowToSigned(source_esize, wide_result);
}
UNREACHABLE();
@ -206,7 +206,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
return true;
}
bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness sign, FloatConversionDirection direction, FP::RoundingMode rounding_mode) {
bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSSBI sign, FloatConversionDirection direction, FP::RoundingMode rounding_mode) {
const u32 immh_value = immh.ZeroExtend();
if ((immh_value & 0b1110) == 0b0000) {
@ -227,23 +227,23 @@ bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Ve
switch (direction) {
case FloatConversionDirection::FloatToFixed:
if (esize == 64) {
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPToFixedS64(operand, fbits, rounding_mode)
: v.ir.FPToFixedU64(operand, fbits, rounding_mode);
}
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPToFixedS32(operand, fbits, rounding_mode)
: v.ir.FPToFixedU32(operand, fbits, rounding_mode);
case FloatConversionDirection::FixedToFloat:
if (esize == 64) {
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPSignedFixedToDouble(operand, fbits, rounding_mode)
: v.ir.FPUnsignedFixedToDouble(operand, fbits, rounding_mode);
}
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPSignedFixedToSingle(operand, fbits, rounding_mode)
: v.ir.FPUnsignedFixedToSingle(operand, fbits, rounding_mode);
}
@ -257,19 +257,19 @@ bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Ve
} // Anonymous namespace
bool TranslatorVisitor::FCVTZS_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FCVTZU_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::SCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::UCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::SLI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -289,27 +289,27 @@ bool TranslatorVisitor::SQSHLU_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToSigned, Signedness::Signed);
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToSigned, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SQSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, Signedness::Signed);
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SRSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SRSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SHL_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -332,23 +332,23 @@ bool TranslatorVisitor::UQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, Signedness::Unsigned);
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::URSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::URSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::USHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::USRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Unsigned);
}
} // namespace Dynarmic::A64

View file

@ -26,12 +26,12 @@ enum class ComparisonVariant {
Zero,
};
enum class Signedness {
enum class SignednessSSTS {
Signed,
Unsigned,
};
bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSSTS sign) {
if (size != 0b11) {
return v.ReservedValue();
}
@ -39,7 +39,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd
const IR::U128 operand1 = v.V(64, Vn);
const IR::U128 operand2 = v.V(64, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSSTS::Signed) {
return v.ir.VectorRoundingShiftLeftSigned(64, operand1, operand2);
}
@ -369,7 +369,7 @@ bool TranslatorVisitor::SQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, Signedness::Signed);
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, SignednessSSTS::Signed);
}
bool TranslatorVisitor::SSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -411,7 +411,7 @@ bool TranslatorVisitor::UQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::URSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, Signedness::Unsigned);
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, SignednessSSTS::Unsigned);
}
bool TranslatorVisitor::USHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {

View file

@ -7,7 +7,7 @@
namespace Dynarmic::A64 {
namespace {
enum class ComparisonType {
enum class ComparisonTypeSSTRM {
EQ,
GE,
GT,
@ -15,12 +15,12 @@ enum class ComparisonType {
LT
};
enum class Signedness {
enum class SignednessSSTRM {
Signed,
Unsigned
};
bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, ComparisonType type) {
bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, ComparisonTypeSSTRM type) {
const size_t esize = sz ? 64 : 32;
const size_t datasize = esize;
@ -28,15 +28,15 @@ bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, C
const IR::U128 zero = v.ir.ZeroVector();
const IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSSTRM::EQ:
return v.ir.FPVectorEqual(esize, operand, zero);
case ComparisonType::GE:
case ComparisonTypeSSTRM::GE:
return v.ir.FPVectorGreaterEqual(esize, operand, zero);
case ComparisonType::GT:
case ComparisonTypeSSTRM::GT:
return v.ir.FPVectorGreater(esize, operand, zero);
case ComparisonType::LE:
case ComparisonTypeSSTRM::LE:
return v.ir.FPVectorGreaterEqual(esize, zero, operand);
case ComparisonType::LT:
case ComparisonTypeSSTRM::LT:
return v.ir.FPVectorGreater(esize, zero, operand);
}
@ -47,18 +47,18 @@ bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, C
return true;
}
bool ScalarFPConvertWithRound(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, FP::RoundingMode rmode, Signedness sign) {
bool ScalarFPConvertWithRound(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, FP::RoundingMode rmode, SignednessSSTRM sign) {
const size_t esize = sz ? 64 : 32;
const IR::U32U64 operand = v.V_scalar(esize, Vn);
const IR::U32U64 result = [&]() -> IR::U32U64 {
if (sz) {
return sign == Signedness::Signed
return sign == SignednessSSTRM::Signed
? v.ir.FPToFixedS64(operand, 0, rmode)
: v.ir.FPToFixedU64(operand, 0, rmode);
}
return sign == Signedness::Signed
return sign == SignednessSSTRM::Signed
? v.ir.FPToFixedS32(operand, 0, rmode)
: v.ir.FPToFixedU32(operand, 0, rmode);
}();
@ -107,55 +107,55 @@ bool TranslatorVisitor::FCMEQ_zero_1(Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCMEQ_zero_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::EQ);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::EQ);
}
bool TranslatorVisitor::FCMGE_zero_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::GE);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::GE);
}
bool TranslatorVisitor::FCMGT_zero_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::GT);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::GT);
}
bool TranslatorVisitor::FCMLE_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::LE);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::LE);
}
bool TranslatorVisitor::FCMLT_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::LT);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::LT);
}
bool TranslatorVisitor::FCVTAS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTAU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTMS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTMU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTNS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTNU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTPS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTPU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTXN_1(bool sz, Vec Vn, Vec Vd) {
@ -171,11 +171,11 @@ bool TranslatorVisitor::FCVTXN_1(bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCVTZS_int_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTZU_int_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FRECPE_1(Vec Vn, Vec Vd) {

View file

@ -9,7 +9,7 @@
namespace Dynarmic::A64 {
namespace {
std::pair<size_t, Vec> Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
std::pair<size_t, Vec> CombineScalar(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
if (size == 0b01) {
return {concatenate(H, L, M).ZeroExtend(), Vmlo.ZeroExtend<Vec>()};
}
@ -122,7 +122,7 @@ bool TranslatorVisitor::SQDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm
}
const size_t esize = 8 << size.ZeroExtend();
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo);
const IR::UAny operand1 = V_scalar(esize, Vn);
const IR::UAny operand2 = ir.VectorGetElement(esize, V(128, Vm), index);
@ -137,7 +137,7 @@ bool TranslatorVisitor::SQRDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> V
}
const size_t esize = 8 << size.ZeroExtend();
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo);
const IR::U128 operand1 = ir.ZeroExtendToQuad(ir.VectorGetElement(esize, V(128, Vn), 0));
const IR::U128 operand2 = V(128, Vm);
@ -154,7 +154,7 @@ bool TranslatorVisitor::SQDMULL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm
}
const size_t esize = 8 << size.ZeroExtend();
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo);
const IR::U128 operand1 = ir.ZeroExtendToQuad(ir.VectorGetElement(esize, V(128, Vn), 0));
const IR::U128 operand2 = V(128, Vm);

View file

@ -20,24 +20,24 @@ enum class Accumulating {
Accumulate
};
enum class Signedness {
enum class SignednessSSBI {
Signed,
Unsigned
};
enum class Narrowing {
enum class NarrowingSSBI {
Truncation,
SaturateToUnsigned,
SaturateToSigned,
};
enum class SaturatingShiftLeftType {
enum class SaturatingShiftLeftTypeSSBI {
Signed,
Unsigned,
SignedWithUnsignedSaturation,
};
enum class FloatConversionDirection {
enum class FloatConversionDirectionSSBI {
FixedToFloat,
FloatToFixed,
};
@ -48,7 +48,7 @@ IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round
return v.ir.VectorSub(esize, shifted, round_correction);
}
bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Accumulating accumulating, Signedness signedness) {
bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Accumulating accumulating, SignednessSSBI SignednessSSBI) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -65,7 +65,7 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn,
const IR::U128 operand = v.V(datasize, Vn);
IR::U128 result = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorArithmeticShiftRight(esize, operand, shift_amount);
}
return v.ir.VectorLogicalShiftRight(esize, operand, shift_amount);
@ -85,7 +85,7 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn,
return true;
}
bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Narrowing narrowing, Signedness signedness) {
bool ShiftRightNarrowingSSBI(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, NarrowingSSBI NarrowingSSBI, SignednessSSBI SignednessSSBI) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -103,7 +103,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
const IR::U128 operand = v.V(128, Vn);
IR::U128 wide_result = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorArithmeticShiftRight(source_esize, operand, shift_amount);
}
return v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount);
@ -115,16 +115,16 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
}
const IR::U128 result = [&] {
switch (narrowing) {
case Narrowing::Truncation:
switch (NarrowingSSBI) {
case NarrowingSSBI::Truncation:
return v.ir.VectorNarrow(source_esize, wide_result);
case Narrowing::SaturateToUnsigned:
if (signedness == Signedness::Signed) {
case NarrowingSSBI::SaturateToUnsigned:
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorSignedSaturatedNarrowToUnsigned(source_esize, wide_result);
}
return v.ir.VectorUnsignedSaturatedNarrow(source_esize, wide_result);
case Narrowing::SaturateToSigned:
ASSERT(signedness == Signedness::Signed);
case NarrowingSSBI::SaturateToSigned:
ASSERT(SignednessSSBI == SignednessSSBI::Signed);
return v.ir.VectorSignedSaturatedNarrowToSigned(source_esize, wide_result);
}
UNREACHABLE();
@ -134,7 +134,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
return true;
}
bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness) {
bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSBI SignednessSSBI) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -151,7 +151,7 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V
const IR::U128 operand = v.Vpart(datasize, Vn, part);
const IR::U128 expanded_operand = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorSignExtend(esize, operand);
}
return v.ir.VectorZeroExtend(esize, operand);
@ -162,7 +162,7 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V
return true;
}
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SaturatingShiftLeftType type) {
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SaturatingShiftLeftTypeSSBI type) {
if (!Q && immh.Bit<3>()) {
return v.ReservedValue();
}
@ -174,11 +174,11 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 shift_vec = v.ir.VectorBroadcast(esize, v.I(esize, shift));
const IR::U128 result = [&] {
if (type == SaturatingShiftLeftType::Signed) {
if (type == SaturatingShiftLeftTypeSSBI::Signed) {
return v.ir.VectorSignedSaturatedShiftLeft(esize, operand, shift_vec);
}
if (type == SaturatingShiftLeftType::Unsigned) {
if (type == SaturatingShiftLeftTypeSSBI::Unsigned) {
return v.ir.VectorUnsignedSaturatedShiftLeft(esize, operand, shift_vec);
}
@ -189,7 +189,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
return true;
}
bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness, FloatConversionDirection direction, FP::RoundingMode rounding_mode) {
bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSBI SignednessSSBI, FloatConversionDirectionSSBI direction, FP::RoundingMode rounding_mode) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -210,12 +210,12 @@ bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 result = [&] {
switch (direction) {
case FloatConversionDirection::FixedToFloat:
return signedness == Signedness::Signed
case FloatConversionDirectionSSBI::FixedToFloat:
return SignednessSSBI == SignednessSSBI::Signed
? v.ir.FPVectorFromSignedFixed(esize, operand, fbits, rounding_mode)
: v.ir.FPVectorFromUnsignedFixed(esize, operand, fbits, rounding_mode);
case FloatConversionDirection::FloatToFixed:
return signedness == Signedness::Signed
case FloatConversionDirectionSSBI::FloatToFixed:
return SignednessSSBI == SignednessSSBI::Signed
? v.ir.FPVectorToSignedFixed(esize, operand, fbits, rounding_mode)
: v.ir.FPVectorToUnsignedFixed(esize, operand, fbits, rounding_mode);
}
@ -229,19 +229,19 @@ bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn
} // Anonymous namespace
bool TranslatorVisitor::SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SRSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SRSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -264,71 +264,71 @@ bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd)
}
bool TranslatorVisitor::SHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::Truncation, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::Truncation, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::RSHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::Truncation, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::Truncation, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::SQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::Signed);
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::Signed);
}
bool TranslatorVisitor::SQSHLU_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::SignedWithUnsignedSaturation);
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::SignedWithUnsignedSaturation);
}
bool TranslatorVisitor::SQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToSigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToSigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToSigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToSigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SQSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SQRSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::UQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::Unsigned);
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::Unsigned);
}
bool TranslatorVisitor::UQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::UQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, Signedness::Signed);
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed);
}
bool TranslatorVisitor::URSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::URSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::USHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::USRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::USHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned);
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::SRI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -384,19 +384,19 @@ bool TranslatorVisitor::SLI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd)
}
bool TranslatorVisitor::SCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed, FloatConversionDirectionSSBI::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::UCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned, FloatConversionDirectionSSBI::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::FCVTZS_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed, FloatConversionDirectionSSBI::FloatToFixed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FCVTZU_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned, FloatConversionDirectionSSBI::FloatToFixed, FP::RoundingMode::TowardsZero);
}
} // namespace Dynarmic::A64

View file

@ -12,12 +12,12 @@ enum class AbsoluteDifferenceBehavior {
Accumulate
};
enum class Signedness {
enum class SignednessSTD {
Signed,
Unsigned
};
bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsoluteDifferenceBehavior behavior, Signedness sign) {
bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsoluteDifferenceBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -27,7 +27,7 @@ bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
const IR::U128 operand1 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vn, Q));
const IR::U128 operand2 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vm, Q));
IR::U128 result = sign == Signedness::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2)
IR::U128 result = sign == SignednessSTD::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2)
: v.ir.VectorUnsignedAbsoluteDifference(esize, operand1, operand2);
if (behavior == AbsoluteDifferenceBehavior::Accumulate) {
@ -45,7 +45,7 @@ enum class MultiplyLongBehavior {
Subtract
};
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MultiplyLongBehavior behavior, Signedness sign) {
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MultiplyLongBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -59,7 +59,7 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec
const auto reg_n = v.Vpart(datasize, Vn, Q);
const auto reg_m = v.Vpart(datasize, Vm, Q);
return sign == Signedness::Signed
return sign == SignednessSTD::Signed
? v.ir.VectorMultiplySignedWiden(esize, reg_n, reg_m)
: v.ir.VectorMultiplyUnsignedWiden(esize, reg_n, reg_m);
}();
@ -81,7 +81,7 @@ enum class LongOperationBehavior {
Subtraction
};
bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, LongOperationBehavior behavior, Signedness sign) {
bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, LongOperationBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -92,7 +92,7 @@ bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Ve
const auto get_operand = [&](Vec vec) {
const IR::U128 tmp = v.Vpart(64, vec, part);
if (sign == Signedness::Signed) {
if (sign == SignednessSTD::Signed) {
return v.ir.VectorSignExtend(esize, tmp);
}
@ -118,7 +118,7 @@ enum class WideOperationBehavior {
Subtraction
};
bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, WideOperationBehavior behavior, Signedness sign) {
bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, WideOperationBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -130,7 +130,7 @@ bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Ve
const IR::U128 operand2 = [&] {
const IR::U128 tmp = v.Vpart(64, Vm, part);
if (sign == Signedness::Signed) {
if (sign == SignednessSTD::Signed) {
return v.ir.VectorSignExtend(esize, tmp);
}
@ -166,75 +166,75 @@ bool TranslatorVisitor::PMULL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Signed);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, SignednessSTD::Signed);
}
bool TranslatorVisitor::SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Signed);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, SignednessSTD::Signed);
}
bool TranslatorVisitor::SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Signed);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, SignednessSTD::Signed);
}
bool TranslatorVisitor::SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Signed);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, SignednessSTD::Signed);
}
bool TranslatorVisitor::SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Signed);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, SignednessSTD::Signed);
}
bool TranslatorVisitor::SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Signed);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, SignednessSTD::Signed);
}
bool TranslatorVisitor::SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Signed);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, SignednessSTD::Signed);
}
bool TranslatorVisitor::SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Signed);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, SignednessSTD::Signed);
}
bool TranslatorVisitor::SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Signed);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, SignednessSTD::Signed);
}
bool TranslatorVisitor::UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Unsigned);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Unsigned);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Unsigned);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Unsigned);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Unsigned);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Unsigned);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::SQDMULL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {

View file

@ -12,12 +12,12 @@ enum class Operation {
Subtract,
};
enum class ExtraBehavior {
enum class ExtraBehaviorSTS {
None,
Round
};
bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, ExtraBehavior behavior) {
bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, ExtraBehaviorSTS behavior) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -35,7 +35,7 @@ bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
return v.ir.VectorSub(doubled_esize, operand1, operand2);
}();
if (behavior == ExtraBehavior::Round) {
if (behavior == ExtraBehaviorSTS::Round) {
const u64 round_const = 1ULL << (esize - 1);
const IR::U128 round_operand = v.ir.VectorBroadcast(doubled_esize, v.I(doubled_esize, round_const));
wide = v.ir.VectorAdd(doubled_esize, wide, round_operand);
@ -48,12 +48,12 @@ bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
return true;
}
enum class AbsDiffExtraBehavior {
enum class AbsDiffExtraBehaviorSTS {
None,
Accumulate
};
bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehavior behavior) {
bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehaviorSTS behavior) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -66,7 +66,7 @@ bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm,
const IR::U128 result = [&] {
const IR::U128 tmp = v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2);
if (behavior == AbsDiffExtraBehavior::Accumulate) {
if (behavior == AbsDiffExtraBehaviorSTS::Accumulate) {
const IR::U128 d = v.V(datasize, Vd);
return v.ir.VectorAdd(esize, d, tmp);
}
@ -78,12 +78,12 @@ bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm,
return true;
}
enum class Signedness {
enum class SignednessSTS {
Signed,
Unsigned
};
bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -93,14 +93,14 @@ bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec V
const IR::U128 operand1 = v.V(datasize, Vm);
const IR::U128 operand2 = v.V(datasize, Vn);
const IR::U128 result = sign == Signedness::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2)
const IR::U128 result = sign == SignednessSTS::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2)
: v.ir.VectorRoundingHalvingAddUnsigned(esize, operand1, operand2);
v.V(datasize, Vd, result);
return true;
}
bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -111,7 +111,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTS::Signed) {
return v.ir.VectorRoundingShiftLeftSigned(esize, operand1, operand2);
}
@ -122,7 +122,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn
return true;
}
enum class ComparisonType {
enum class ComparisonTypeSTS {
EQ,
GE,
AbsoluteGE,
@ -130,7 +130,7 @@ enum class ComparisonType {
AbsoluteGT
};
bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonType type) {
bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonTypeSTS type) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -142,17 +142,17 @@ bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSTS::EQ:
return v.ir.FPVectorEqual(esize, operand1, operand2);
case ComparisonType::GE:
case ComparisonTypeSTS::GE:
return v.ir.FPVectorGreaterEqual(esize, operand1, operand2);
case ComparisonType::AbsoluteGE:
case ComparisonTypeSTS::AbsoluteGE:
return v.ir.FPVectorGreaterEqual(esize,
v.ir.FPVectorAbs(esize, operand1),
v.ir.FPVectorAbs(esize, operand2));
case ComparisonType::GT:
case ComparisonTypeSTS::GT:
return v.ir.FPVectorGreater(esize, operand1, operand2);
case ComparisonType::AbsoluteGT:
case ComparisonTypeSTS::AbsoluteGT:
return v.ir.FPVectorGreater(esize,
v.ir.FPVectorAbs(esize, operand1),
v.ir.FPVectorAbs(esize, operand2));
@ -165,12 +165,12 @@ bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
return true;
}
enum class MinMaxOperation {
enum class MinMaxOperationSTS {
Min,
Max,
};
bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation, Signedness sign) {
bool VectorMinMaxOperationSTS(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation, SignednessSTS sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -182,14 +182,14 @@ bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
switch (operation) {
case MinMaxOperation::Max:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Max:
if (sign == SignednessSTS::Signed) {
return v.ir.VectorMaxSigned(esize, operand1, operand2);
}
return v.ir.VectorMaxUnsigned(esize, operand1, operand2);
case MinMaxOperation::Min:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Min:
if (sign == SignednessSTS::Signed) {
return v.ir.VectorMinSigned(esize, operand1, operand2);
}
return v.ir.VectorMinUnsigned(esize, operand1, operand2);
@ -203,7 +203,7 @@ bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve
return true;
}
bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) {
bool FPMinMaxOperationSTS(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -214,7 +214,7 @@ bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (operation == MinMaxOperation::Min) {
if (operation == MinMaxOperationSTS::Min) {
return v.ir.FPVectorMin(esize, operand1, operand2);
}
@ -225,7 +225,7 @@ bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
return true;
}
bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) {
bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -236,7 +236,7 @@ bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (operation == MinMaxOperation::Min) {
if (operation == MinMaxOperationSTS::Min) {
return v.ir.FPVectorMinNumeric(esize, operand1, operand2);
}
@ -247,7 +247,7 @@ bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec
return true;
}
bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation, Signedness sign) {
bool PairedMinMaxOperationSTS(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation, SignednessSTS sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -259,14 +259,14 @@ bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
IR::U128 result = [&] {
switch (operation) {
case MinMaxOperation::Max:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Max:
if (sign == SignednessSTS::Signed) {
return Q ? v.ir.VectorPairedMaxSigned(esize, operand1, operand2) : v.ir.VectorPairedMaxSignedLower(esize, operand1, operand2);
}
return Q ? v.ir.VectorPairedMaxUnsigned(esize, operand1, operand2) : v.ir.VectorPairedMaxUnsignedLower(esize, operand1, operand2);
case MinMaxOperation::Min:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Min:
if (sign == SignednessSTS::Signed) {
return Q ? v.ir.VectorPairedMinSigned(esize, operand1, operand2) : v.ir.VectorPairedMinSignedLower(esize, operand1, operand2);
}
return Q ? v.ir.VectorPairedMinUnsigned(esize, operand1, operand2) : v.ir.VectorPairedMinUnsignedLower(esize, operand1, operand2);
@ -311,7 +311,7 @@ bool FPPairedMinMax(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec V
return true;
}
bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, Signedness sign) {
bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, SignednessSTS sign) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -323,7 +323,7 @@ bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTS::Signed) {
if (op == Operation::Add) {
return v.ir.VectorSignedSaturatedAdd(esize, operand1, operand2);
}
@ -342,7 +342,7 @@ bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Ve
return true;
}
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -353,7 +353,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTS::Signed) {
return v.ir.VectorSignedSaturatedShiftLeft(esize, operand1, operand2);
}
@ -401,27 +401,27 @@ bool TranslatorVisitor::CMGE_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd)
}
bool TranslatorVisitor::SABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::Accumulate);
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehaviorSTS::Accumulate);
}
bool TranslatorVisitor::SABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::None);
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehaviorSTS::None);
}
bool TranslatorVisitor::SMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Signed);
}
bool TranslatorVisitor::SMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Signed);
}
bool TranslatorVisitor::SMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Signed);
}
bool TranslatorVisitor::SMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Signed);
}
bool TranslatorVisitor::SQDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -506,19 +506,19 @@ bool TranslatorVisitor::MUL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::ADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::None);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehaviorSTS::None);
}
bool TranslatorVisitor::RADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::Round);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehaviorSTS::Round);
}
bool TranslatorVisitor::SUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::None);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehaviorSTS::None);
}
bool TranslatorVisitor::RSUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::Round);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehaviorSTS::Round);
}
bool TranslatorVisitor::SHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -554,15 +554,15 @@ bool TranslatorVisitor::SHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Signed);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, SignednessSTS::Signed);
}
bool TranslatorVisitor::SQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Signed);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, SignednessSTS::Signed);
}
bool TranslatorVisitor::SRHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed);
}
bool TranslatorVisitor::UHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -598,15 +598,15 @@ bool TranslatorVisitor::UHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Unsigned);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Unsigned);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::URHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::ADDP_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -642,11 +642,11 @@ bool TranslatorVisitor::FABD_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FACGE_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGE);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::AbsoluteGE);
}
bool TranslatorVisitor::FACGT_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGT);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::AbsoluteGT);
}
bool TranslatorVisitor::FADD_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
@ -737,15 +737,15 @@ bool TranslatorVisitor::FCMEQ_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCMEQ_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::EQ);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::EQ);
}
bool TranslatorVisitor::FCMGE_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GE);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::GE);
}
bool TranslatorVisitor::FCMGT_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GT);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::GT);
}
bool TranslatorVisitor::AND_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
@ -827,11 +827,11 @@ bool TranslatorVisitor::CMTST_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed);
}
bool TranslatorVisitor::SRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed);
}
bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -851,11 +851,11 @@ bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::URSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -875,11 +875,11 @@ bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -918,11 +918,11 @@ bool TranslatorVisitor::UABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::FSUB_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
@ -1104,11 +1104,11 @@ bool TranslatorVisitor::EOR_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FMAX_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max);
return FPMinMaxOperationSTS(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Max);
}
bool TranslatorVisitor::FMAXNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max);
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Max);
}
bool TranslatorVisitor::FMAXNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
@ -1120,11 +1120,11 @@ bool TranslatorVisitor::FMAXP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FMIN_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min);
return FPMinMaxOperationSTS(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Min);
}
bool TranslatorVisitor::FMINNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min);
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Min);
}
bool TranslatorVisitor::FMINNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {

View file

@ -8,7 +8,7 @@
namespace Dynarmic::A64 {
namespace {
enum class ComparisonType {
enum class ComparisonTypeSTRM {
EQ,
GE,
GT,
@ -16,7 +16,7 @@ enum class ComparisonType {
LT,
};
bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, ComparisonType type) {
bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, ComparisonTypeSTRM type) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -28,15 +28,15 @@ bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec V
const IR::U128 zero = v.ir.ZeroVector();
IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSTRM::EQ:
return v.ir.VectorEqual(esize, operand, zero);
case ComparisonType::GE:
case ComparisonTypeSTRM::GE:
return v.ir.VectorGreaterEqualSigned(esize, operand, zero);
case ComparisonType::GT:
case ComparisonTypeSTRM::GT:
return v.ir.VectorGreaterSigned(esize, operand, zero);
case ComparisonType::LE:
case ComparisonTypeSTRM::LE:
return v.ir.VectorLessEqualSigned(esize, operand, zero);
case ComparisonType::LT:
case ComparisonTypeSTRM::LT:
default:
return v.ir.VectorLessSigned(esize, operand, zero);
}
@ -50,7 +50,7 @@ bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec V
return true;
}
bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, ComparisonType type) {
bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, ComparisonTypeSTRM type) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -62,15 +62,15 @@ bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd,
const IR::U128 zero = v.ir.ZeroVector();
const IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSTRM::EQ:
return v.ir.FPVectorEqual(esize, operand, zero);
case ComparisonType::GE:
case ComparisonTypeSTRM::GE:
return v.ir.FPVectorGreaterEqual(esize, operand, zero);
case ComparisonType::GT:
case ComparisonTypeSTRM::GT:
return v.ir.FPVectorGreater(esize, operand, zero);
case ComparisonType::LE:
case ComparisonTypeSTRM::LE:
return v.ir.FPVectorGreaterEqual(esize, zero, operand);
case ComparisonType::LT:
case ComparisonTypeSTRM::LT:
return v.ir.FPVectorGreater(esize, zero, operand);
}
@ -81,12 +81,12 @@ bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd,
return true;
}
enum class Signedness {
enum class SignednessSTRM {
Signed,
Unsigned
};
bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, Signedness signedness) {
bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, SignednessSTRM SignednessSTRM) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -96,7 +96,7 @@ bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd
const FP::RoundingMode rounding_mode = v.ir.current_location->FPCR().RMode();
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 result = signedness == Signedness::Signed
const IR::U128 result = SignednessSTRM == SignednessSTRM::Signed
? v.ir.FPVectorFromSignedFixed(esize, operand, 0, rounding_mode)
: v.ir.FPVectorFromUnsignedFixed(esize, operand, 0, rounding_mode);
@ -104,7 +104,7 @@ bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd
return true;
}
bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, Signedness signedness, FP::RoundingMode rounding_mode) {
bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, SignednessSTRM SignednessSTRM, FP::RoundingMode rounding_mode) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -113,7 +113,7 @@ bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd
const size_t esize = sz ? 64 : 32;
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 result = signedness == Signedness::Signed
const IR::U128 result = SignednessSTRM == SignednessSTRM::Signed
? v.ir.FPVectorToSignedFixed(esize, operand, 0, rounding_mode)
: v.ir.FPVectorToUnsignedFixed(esize, operand, 0, rounding_mode);
@ -168,7 +168,7 @@ enum class PairedAddLongExtraBehavior {
Accumulate,
};
bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Signedness sign, PairedAddLongExtraBehavior behavior) {
bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, SignednessSTRM sign, PairedAddLongExtraBehavior behavior) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -178,7 +178,7 @@ bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Si
const IR::U128 operand = v.V(datasize, Vn);
IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTRM::Signed) {
return v.ir.VectorPairedAddSignedWiden(esize, operand);
}
@ -254,23 +254,23 @@ bool TranslatorVisitor::CNT(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::CMGE_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::GE);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::GE);
}
bool TranslatorVisitor::CMGT_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::GT);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::GT);
}
bool TranslatorVisitor::CMEQ_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::EQ);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::EQ);
}
bool TranslatorVisitor::CMLE_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::LE);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::LE);
}
bool TranslatorVisitor::CMLT_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::LT);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::LT);
}
bool TranslatorVisitor::ABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
@ -341,23 +341,23 @@ bool TranslatorVisitor::FCMEQ_zero_3(bool Q, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCMEQ_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::EQ);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::EQ);
}
bool TranslatorVisitor::FCMGE_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::GE);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::GE);
}
bool TranslatorVisitor::FCMGT_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::GT);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::GT);
}
bool TranslatorVisitor::FCMLE_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::LE);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::LE);
}
bool TranslatorVisitor::FCMLT_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::LT);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::LT);
}
bool TranslatorVisitor::FCVTL(bool Q, bool sz, Vec Vn, Vec Vd) {
@ -411,19 +411,19 @@ bool TranslatorVisitor::FCVTN(bool Q, bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCVTNS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::ToNearest_TieEven);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::ToNearest_TieEven);
}
bool TranslatorVisitor::FCVTMS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsMinusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsMinusInfinity);
}
bool TranslatorVisitor::FCVTAS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::ToNearest_TieAwayFromZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::ToNearest_TieAwayFromZero);
}
bool TranslatorVisitor::FCVTPS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsPlusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsPlusInfinity);
}
bool TranslatorVisitor::FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) {
@ -447,27 +447,27 @@ bool TranslatorVisitor::FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCVTZS_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FCVTNU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::ToNearest_TieEven);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::ToNearest_TieEven);
}
bool TranslatorVisitor::FCVTMU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsMinusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsMinusInfinity);
}
bool TranslatorVisitor::FCVTAU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::ToNearest_TieAwayFromZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::ToNearest_TieAwayFromZero);
}
bool TranslatorVisitor::FCVTPU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsPlusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsPlusInfinity);
}
bool TranslatorVisitor::FCVTZU_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FRINTN_1(bool Q, Vec Vn, Vec Vd) {
@ -780,19 +780,19 @@ bool TranslatorVisitor::USQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Signed, PairedAddLongExtraBehavior::Accumulate);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Signed, PairedAddLongExtraBehavior::Accumulate);
}
bool TranslatorVisitor::SADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Signed, PairedAddLongExtraBehavior::None);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Signed, PairedAddLongExtraBehavior::None);
}
bool TranslatorVisitor::UADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Unsigned, PairedAddLongExtraBehavior::Accumulate);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Unsigned, PairedAddLongExtraBehavior::Accumulate);
}
bool TranslatorVisitor::UADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Unsigned, PairedAddLongExtraBehavior::None);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Unsigned, PairedAddLongExtraBehavior::None);
}
bool TranslatorVisitor::URECPE(bool Q, bool sz, Vec Vn, Vec Vd) {
@ -824,11 +824,11 @@ bool TranslatorVisitor::URSQRTE(bool Q, bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, Signedness::Signed);
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed);
}
bool TranslatorVisitor::UCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, Signedness::Unsigned);
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned);
}
bool TranslatorVisitor::SHLL(bool Q, Imm<2> size, Vec Vn, Vec Vd) {

View file

@ -11,7 +11,7 @@
namespace Dynarmic::A64 {
namespace {
std::pair<size_t, Vec> Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
std::pair<size_t, Vec> CombineVector(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
if (size == 0b01) {
return {concatenate(H, L, M).ZeroExtend(), Vmlo.ZeroExtend<Vec>()};
}
@ -19,19 +19,19 @@ std::pair<size_t, Vec> Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4>
return {concatenate(H, L).ZeroExtend(), concatenate(M, Vmlo).ZeroExtend<Vec>()};
}
enum class ExtraBehavior {
enum class ExtraBehaviorSVXIE {
None,
Extended,
Accumulate,
Subtract,
};
bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) {
bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) {
if (size != 0b01 && size != 0b10) {
return v.ReservedValue();
}
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const size_t idxdsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = Q ? 128 : 64;
@ -41,9 +41,9 @@ bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<
const IR::U128 operand3 = v.V(datasize, Vd);
IR::U128 result = v.ir.VectorMultiply(esize, operand1, operand2);
if (extra_behavior == ExtraBehavior::Accumulate) {
if (extra_behavior == ExtraBehaviorSVXIE::Accumulate) {
result = v.ir.VectorAdd(esize, operand3, result);
} else if (extra_behavior == ExtraBehavior::Subtract) {
} else if (extra_behavior == ExtraBehaviorSVXIE::Subtract) {
result = v.ir.VectorSub(esize, operand3, result);
}
@ -51,7 +51,7 @@ bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<
return true;
}
bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) {
bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) {
if (sz && L == 1) {
return v.ReservedValue();
}
@ -71,13 +71,13 @@ bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1>
const IR::U128 result = [&] {
switch (extra_behavior) {
case ExtraBehavior::None:
case ExtraBehaviorSVXIE::None:
return v.ir.FPVectorMul(esize, operand1, operand2);
case ExtraBehavior::Extended:
case ExtraBehaviorSVXIE::Extended:
return v.ir.FPVectorMulX(esize, operand1, operand2);
case ExtraBehavior::Accumulate:
case ExtraBehaviorSVXIE::Accumulate:
return v.ir.FPVectorMulAdd(esize, operand3, operand1, operand2);
case ExtraBehavior::Subtract:
case ExtraBehaviorSVXIE::Subtract:
return v.ir.FPVectorMulAdd(esize, operand3, v.ir.FPVectorNeg(esize, operand1), operand2);
}
UNREACHABLE();
@ -86,7 +86,7 @@ bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1>
return true;
}
bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) {
bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) {
const size_t idxdsize = H == 1 ? 128 : 64;
const size_t index = concatenate(H, L, M).ZeroExtend();
const Vec Vm = Vmlo.ZeroExtend<Vec>();
@ -101,13 +101,13 @@ bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Im
// regular multiplies and extended multiplies.
const IR::U128 result = [&] {
switch (extra_behavior) {
case ExtraBehavior::None:
case ExtraBehaviorSVXIE::None:
break;
case ExtraBehavior::Extended:
case ExtraBehaviorSVXIE::Extended:
break;
case ExtraBehavior::Accumulate:
case ExtraBehaviorSVXIE::Accumulate:
return v.ir.FPVectorMulAdd(esize, operand3, operand1, operand2);
case ExtraBehavior::Subtract:
case ExtraBehaviorSVXIE::Subtract:
return v.ir.FPVectorMulAdd(esize, operand3, v.ir.FPVectorNeg(esize, operand1), operand2);
}
UNREACHABLE();
@ -151,12 +151,12 @@ bool DotProduct(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I
return true;
}
enum class Signedness {
enum class SignednessSVXIE {
Signed,
Unsigned
};
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior, Signedness sign) {
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior, SignednessSVXIE sign) {
if (size == 0b00 || size == 0b11) {
return v.ReservedValue();
}
@ -164,23 +164,23 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M,
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = v.Vpart(datasize, Vn, Q);
const IR::U128 operand2 = v.V(idxsize, Vm);
const IR::U128 index_vector = v.ir.VectorBroadcastElement(esize, operand2, index);
const IR::U128 result = [&] {
const IR::U128 product = sign == Signedness::Signed
const IR::U128 product = sign == SignednessSVXIE::Signed
? v.ir.VectorMultiplySignedWiden(esize, operand1, index_vector)
: v.ir.VectorMultiplyUnsignedWiden(esize, operand1, index_vector);
if (extra_behavior == ExtraBehavior::None) {
if (extra_behavior == ExtraBehaviorSVXIE::None) {
return product;
}
const IR::U128 operand3 = v.V(2 * datasize, Vd);
if (extra_behavior == ExtraBehavior::Accumulate) {
if (extra_behavior == ExtraBehaviorSVXIE::Accumulate) {
return v.ir.VectorAdd(2 * esize, operand3, product);
}
@ -193,15 +193,15 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M,
} // Anonymous namespace
bool TranslatorVisitor::MLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate);
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate);
}
bool TranslatorVisitor::MLS_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract);
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract);
}
bool TranslatorVisitor::MUL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None);
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None);
}
bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<2> rot, Imm<1> H, Vec Vn, Vec Vd) {
@ -292,39 +292,39 @@ bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4
}
bool TranslatorVisitor::FMLA_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate);
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate);
}
bool TranslatorVisitor::FMLA_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate);
}
bool TranslatorVisitor::FMLS_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract);
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract);
}
bool TranslatorVisitor::FMLS_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract);
}
bool TranslatorVisitor::FMUL_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None);
}
bool TranslatorVisitor::FMULX_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Extended);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Extended);
}
bool TranslatorVisitor::SMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate, Signedness::Signed);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate, SignednessSVXIE::Signed);
}
bool TranslatorVisitor::SMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract, Signedness::Signed);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract, SignednessSVXIE::Signed);
}
bool TranslatorVisitor::SMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None, Signedness::Signed);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None, SignednessSVXIE::Signed);
}
bool TranslatorVisitor::SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
@ -336,7 +336,7 @@ bool TranslatorVisitor::SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = Vpart(datasize, Vn, part);
const IR::U128 operand2 = V(idxsize, Vm);
@ -355,7 +355,7 @@ bool TranslatorVisitor::SQDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = Q ? 128 : 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = V(datasize, Vn);
const IR::U128 operand2 = V(idxsize, Vm);
@ -374,7 +374,7 @@ bool TranslatorVisitor::SQRDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M,
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = Q ? 128 : 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = V(datasize, Vn);
const IR::U128 operand2 = V(idxsize, Vm);
@ -394,15 +394,15 @@ bool TranslatorVisitor::UDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4>
}
bool TranslatorVisitor::UMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate, SignednessSVXIE::Unsigned);
}
bool TranslatorVisitor::UMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract, SignednessSVXIE::Unsigned);
}
bool TranslatorVisitor::UMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None, SignednessSVXIE::Unsigned);
}
} // namespace Dynarmic::A64

View file

@ -5,10 +5,12 @@
#pragma once
#include <stdint.h>
namespace Dynarmic {
namespace A32 {
enum class ArchVersion {
enum class ArchVersion : std::uint8_t {
v3,
v4,
v4T,

View file

@ -120,14 +120,32 @@ struct UserCallbacks : public TranslateCallbacks {
};
struct UserConfig {
bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
UserCallbacks* callbacks;
size_t processor_id = 0;
ExclusiveMonitor* global_monitor = nullptr;
/// Select the architecture version to use.
/// There are minor behavioural differences between versions.
ArchVersion arch_version = ArchVersion::v8;
// Page Table
// The page table is used for faster memory access. If an entry in the table is nullptr,
// the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>* page_table = nullptr;
/// Coprocessors
std::array<std::shared_ptr<Coprocessor>, 16> coprocessors{};
/// Fastmem Pointer
/// This should point to the beginning of a 4GB address space which is in arranged just like
/// what you wish for emulated memory to be. If the host page faults on an address, the JIT
/// will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
std::optional<uintptr_t> fastmem_pointer = std::nullopt;
/// This selects other optimizations than can't otherwise be disabled by setting other
/// configuration options. This includes:
@ -137,12 +155,29 @@ struct UserConfig {
/// This is intended to be used for debugging.
OptimizationFlag optimizations = all_safe_optimizations;
bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
/// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
/// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
std::uint32_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Processor ID
std::uint32_t processor_id = 0;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
std::int32_t page_table_pointer_mask_bits = 0;
/// Select the architecture version to use.
/// There are minor behavioural differences between versions.
ArchVersion arch_version = ArchVersion::v8;
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// This enables unsafe optimizations that reduce emulation accuracy in favour of speed.
/// For safety, in order to enable unsafe optimizations you have to set BOTH this flag
@ -150,12 +185,6 @@ struct UserConfig {
/// The prefered and tested mode for this library is with unsafe optimizations disabled.
bool unsafe_optimizations = false;
// Page Table
// The page table is used for faster memory access. If an entry in the table is nullptr,
// the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>* page_table = nullptr;
/// Determines if the pointer in the page_table shall be offseted locally or globally.
/// 'false' will access page_table[addr >> bits][addr & mask]
/// 'true' will access page_table[addr >> bits][addr]
@ -163,26 +192,11 @@ struct UserConfig {
/// So there might be wrongly faulted pages which maps to nullptr.
/// This can be avoided by carefully allocating the memory region.
bool absolute_offset_page_table = false;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
int page_table_pointer_mask_bits = 0;
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// Determines if the above option only triggers when the misalignment straddles a
/// page boundary.
bool only_detect_misalignment_via_page_table_on_page_boundary = false;
// Fastmem Pointer
// This should point to the beginning of a 4GB address space which is in arranged just like
// what you wish for emulated memory to be. If the host page faults on an address, the JIT
// will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
std::optional<uintptr_t> fastmem_pointer = std::nullopt;
/// Determines if instructions that pagefault should cause recompilation of that block
/// with fastmem disabled.
/// Recompiled code will use the page_table if this is available, otherwise memory
@ -198,9 +212,6 @@ struct UserConfig {
/// callbacks.
bool recompile_on_exclusive_fastmem_failure = true;
// Coprocessors
std::array<std::shared_ptr<Coprocessor>, 16> coprocessors{};
/// When set to true, UserCallbacks::InstructionSynchronizationBarrierRaised will be
/// called when an ISB instruction is executed.
/// When set to false, ISB will be treated as a NOP instruction.
@ -234,10 +245,6 @@ struct UserConfig {
/// in unusual behavior.
bool always_little_endian = false;
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
size_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Internal use only
bool very_verbose_debugging_output = false;
};

View file

@ -136,11 +136,30 @@ struct UserCallbacks {
};
struct UserConfig {
/// Fastmem Pointer
/// This should point to the beginning of a 2^page_table_address_space_bits bytes
/// address space which is in arranged just like what you wish for emulated memory to
/// be. If the host page faults on an address, the JIT will fallback to calling the
/// MemoryRead*/MemoryWrite* callbacks.
std::optional<std::uintptr_t> fastmem_pointer = std::nullopt;
UserCallbacks* callbacks;
size_t processor_id = 0;
ExclusiveMonitor* global_monitor = nullptr;
/// Pointer to where TPIDRRO_EL0 is stored. This pointer will be inserted into
/// emitted code.
const std::uint64_t* tpidrro_el0 = nullptr;
/// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into
/// emitted code.
std::uint64_t* tpidr_el0 = nullptr;
/// Pointer to the page table which we can use for direct page table access.
/// If an entry in page_table is null, the relevant memory callback will be called.
/// If page_table is nullptr, all memory accesses hit the memory callbacks.
void** page_table = nullptr;
/// This selects other optimizations than can't otherwise be disabled by setting other
/// configuration options. This includes:
/// - IR optimizations
@ -149,12 +168,50 @@ struct UserConfig {
/// This is intended to be used for debugging.
OptimizationFlag optimizations = all_safe_optimizations;
bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of page_table. Valid values are between 12 and 64 inclusive.
/// This is only used if page_table is not nullptr.
std::uint32_t page_table_address_space_bits = 36;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
std::int32_t page_table_pointer_mask_bits = 0;
/// Counter-timer frequency register. The value of the register is not interpreted by
/// dynarmic.
std::uint32_t cntfrq_el0 = 600000000;
/// CTR_EL0<27:24> is log2 of the cache writeback granule in words.
/// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words.
/// CTR_EL0<19:16> is log2 of the smallest data/unified cacheline in words.
/// CTR_EL0<15:14> is the level 1 instruction cache policy.
/// CTR_EL0<3:0> is log2 of the smallest instruction cacheline in words.
std::uint32_t ctr_el0 = 0x8444c004;
/// DCZID_EL0<3:0> is log2 of the block size in words
/// DCZID_EL0<4> is 0 if the DC ZVA instruction is permitted.
std::uint32_t dczid_el0 = 4;
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of fastmem arena. Valid values are between 12 and 64 inclusive.
/// This is only used if fastmem_pointer is set.
std::uint32_t fastmem_address_space_bits = 36;
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
std::uint32_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64 | 128.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// Processor ID
std::uint8_t processor_id = 0;
/// This enables unsafe optimizations that reduce emulation accuracy in favour of speed.
/// For safety, in order to enable unsafe optimizations you have to set BOTH this flag
@ -177,48 +234,13 @@ struct UserConfig {
/// instruction is executed.
bool hook_hint_instructions = false;
/// Counter-timer frequency register. The value of the register is not interpreted by
/// dynarmic.
std::uint32_t cntfrq_el0 = 600000000;
/// CTR_EL0<27:24> is log2 of the cache writeback granule in words.
/// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words.
/// CTR_EL0<19:16> is log2 of the smallest data/unified cacheline in words.
/// CTR_EL0<15:14> is the level 1 instruction cache policy.
/// CTR_EL0<3:0> is log2 of the smallest instruction cacheline in words.
std::uint32_t ctr_el0 = 0x8444c004;
/// DCZID_EL0<3:0> is log2 of the block size in words
/// DCZID_EL0<4> is 0 if the DC ZVA instruction is permitted.
std::uint32_t dczid_el0 = 4;
/// Pointer to where TPIDRRO_EL0 is stored. This pointer will be inserted into
/// emitted code.
const std::uint64_t* tpidrro_el0 = nullptr;
/// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into
/// emitted code.
std::uint64_t* tpidr_el0 = nullptr;
/// Pointer to the page table which we can use for direct page table access.
/// If an entry in page_table is null, the relevant memory callback will be called.
/// If page_table is nullptr, all memory accesses hit the memory callbacks.
void** page_table = nullptr;
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of page_table. Valid values are between 12 and 64 inclusive.
/// This is only used if page_table is not nullptr.
size_t page_table_address_space_bits = 36;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
int page_table_pointer_mask_bits = 0;
/// Determines what happens if the guest accesses an entry that is off the end of the
/// page table. If true, Dynarmic will silently mirror page_table's address space. If
/// false, accessing memory outside of page_table bounds will result in a call to the
/// relevant memory callback.
/// This is only used if page_table is not nullptr.
bool silently_mirror_page_table = true;
/// Determines if the pointer in the page_table shall be offseted locally or globally.
/// 'false' will access page_table[addr >> bits][addr & mask]
/// 'true' will access page_table[addr >> bits][addr]
@ -226,31 +248,17 @@ struct UserConfig {
/// So there might be wrongly faulted pages which maps to nullptr.
/// This can be avoided by carefully allocating the memory region.
bool absolute_offset_page_table = false;
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64 | 128.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// Determines if the above option only triggers when the misalignment straddles a
/// page boundary.
bool only_detect_misalignment_via_page_table_on_page_boundary = false;
/// Fastmem Pointer
/// This should point to the beginning of a 2^page_table_address_space_bits bytes
/// address space which is in arranged just like what you wish for emulated memory to
/// be. If the host page faults on an address, the JIT will fallback to calling the
/// MemoryRead*/MemoryWrite* callbacks.
std::optional<uintptr_t> fastmem_pointer = std::nullopt;
/// Determines if instructions that pagefault should cause recompilation of that block
/// with fastmem disabled.
/// Recompiled code will use the page_table if this is available, otherwise memory
/// accesses will hit the memory callbacks.
bool recompile_on_fastmem_failure = true;
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of fastmem arena. Valid values are between 12 and 64 inclusive.
/// This is only used if fastmem_pointer is set.
size_t fastmem_address_space_bits = 36;
/// Determines what happens if the guest accesses an entry that is off the end of the
/// fastmem arena. If true, Dynarmic will silently mirror fastmem's address space. If
/// false, accessing memory outside of fastmem bounds will result in a call to the
@ -285,12 +293,15 @@ struct UserConfig {
/// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
bool enable_cycle_counting = true;
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
size_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Internal use only
bool very_verbose_debugging_output = false;
inline bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
};
} // namespace A64

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff