early-access version 2836

This commit is contained in:
pineappleEA
2022-07-15 13:11:09 +02:00
parent 0e7aef7e36
commit 2a9883730d
78 changed files with 1122 additions and 982 deletions

View File

@@ -114,9 +114,6 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
// Start emitting.
code.align();
const u8* const entrypoint = code.getCurr();
code.SwitchToFarCode();
const u8* const entrypoint_far = code.getCurr();
code.SwitchToNearCode();
EmitCondPrelude(ctx);
@@ -155,6 +152,11 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
EmitX64::EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.int3();
for (auto& deferred_emit : ctx.deferred_emits) {
deferred_emit();
}
code.int3();
const size_t size = static_cast<size_t>(code.getCurr() - entrypoint);
const A32::LocationDescriptor descriptor{block.Location()};
@@ -163,7 +165,7 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
const auto range = boost::icl::discrete_interval<u32>::closed(descriptor.PC(), end_location.PC() - 1);
block_ranges.AddRange(range, descriptor);
return RegisterBlock(descriptor, entrypoint, entrypoint_far, size);
return RegisterBlock(descriptor, entrypoint, size);
}
void A32EmitX64::ClearCache() {
@@ -1168,16 +1170,9 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
}
}
Xbyak::Label dest;
code.jmp(dest, Xbyak::CodeGenerator::T_NEAR);
code.SwitchToFarCode();
code.align(16);
code.L(dest);
code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC());
PushRSBHelper(rax, rbx, terminal.next);
code.ForceReturnFromRunCode();
code.SwitchToNearCode();
}
void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {

View File

@@ -110,6 +110,7 @@ protected:
FakeCall FastmemCallback(u64 rip);
// Memory access helpers
void EmitCheckMemoryAbort(A32EmitContext& ctx, IR::Inst* inst, Xbyak::Label* end = nullptr);
template<std::size_t bitsize, auto callback>
void EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst);
template<std::size_t bitsize, auto callback>

View File

@@ -235,4 +235,25 @@ void A32EmitX64::EmitA32ExclusiveWriteMemory64(A32EmitContext& ctx, IR::Inst* in
}
}
void A32EmitX64::EmitCheckMemoryAbort(A32EmitContext& ctx, IR::Inst* inst, Xbyak::Label* end) {
if (!conf.check_halt_on_memory_access) {
return;
}
Xbyak::Label skip;
const A32::LocationDescriptor current_location{IR::LocationDescriptor{inst->GetArg(0).GetU64()}};
code.test(dword[r15 + offsetof(A32JitState, halt_reason)], static_cast<u32>(HaltReason::MemoryAbort));
if (end) {
code.jz(*end, code.T_NEAR);
} else {
code.jz(skip, code.T_NEAR);
}
EmitSetUpperLocationDescriptor(current_location, ctx.Location());
code.mov(dword[r15 + offsetof(A32JitState, Reg) + sizeof(u32) * 15], current_location.PC());
code.ForceReturnFromRunCode();
code.L(skip);
}
} // namespace Dynarmic::Backend::X64

View File

@@ -60,7 +60,7 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
struct Jit::Impl {
Impl(Jit* jit, A32::UserConfig conf)
: block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, conf.far_code_offset, GenRCP(conf))
: block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
, emitter(block_of_code, conf, jit)
, polyfill_options(GenPolyfillOptions(block_of_code))
, conf(std::move(conf))
@@ -171,10 +171,9 @@ private:
PerformCacheInvalidation();
}
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks,
{conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions, conf.check_halt_on_memory_access});
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
Optimization::PolyfillPass(ir_block, polyfill_options);
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) {
Optimization::A32GetSetElimination(ir_block);
Optimization::DeadCodeElimination(ir_block);
}

View File

@@ -85,9 +85,6 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
// Start emitting.
code.align();
const u8* const entrypoint = code.getCurr();
code.SwitchToFarCode();
const u8* const entrypoint_far = code.getCurr();
code.SwitchToNearCode();
ASSERT(block.GetCondition() == IR::Cond::AL);
@@ -126,6 +123,11 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
EmitX64::EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.int3();
for (auto& deferred_emit : ctx.deferred_emits) {
deferred_emit();
}
code.int3();
const size_t size = static_cast<size_t>(code.getCurr() - entrypoint);
const A64::LocationDescriptor descriptor{block.Location()};
@@ -134,7 +136,7 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
const auto range = boost::icl::discrete_interval<u64>::closed(descriptor.PC(), end_location.PC() - 1);
block_ranges.AddRange(range, descriptor);
return RegisterBlock(descriptor, entrypoint, entrypoint_far, size);
return RegisterBlock(descriptor, entrypoint, size);
}
void A64EmitX64::ClearCache() {

View File

@@ -108,6 +108,7 @@ protected:
FakeCall FastmemCallback(u64 rip);
// Memory access helpers
void EmitCheckMemoryAbort(A64EmitContext& ctx, IR::Inst* inst, Xbyak::Label* end = nullptr);
template<std::size_t bitsize, auto callback>
void EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst);
template<std::size_t bitsize, auto callback>

View File

@@ -407,4 +407,25 @@ void A64EmitX64::EmitA64ExclusiveWriteMemory128(A64EmitContext& ctx, IR::Inst* i
}
}
void A64EmitX64::EmitCheckMemoryAbort(A64EmitContext&, IR::Inst* inst, Xbyak::Label* end) {
if (!conf.check_halt_on_memory_access) {
return;
}
Xbyak::Label skip;
const A64::LocationDescriptor current_location{IR::LocationDescriptor{inst->GetArg(0).GetU64()}};
code.test(dword[r15 + offsetof(A64JitState, halt_reason)], static_cast<u32>(HaltReason::MemoryAbort));
if (end) {
code.jz(*end, code.T_NEAR);
} else {
code.jz(skip, code.T_NEAR);
}
code.mov(rax, current_location.PC());
code.mov(qword[r15 + offsetof(A64JitState, pc)], rax);
code.ForceReturnFromRunCode();
code.L(skip);
}
} // namespace Dynarmic::Backend::X64

View File

@@ -58,7 +58,7 @@ struct Jit::Impl final {
public:
Impl(Jit* jit, UserConfig conf)
: conf(conf)
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, conf.far_code_offset, GenRCP(conf))
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
, emitter(block_of_code, conf, jit)
, polyfill_options(GenPolyfillOptions(block_of_code)) {
ASSERT(conf.page_table_address_space_bits >= 12 && conf.page_table_address_space_bits <= 64);
@@ -269,10 +269,10 @@ private:
// JIT Compile
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, get_code,
{conf.define_unpredictable_behaviour, conf.wall_clock_cntpct, conf.hook_hint_instructions, conf.check_halt_on_memory_access});
{conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
Optimization::PolyfillPass(ir_block, polyfill_options);
Optimization::A64CallbackConfigPass(ir_block, conf);
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) {
Optimization::A64GetSetElimination(ir_block);
Optimization::DeadCodeElimination(ir_block);
}

View File

@@ -185,22 +185,19 @@ HostFeature GetHostFeatures() {
} // anonymous namespace
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, size_t far_code_offset, std::function<void(BlockOfCode&)> rcp)
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function<void(BlockOfCode&)> rcp)
: Xbyak::CodeGenerator(total_code_size, nullptr, &s_allocator)
, cb(std::move(cb))
, jsi(jsi)
, far_code_offset(far_code_offset)
, constant_pool(*this, CONSTANT_POOL_SIZE)
, host_features(GetHostFeatures()) {
ASSERT(total_code_size > far_code_offset);
EnableWriting();
GenRunCode(rcp);
}
void BlockOfCode::PreludeComplete() {
prelude_complete = true;
near_code_begin = getCurr();
far_code_begin = getCurr() + far_code_offset;
code_begin = getCurr();
ClearCache();
DisableWriting();
}
@@ -219,21 +216,15 @@ void BlockOfCode::DisableWriting() {
void BlockOfCode::ClearCache() {
ASSERT(prelude_complete);
in_far_code = false;
near_code_ptr = near_code_begin;
far_code_ptr = far_code_begin;
SetCodePtr(near_code_begin);
SetCodePtr(code_begin);
}
size_t BlockOfCode::SpaceRemaining() const {
ASSERT(prelude_complete);
const u8* current_near_ptr = in_far_code ? reinterpret_cast<const u8*>(near_code_ptr) : getCurr<const u8*>();
const u8* current_far_ptr = in_far_code ? getCurr<const u8*>() : reinterpret_cast<const u8*>(far_code_ptr);
if (current_near_ptr >= far_code_begin)
const u8* current_ptr = getCurr<const u8*>();
if (current_ptr >= &top_[maxSize_])
return 0;
if (current_far_ptr >= &top_[maxSize_])
return 0;
return std::min(reinterpret_cast<const u8*>(far_code_begin) - current_near_ptr, &top_[maxSize_] - current_far_ptr);
return &top_[maxSize_] - current_ptr;
}
HaltReason BlockOfCode::RunCode(void* jit_state, CodePtr code_ptr) const {
@@ -406,26 +397,8 @@ Xbyak::Address BlockOfCode::XmmConst(const Xbyak::AddressFrame& frame, u64 lower
return constant_pool.GetConstant(frame, lower, upper);
}
void BlockOfCode::SwitchToFarCode() {
ASSERT(prelude_complete);
ASSERT(!in_far_code);
in_far_code = true;
near_code_ptr = getCurr();
SetCodePtr(far_code_ptr);
ASSERT_MSG(near_code_ptr < far_code_begin, "Near code has overwritten far code!");
}
void BlockOfCode::SwitchToNearCode() {
ASSERT(prelude_complete);
ASSERT(in_far_code);
in_far_code = false;
far_code_ptr = getCurr();
SetCodePtr(near_code_ptr);
}
CodePtr BlockOfCode::GetCodeBegin() const {
return near_code_begin;
return code_begin;
}
size_t BlockOfCode::GetTotalCodeSize() const {

View File

@@ -36,7 +36,7 @@ struct RunCodeCallbacks {
class BlockOfCode final : public Xbyak::CodeGenerator {
public:
BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, size_t far_code_offset, std::function<void(BlockOfCode&)> rcp);
BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function<void(BlockOfCode&)> rcp);
BlockOfCode(const BlockOfCode&) = delete;
/// Call when external emitters have finished emitting their preludes.
@@ -49,7 +49,7 @@ public:
/// Clears this block of code and resets code pointer to beginning.
void ClearCache();
/// Calculates how much space is remaining to use. This is the minimum of near code and far code.
/// Calculates how much space is remaining to use.
size_t SpaceRemaining() const;
/// Runs emulated code from code_ptr.
@@ -125,11 +125,6 @@ public:
mcl::bit::replicate_element<u64>(esize, value));
}
/// Far code sits far away from the near code. Execution remains primarily in near code.
/// "Cold" / Rarely executed instructions sit in far code, so the CPU doesn't fetch them unless necessary.
void SwitchToFarCode();
void SwitchToNearCode();
CodePtr GetCodeBegin() const;
size_t GetTotalCodeSize() const;
@@ -180,18 +175,12 @@ public:
private:
RunCodeCallbacks cb;
JitStateInfo jsi;
size_t far_code_offset;
bool prelude_complete = false;
CodePtr near_code_begin = nullptr;
CodePtr far_code_begin = nullptr;
CodePtr code_begin = nullptr;
ConstantPool constant_pool;
bool in_far_code = false;
CodePtr near_code_ptr;
CodePtr far_code_ptr;
using RunCodeFuncType = HaltReason (*)(void*, CodePtr);
RunCodeFuncType run_code = nullptr;
RunCodeFuncType step_code = nullptr;

View File

@@ -32,6 +32,8 @@ using namespace Xbyak::util;
EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block)
: reg_alloc(reg_alloc), block(block) {}
EmitContext::~EmitContext() = default;
size_t EmitContext::GetInstOffset(IR::Inst* inst) const {
return static_cast<size_t>(std::distance(block.begin(), IR::Block::iterator(inst)));
}
@@ -274,11 +276,8 @@ Xbyak::Label EmitX64::EmitCond(IR::Cond cond) {
return pass;
}
EmitX64::BlockDescriptor EmitX64::RegisterBlock(const IR::LocationDescriptor& descriptor, CodePtr entrypoint, CodePtr entrypoint_far, size_t size) {
EmitX64::BlockDescriptor EmitX64::RegisterBlock(const IR::LocationDescriptor& descriptor, CodePtr entrypoint, size_t size) {
PerfMapRegister(entrypoint, code.getCurr(), LocationDescriptorToFriendlyName(descriptor));
code.SwitchToFarCode();
PerfMapRegister(entrypoint_far, code.getCurr(), LocationDescriptorToFriendlyName(descriptor) + "_far");
code.SwitchToNearCode();
Patch(descriptor, entrypoint);
BlockDescriptor block_desc{entrypoint, size};

View File

@@ -6,6 +6,8 @@
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
@@ -14,6 +16,7 @@
#include <mcl/bitsizeof.hpp>
#include <tsl/robin_map.h>
#include <tsl/robin_set.h>
#include <xbyak/xbyak.h>
#include <xbyak/xbyak_util.h>
#include "dynarmic/backend/x64/exception_handler.h"
@@ -48,6 +51,7 @@ using HalfVectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof
struct EmitContext {
EmitContext(RegAlloc& reg_alloc, IR::Block& block);
virtual ~EmitContext();
size_t GetInstOffset(IR::Inst* inst) const;
void EraseInstruction(IR::Inst* inst);
@@ -58,8 +62,16 @@ struct EmitContext {
RegAlloc& reg_alloc;
IR::Block& block;
std::vector<std::function<void()>> deferred_emits;
};
using SharedLabel = std::shared_ptr<Xbyak::Label>;
inline SharedLabel GenSharedLabel() {
return std::make_shared<Xbyak::Label>();
}
class EmitX64 {
public:
struct BlockDescriptor {
@@ -93,7 +105,7 @@ protected:
virtual std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const = 0;
void EmitAddCycles(size_t cycles);
Xbyak::Label EmitCond(IR::Cond cond);
BlockDescriptor RegisterBlock(const IR::LocationDescriptor& location_descriptor, CodePtr entrypoint, CodePtr entrypoint_far, size_t size);
BlockDescriptor RegisterBlock(const IR::LocationDescriptor& location_descriptor, CodePtr entrypoint, size_t size);
void PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, IR::LocationDescriptor target);
// Terminal instruction emitters

View File

@@ -152,18 +152,18 @@ void ForceToDefaultNaN(BlockOfCode& code, Xbyak::Xmm result) {
}
template<size_t fsize>
Xbyak::Label ProcessNaN(BlockOfCode& code, Xbyak::Xmm a) {
Xbyak::Label nan, end;
SharedLabel ProcessNaN(BlockOfCode& code, EmitContext& ctx, Xbyak::Xmm a) {
SharedLabel nan = GenSharedLabel(), end = GenSharedLabel();
FCODE(ucomis)(a, a);
code.jp(nan, code.T_NEAR);
code.SwitchToFarCode();
code.L(nan);
code.jp(*nan, code.T_NEAR);
code.orps(a, code.XmmBConst<fsize>(xword, fsize == 32 ? 0x00400000 : 0x0008'0000'0000'0000));
ctx.deferred_emits.emplace_back([=, &code] {
code.L(*nan);
code.orps(a, code.XmmBConst<fsize>(xword, fsize == 32 ? 0x00400000 : 0x0008'0000'0000'0000));
code.jmp(*end, code.T_NEAR);
});
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
return end;
}
@@ -268,12 +268,12 @@ template<size_t fsize, typename Function>
void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Label end;
SharedLabel end = GenSharedLabel();
Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
if (!ctx.FPCR().DN() && !ctx.HasOptimization(OptimizationFlag::Unsafe_InaccurateNaN)) {
end = ProcessNaN<fsize>(code, result);
end = ProcessNaN<fsize>(code, ctx, result);
}
if constexpr (std::is_member_function_pointer_v<Function>) {
(code.*fn)(result, result);
@@ -287,7 +287,7 @@ void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
} else {
PostProcessNaN<fsize>(code, result, ctx.reg_alloc.ScratchXmm());
}
code.L(end);
code.L(*end);
ctx.reg_alloc.DefineValue(inst, result);
}
@@ -321,7 +321,7 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
const Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr();
Xbyak::Label end, nan, op_are_nans;
SharedLabel end = GenSharedLabel(), nan = GenSharedLabel();
code.movaps(result, op1);
if constexpr (std::is_member_function_pointer_v<Function>) {
@@ -330,19 +330,21 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
fn(result, op2);
}
FCODE(ucomis)(result, result);
code.jp(nan, code.T_NEAR);
code.L(end);
code.jp(*nan, code.T_NEAR);
code.L(*end);
code.SwitchToFarCode();
code.L(nan);
FCODE(ucomis)(op1, op2);
code.jp(op_are_nans);
// Here we must return a positive NaN, because the indefinite value on x86 is a negative NaN!
code.movaps(result, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::DefaultNaN()));
code.jmp(end, code.T_NEAR);
code.L(op_are_nans);
EmitPostProcessNaNs<fsize>(code, result, op1, op2, tmp, end);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code] {
Xbyak::Label op_are_nans;
code.L(*nan);
FCODE(ucomis)(op1, op2);
code.jp(op_are_nans);
// Here we must return a positive NaN, because the indefinite value on x86 is a negative NaN!
code.movaps(result, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::DefaultNaN()));
code.jmp(*end, code.T_NEAR);
code.L(op_are_nans);
EmitPostProcessNaNs<fsize>(code, result, op1, op2, tmp, *end);
});
ctx.reg_alloc.DefineValue(inst, result);
}
@@ -428,39 +430,39 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
DenormalsAreZero<fsize>(code, ctx, {result, operand});
Xbyak::Label equal, end, nan;
SharedLabel equal = GenSharedLabel(), end = GenSharedLabel();
FCODE(ucomis)(result, operand);
code.jz(equal, code.T_NEAR);
code.jz(*equal, code.T_NEAR);
if constexpr (is_max) {
FCODE(maxs)(result, operand);
} else {
FCODE(mins)(result, operand);
}
code.L(end);
code.L(*end);
code.SwitchToFarCode();
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
Xbyak::Label nan;
code.L(equal);
code.jp(nan);
if constexpr (is_max) {
code.andps(result, operand);
} else {
code.orps(result, operand);
}
code.jmp(end);
code.L(*equal);
code.jp(nan);
if constexpr (is_max) {
code.andps(result, operand);
} else {
code.orps(result, operand);
}
code.jmp(*end);
code.L(nan);
if (ctx.FPCR().DN()) {
code.movaps(result, code.XmmBConst<fsize>(xword, fsize == 32 ? f32_nan : f64_nan));
code.jmp(end);
} else {
code.movaps(tmp, result);
FCODE(adds)(result, operand);
EmitPostProcessNaNs<fsize>(code, result, tmp, operand, gpr_scratch, end);
}
code.SwitchToNearCode();
code.L(nan);
if (ctx.FPCR().DN()) {
code.movaps(result, code.XmmBConst<fsize>(xword, fsize == 32 ? f32_nan : f64_nan));
code.jmp(*end);
} else {
code.movaps(tmp, result);
FCODE(adds)(result, operand);
EmitPostProcessNaNs<fsize>(code, result, tmp, operand, gpr_scratch, *end);
}
});
ctx.reg_alloc.DefineValue(inst, result);
}
@@ -469,7 +471,6 @@ template<size_t fsize, bool is_max>
static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT default_nan = FP::FPInfo<FPT>::DefaultNaN();
constexpr u8 mantissa_msb_bit = static_cast<u8>(FP::FPInfo<FPT>::explicit_mantissa_width - 1);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@@ -492,7 +493,7 @@ static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
Xbyak::Reg tmp = ctx.reg_alloc.ScratchGpr();
tmp.setBit(fsize);
const auto move_to_tmp = [&](const Xbyak::Xmm& xmm) {
const auto move_to_tmp = [=, &code](const Xbyak::Xmm& xmm) {
if constexpr (fsize == 32) {
code.movd(tmp.cvt32(), xmm);
} else {
@@ -500,78 +501,79 @@ static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
}
};
Xbyak::Label end, z, nan, op2_is_nan, snan, maybe_both_nan, normal;
SharedLabel end = GenSharedLabel(), z = GenSharedLabel();
FCODE(ucomis)(op1, op2);
code.jz(z, code.T_NEAR);
code.L(normal);
code.jz(*z, code.T_NEAR);
if constexpr (is_max) {
FCODE(maxs)(op2, op1);
} else {
FCODE(mins)(op2, op1);
}
code.L(end);
code.L(*end);
code.SwitchToFarCode();
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
Xbyak::Label nan, op2_is_nan, snan, maybe_both_nan;
code.L(z);
code.jp(nan);
if constexpr (is_max) {
code.andps(op2, op1);
} else {
code.orps(op2, op1);
}
code.jmp(end);
constexpr u8 mantissa_msb_bit = static_cast<u8>(FP::FPInfo<FPT>::explicit_mantissa_width - 1);
// NaN requirements:
// op1 op2 result
// SNaN anything op1
// !SNaN SNaN op2
// QNaN !NaN op2
// !NaN QNaN op1
// QNaN QNaN op1
code.L(*z);
code.jp(nan);
if constexpr (is_max) {
code.andps(op2, op1);
} else {
code.orps(op2, op1);
}
code.jmp(*end);
code.L(nan);
FCODE(ucomis)(op1, op1);
code.jnp(op2_is_nan);
// NaN requirements:
// op1 op2 result
// SNaN anything op1
// !SNaN SNaN op2
// QNaN !NaN op2
// !NaN QNaN op1
// QNaN QNaN op1
// op1 is NaN
move_to_tmp(op1);
code.bt(tmp, mantissa_msb_bit);
code.jc(maybe_both_nan);
if (ctx.FPCR().DN()) {
code.L(snan);
code.movaps(op2, code.XmmBConst<fsize>(xword, default_nan));
code.jmp(end);
} else {
code.movaps(op2, op1);
code.L(snan);
code.orps(op2, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::mantissa_msb));
code.jmp(end);
}
code.L(nan);
FCODE(ucomis)(op1, op1);
code.jnp(op2_is_nan);
code.L(maybe_both_nan);
FCODE(ucomis)(op2, op2);
code.jnp(end, code.T_NEAR);
if (ctx.FPCR().DN()) {
code.jmp(snan);
} else {
// op1 is NaN
move_to_tmp(op1);
code.bt(tmp, mantissa_msb_bit);
code.jc(maybe_both_nan);
if (ctx.FPCR().DN()) {
code.L(snan);
code.movaps(op2, code.XmmBConst<fsize>(xword, default_nan));
code.jmp(*end);
} else {
code.movaps(op2, op1);
code.L(snan);
code.orps(op2, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::mantissa_msb));
code.jmp(*end);
}
code.L(maybe_both_nan);
FCODE(ucomis)(op2, op2);
code.jnp(*end, code.T_NEAR);
if (ctx.FPCR().DN()) {
code.jmp(snan);
} else {
move_to_tmp(op2);
code.bt(tmp.cvt64(), mantissa_msb_bit);
code.jnc(snan);
code.movaps(op2, op1);
code.jmp(*end);
}
// op2 is NaN
code.L(op2_is_nan);
move_to_tmp(op2);
code.bt(tmp.cvt64(), mantissa_msb_bit);
code.bt(tmp, mantissa_msb_bit);
code.jnc(snan);
code.movaps(op2, op1);
code.jmp(end);
}
// op2 is NaN
code.L(op2_is_nan);
move_to_tmp(op2);
code.bt(tmp, mantissa_msb_bit);
code.jnc(snan);
code.movaps(op2, op1);
code.jmp(end);
code.SwitchToNearCode();
code.jmp(*end);
});
}
ctx.reg_alloc.DefineValue(inst, op2);
@@ -636,7 +638,7 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
}
if (code.HasHostFeature(HostFeature::FMA)) {
Xbyak::Label end, fallback;
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(args[0]);
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(args[1]);
@@ -650,34 +652,34 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.movaps(tmp, code.XmmBConst<fsize>(xword, fsize == 32 ? f32_non_sign_mask : f64_non_sign_mask));
code.andps(tmp, result);
FCODE(ucomis)(tmp, code.XmmBConst<fsize>(xword, fsize == 32 ? f32_smallest_normal : f64_smallest_normal));
code.jz(fallback, code.T_NEAR);
code.L(end);
code.jz(*fallback, code.T_NEAR);
code.L(*end);
code.SwitchToFarCode();
code.L(fallback);
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(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());
code.sub(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(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.mov(qword[rsp + ABI_SHADOW_SPACE], rax);
code.CallFunction(&FP::FPMulAdd<FPT>);
code.add(rsp, 16 + ABI_SHADOW_SPACE);
code.sub(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(&FP::FPMulAdd<FPT>);
code.add(rsp, 16 + ABI_SHADOW_SPACE);
#else
code.lea(code.ABI_PARAM5, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPMulAdd<FPT>);
code.lea(code.ABI_PARAM5, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPMulAdd<FPT>);
#endif
code.movq(result, code.ABI_RETURN);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.movq(result, code.ABI_RETURN);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
code.jmp(*end, code.T_NEAR);
});
ctx.reg_alloc.DefineValue(inst, result);
return;
@@ -735,7 +737,7 @@ static void EmitFPMulX(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
const Xbyak::Reg64 tmp = do_default_nan ? INVALID_REG : ctx.reg_alloc.ScratchGpr();
Xbyak::Label end, nan, op_are_nans;
SharedLabel end = GenSharedLabel(), nan = GenSharedLabel();
if (code.HasHostFeature(HostFeature::AVX)) {
FCODE(vmuls)(result, op1, op2);
@@ -744,30 +746,32 @@ static void EmitFPMulX(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
FCODE(muls)(result, op2);
}
FCODE(ucomis)(result, result);
code.jp(nan, code.T_NEAR);
code.L(end);
code.jp(*nan, code.T_NEAR);
code.L(*end);
code.SwitchToFarCode();
code.L(nan);
FCODE(ucomis)(op1, op2);
code.jp(op_are_nans);
if (code.HasHostFeature(HostFeature::AVX)) {
code.vxorps(result, op1, op2);
} else {
code.movaps(result, op1);
code.xorps(result, op2);
}
code.andps(result, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::sign_mask));
code.orps(result, code.XmmBConst<fsize>(xword, FP::FPValue<FPT, false, 0, 2>()));
code.jmp(end, code.T_NEAR);
code.L(op_are_nans);
if (do_default_nan) {
code.movaps(result, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::DefaultNaN()));
code.jmp(end, code.T_NEAR);
} else {
EmitPostProcessNaNs<fsize>(code, result, op1, op2, tmp, end);
}
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code] {
Xbyak::Label op_are_nans;
code.L(*nan);
FCODE(ucomis)(op1, op2);
code.jp(op_are_nans);
if (code.HasHostFeature(HostFeature::AVX)) {
code.vxorps(result, op1, op2);
} else {
code.movaps(result, op1);
code.xorps(result, op2);
}
code.andps(result, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::sign_mask));
code.orps(result, code.XmmBConst<fsize>(xword, FP::FPValue<FPT, false, 0, 2>()));
code.jmp(*end, code.T_NEAR);
code.L(op_are_nans);
if (do_default_nan) {
code.movaps(result, code.XmmBConst<fsize>(xword, FP::FPInfo<FPT>::DefaultNaN()));
code.jmp(*end, code.T_NEAR);
} else {
EmitPostProcessNaNs<fsize>(code, result, op1, op2, tmp, *end);
}
});
ctx.reg_alloc.DefineValue(inst, result);
}
@@ -871,7 +875,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
}
if (code.HasHostFeature(HostFeature::FMA)) {
Xbyak::Label end, fallback;
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(args[0]);
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(args[1]);
@@ -880,25 +884,25 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
code.movaps(result, code.XmmBConst<fsize>(xword, FP::FPValue<FPT, false, 0, 2>()));
FCODE(vfnmadd231s)(result, operand1, operand2);
FCODE(ucomis)(result, result);
code.jp(fallback, code.T_NEAR);
code.L(end);
code.jp(*fallback, code.T_NEAR);
code.L(*end);
code.SwitchToFarCode();
code.L(fallback);
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPRecipStepFused<FPT>);
code.movq(result, code.ABI_RETURN);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPRecipStepFused<FPT>);
code.movq(result, code.ABI_RETURN);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
code.jmp(*end, code.T_NEAR);
});
ctx.reg_alloc.DefineValue(inst, result);
return;
@@ -1034,8 +1038,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
const Xbyak::Xmm value = ctx.reg_alloc.ScratchXmm();
[[maybe_unused]] const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32();
Xbyak::Label fallback, bad_values, end, default_nan;
bool needs_fallback = false;
SharedLabel bad_values = GenSharedLabel(), end = GenSharedLabel();
code.movaps(value, operand);
@@ -1045,7 +1048,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
// Detect NaNs, negatives, zeros, denormals and infinities
FCODE(ucomis)(value, code.XmmBConst<fsize>(xword, FPT(1) << FP::FPInfo<FPT>::explicit_mantissa_width));
code.jna(bad_values, code.T_NEAR);
code.jna(*bad_values, code.T_NEAR);
FCODE(sqrts)(value, value);
ICODE(mov)(result, code.XmmBConst<fsize>(xword, FP::FPValue<FPT, false, 0, 1>()));
@@ -1054,109 +1057,110 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
ICODE(padd)(result, code.XmmBConst<fsize>(xword, fsize == 32 ? 0x00004000 : 0x0000'0800'0000'0000));
code.pand(result, xmm0);
code.L(end);
code.L(*end);
code.SwitchToFarCode();
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
Xbyak::Label fallback, default_nan;
bool needs_fallback = false;
code.L(bad_values);
if constexpr (fsize == 32) {
code.movd(tmp, operand);
code.L(*bad_values);
if constexpr (fsize == 32) {
code.movd(tmp, operand);
if (!ctx.FPCR().FZ()) {
if (ctx.FPCR().DN()) {
// a > 0x80000000
code.cmp(tmp, 0x80000000);
code.ja(default_nan, code.T_NEAR);
}
// a > 0 && a < 0x00800000;
code.sub(tmp, 1);
code.cmp(tmp, 0x007FFFFF);
code.jb(fallback);
needs_fallback = true;
}
code.rsqrtss(result, operand);
if (!ctx.FPCR().FZ()) {
if (ctx.FPCR().DN()) {
// a > 0x80000000
code.cmp(tmp, 0x80000000);
code.ja(default_nan, code.T_NEAR);
}
// a > 0 && a < 0x00800000;
code.sub(tmp, 1);
code.cmp(tmp, 0x007FFFFF);
code.jb(fallback);
needs_fallback = true;
}
code.rsqrtss(result, operand);
if (ctx.FPCR().DN()) {
code.ucomiss(result, result);
code.jnp(end, code.T_NEAR);
} else {
// FZ ? (a >= 0x80800000 && a <= 0xFF800000) : (a >= 0x80000001 && a <= 0xFF800000)
// !FZ path takes into account the subtraction by one from the earlier block
code.add(tmp, ctx.FPCR().FZ() ? 0x7F800000 : 0x80000000);
code.cmp(tmp, ctx.FPCR().FZ() ? 0x7F000001 : 0x7F800000);
code.jnb(end, code.T_NEAR);
}
code.L(default_nan);
code.movd(result, code.XmmBConst<32>(xword, 0x7FC00000));
code.jmp(end, code.T_NEAR);
} else {
Xbyak::Label nan, zero;
code.movaps(value, operand);
DenormalsAreZero<fsize>(code, ctx, {value});
code.pxor(result, result);
code.ucomisd(value, result);
if (ctx.FPCR().DN()) {
code.jc(default_nan);
code.je(zero);
} else {
code.jp(nan);
code.je(zero);
code.jc(default_nan);
}
if (!ctx.FPCR().FZ()) {
needs_fallback = true;
code.jmp(fallback);
} else {
// result = 0
code.jmp(end, code.T_NEAR);
}
code.L(zero);
if (code.HasHostFeature(HostFeature::AVX)) {
code.vpor(result, value, code.XmmBConst<64>(xword, 0x7FF0'0000'0000'0000));
} else {
code.movaps(result, value);
code.por(result, code.XmmBConst<64>(xword, 0x7FF0'0000'0000'0000));
}
code.jmp(end, code.T_NEAR);
code.L(nan);
if (!ctx.FPCR().DN()) {
if (code.HasHostFeature(HostFeature::AVX)) {
code.vpor(result, operand, code.XmmBConst<64>(xword, 0x0008'0000'0000'0000));
code.ucomiss(result, result);
code.jnp(*end, code.T_NEAR);
} else {
code.movaps(result, operand);
code.por(result, code.XmmBConst<64>(xword, 0x0008'0000'0000'0000));
// FZ ? (a >= 0x80800000 && a <= 0xFF800000) : (a >= 0x80000001 && a <= 0xFF800000)
// !FZ path takes into account the subtraction by one from the earlier block
code.add(tmp, ctx.FPCR().FZ() ? 0x7F800000 : 0x80000000);
code.cmp(tmp, ctx.FPCR().FZ() ? 0x7F000001 : 0x7F800000);
code.jnb(*end, code.T_NEAR);
}
code.jmp(end, code.T_NEAR);
code.L(default_nan);
code.movd(result, code.XmmBConst<32>(xword, 0x7FC00000));
code.jmp(*end, code.T_NEAR);
} else {
Xbyak::Label nan, zero;
code.movaps(value, operand);
DenormalsAreZero<fsize>(code, ctx, {value});
code.pxor(result, result);
code.ucomisd(value, result);
if (ctx.FPCR().DN()) {
code.jc(default_nan);
code.je(zero);
} else {
code.jp(nan);
code.je(zero);
code.jc(default_nan);
}
if (!ctx.FPCR().FZ()) {
needs_fallback = true;
code.jmp(fallback);
} else {
// result = 0
code.jmp(*end, code.T_NEAR);
}
code.L(zero);
if (code.HasHostFeature(HostFeature::AVX)) {
code.vpor(result, value, code.XmmBConst<64>(xword, 0x7FF0'0000'0000'0000));
} else {
code.movaps(result, value);
code.por(result, code.XmmBConst<64>(xword, 0x7FF0'0000'0000'0000));
}
code.jmp(*end, code.T_NEAR);
code.L(nan);
if (!ctx.FPCR().DN()) {
if (code.HasHostFeature(HostFeature::AVX)) {
code.vpor(result, operand, code.XmmBConst<64>(xword, 0x0008'0000'0000'0000));
} else {
code.movaps(result, operand);
code.por(result, code.XmmBConst<64>(xword, 0x0008'0000'0000'0000));
}
code.jmp(*end, code.T_NEAR);
}
code.L(default_nan);
code.movq(result, code.XmmBConst<64>(xword, 0x7FF8'0000'0000'0000));
code.jmp(*end, code.T_NEAR);
}
code.L(default_nan);
code.movq(result, code.XmmBConst<64>(xword, 0x7FF8'0000'0000'0000));
code.jmp(end, code.T_NEAR);
}
code.L(fallback);
if (needs_fallback) {
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
code.lea(code.ABI_PARAM3, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPRSqrtEstimate<FPT>);
code.movq(result, rax);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
}
code.SwitchToNearCode();
code.L(fallback);
if (needs_fallback) {
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
code.lea(code.ABI_PARAM3, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPRSqrtEstimate<FPT>);
code.movq(result, rax);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(*end, code.T_NEAR);
}
});
ctx.reg_alloc.DefineValue(inst, result);
} else {
@@ -1201,7 +1205,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
}
if (code.HasHostFeature(HostFeature::FMA | HostFeature::AVX)) {
Xbyak::Label end, fallback;
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(args[0]);
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(args[1]);
@@ -1220,27 +1224,27 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
code.cmp(tmp.cvt16(), fsize == 32 ? 0x7f00 : 0x7fe0);
ctx.reg_alloc.Release(tmp);
code.jae(fallback, code.T_NEAR);
code.jae(*fallback, code.T_NEAR);
FCODE(vmuls)(result, result, code.XmmBConst<fsize>(xword, FP::FPValue<FPT, false, -1, 1>()));
code.L(end);
code.L(*end);
code.SwitchToFarCode();
code.L(fallback);
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPRSqrtStepFused<FPT>);
code.movq(result, code.ABI_RETURN);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPRSqrtStepFused<FPT>);
code.movq(result, code.ABI_RETURN);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
code.jmp(*end, code.T_NEAR);
});
ctx.reg_alloc.DefineValue(inst, result);
return;
@@ -1528,22 +1532,22 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
if constexpr (isize == 64) {
const Xbyak::Xmm scratch = ctx.reg_alloc.ScratchXmm();
Xbyak::Label saturate_max, end;
if (!unsigned_) {
SharedLabel saturate_max = GenSharedLabel(), end = GenSharedLabel();
ZeroIfNaN<64>(code, src, scratch);
code.movsd(scratch, code.XmmBConst<64>(xword, f64_max_s64_lim));
code.comisd(scratch, src);
code.jna(saturate_max, code.T_NEAR);
code.jna(*saturate_max, code.T_NEAR);
code.cvttsd2si(result, src); // 64 bit gpr
code.L(end);
code.L(*end);
code.SwitchToFarCode();
code.L(saturate_max);
code.mov(result, 0x7FFF'FFFF'FFFF'FFFF);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code] {
code.L(*saturate_max);
code.mov(result, 0x7FFF'FFFF'FFFF'FFFF);
code.jmp(*end, code.T_NEAR);
});
} else {
Xbyak::Label below_max;

View File

@@ -52,26 +52,27 @@ FakeCall AxxEmitX64::FastmemCallback(u64 rip_) {
template<std::size_t bitsize, auto callback>
void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const bool ordered = IsOrdered(args[1].GetImmediateAccType());
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
const auto fastmem_marker = ShouldFastmem(ctx, inst);
if (!conf.page_table && !fastmem_marker) {
// Neither fastmem nor page table: Use callbacks
if constexpr (bitsize == 128) {
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
ctx.reg_alloc.HostCall(nullptr, {}, args[1]);
if (ordered) {
code.mfence();
}
code.CallFunction(memory_read_128);
ctx.reg_alloc.DefineValue(inst, xmm1);
} else {
ctx.reg_alloc.HostCall(inst, {}, args[0]);
ctx.reg_alloc.HostCall(inst, {}, args[1]);
if (ordered) {
code.mfence();
}
Devirtualize<callback>(conf.callbacks).EmitCall(code);
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
}
EmitCheckMemoryAbort(ctx, inst);
return;
}
@@ -83,44 +84,50 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.ScratchGpr(HostLoc::RDX);
}
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[1]);
const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm().getIdx() : ctx.reg_alloc.ScratchGpr().getIdx();
const auto wrapped_fn = read_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
Xbyak::Label abort, end;
bool require_abort_handling = false;
SharedLabel abort = GenSharedLabel(), end = GenSharedLabel();
if (fastmem_marker) {
// Use fastmem
const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
bool require_abort_handling;
const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
fastmem_patch_info.emplace(
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_fastmem_failure,
});
ctx.deferred_emits.emplace_back([=, this, &ctx] {
code.L(*abort);
code.call(wrapped_fn);
fastmem_patch_info.emplace(
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_fastmem_failure,
});
EmitCheckMemoryAbort(ctx, inst, end.get());
code.jmp(*end, code.T_NEAR);
});
} else {
// Use page table
ASSERT(conf.page_table);
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
require_abort_handling = true;
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
}
code.L(end);
if (require_abort_handling) {
code.SwitchToFarCode();
code.L(abort);
code.call(wrapped_fn);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, this, &ctx] {
code.L(*abort);
code.call(wrapped_fn);
EmitCheckMemoryAbort(ctx, inst, end.get());
code.jmp(*end, code.T_NEAR);
});
}
code.L(*end);
if constexpr (bitsize == 128) {
ctx.reg_alloc.DefineValue(inst, Xbyak::Xmm{value_idx});
@@ -132,24 +139,25 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
template<std::size_t bitsize, auto callback>
void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
const auto fastmem_marker = ShouldFastmem(ctx, inst);
if (!conf.page_table && !fastmem_marker) {
// Neither fastmem nor page table: Use callbacks
if constexpr (bitsize == 128) {
ctx.reg_alloc.Use(args[0], ABI_PARAM2);
ctx.reg_alloc.Use(args[1], HostLoc::XMM1);
ctx.reg_alloc.Use(args[1], ABI_PARAM2);
ctx.reg_alloc.Use(args[2], HostLoc::XMM1);
ctx.reg_alloc.EndOfAllocScope();
ctx.reg_alloc.HostCall(nullptr);
code.CallFunction(memory_write_128);
} else {
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
ctx.reg_alloc.HostCall(nullptr, {}, args[1], args[2]);
Devirtualize<callback>(conf.callbacks).EmitCall(code);
}
if (ordered) {
code.mfence();
}
EmitCheckMemoryAbort(ctx, inst);
return;
}
@@ -161,58 +169,64 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.ScratchGpr(HostLoc::RDX);
}
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[1]);
const int value_idx = bitsize == 128
? ctx.reg_alloc.UseXmm(args[1]).getIdx()
: (ordered ? ctx.reg_alloc.UseScratchGpr(args[1]).getIdx() : ctx.reg_alloc.UseGpr(args[1]).getIdx());
? ctx.reg_alloc.UseXmm(args[2]).getIdx()
: (ordered ? ctx.reg_alloc.UseScratchGpr(args[2]).getIdx() : ctx.reg_alloc.UseGpr(args[2]).getIdx());
const auto wrapped_fn = write_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
Xbyak::Label abort, end;
bool require_abort_handling = false;
SharedLabel abort = GenSharedLabel(), end = GenSharedLabel();
if (fastmem_marker) {
// Use fastmem
const auto dest_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
bool require_abort_handling;
const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
const auto location = EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
fastmem_patch_info.emplace(
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_fastmem_failure,
});
ctx.deferred_emits.emplace_back([=, this, &ctx] {
code.L(*abort);
code.call(wrapped_fn);
fastmem_patch_info.emplace(
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_fastmem_failure,
});
EmitCheckMemoryAbort(ctx, inst, end.get());
code.jmp(*end, code.T_NEAR);
});
} else {
// Use page table
ASSERT(conf.page_table);
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
require_abort_handling = true;
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
}
code.L(end);
if (require_abort_handling) {
code.SwitchToFarCode();
code.L(abort);
code.call(wrapped_fn);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, this, &ctx] {
code.L(*abort);
code.call(wrapped_fn);
EmitCheckMemoryAbort(ctx, inst, end.get());
code.jmp(*end, code.T_NEAR);
});
}
code.L(*end);
}
template<std::size_t bitsize, auto callback>
void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
ASSERT(conf.global_monitor != nullptr);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const bool ordered = IsOrdered(args[1].GetImmediateAccType());
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
if constexpr (bitsize != 128) {
using T = mcl::unsigned_integer_of_size<bitsize>;
ctx.reg_alloc.HostCall(inst, {}, args[0]);
ctx.reg_alloc.HostCall(inst, {}, args[1]);
code.mov(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(1));
code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf));
@@ -228,7 +242,7 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
} else {
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
ctx.reg_alloc.Use(args[0], ABI_PARAM2);
ctx.reg_alloc.Use(args[1], ABI_PARAM2);
ctx.reg_alloc.EndOfAllocScope();
ctx.reg_alloc.HostCall(nullptr);
@@ -250,19 +264,21 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
EmitCheckMemoryAbort(ctx, inst);
}
template<std::size_t bitsize, auto callback>
void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) {
ASSERT(conf.global_monitor != nullptr);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
if constexpr (bitsize != 128) {
ctx.reg_alloc.HostCall(inst, {}, args[0], args[1]);
ctx.reg_alloc.HostCall(inst, {}, args[1], args[2]);
} else {
ctx.reg_alloc.Use(args[0], ABI_PARAM2);
ctx.reg_alloc.Use(args[1], HostLoc::XMM1);
ctx.reg_alloc.Use(args[1], ABI_PARAM2);
ctx.reg_alloc.Use(args[2], HostLoc::XMM1);
ctx.reg_alloc.EndOfAllocScope();
ctx.reg_alloc.HostCall(inst);
}
@@ -308,6 +324,8 @@ void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.ReleaseStackSpace(16 + ABI_SHADOW_SPACE);
}
code.L(end);
EmitCheckMemoryAbort(ctx, inst);
}
template<std::size_t bitsize, auto callback>
@@ -329,7 +347,7 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
ctx.reg_alloc.ScratchGpr(HostLoc::RDX);
}
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[1]);
const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm().getIdx() : ctx.reg_alloc.ScratchGpr().getIdx();
const Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr();
const Xbyak::Reg64 tmp2 = ctx.reg_alloc.ScratchGpr();
@@ -344,10 +362,10 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
const auto fastmem_marker = ShouldFastmem(ctx, inst);
if (fastmem_marker) {
Xbyak::Label abort, end;
SharedLabel abort = GenSharedLabel(), end = GenSharedLabel();
bool require_abort_handling = false;
const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
@@ -360,14 +378,14 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
conf.recompile_on_exclusive_fastmem_failure,
});
code.L(end);
code.L(*end);
if (require_abort_handling) {
code.SwitchToFarCode();
code.L(abort);
code.call(wrapped_fn);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, this] {
code.L(*abort);
code.call(wrapped_fn);
code.jmp(*end, code.T_NEAR);
});
}
} else {
code.call(wrapped_fn);
@@ -383,6 +401,8 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
} else {
ctx.reg_alloc.DefineValue(inst, Xbyak::Reg64{value_idx});
}
EmitCheckMemoryAbort(ctx, inst);
}
template<std::size_t bitsize, auto callback>
@@ -402,13 +422,13 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
ctx.reg_alloc.ScratchGpr(HostLoc::RBX);
ctx.reg_alloc.ScratchGpr(HostLoc::RCX);
ctx.reg_alloc.ScratchGpr(HostLoc::RDX);
return ctx.reg_alloc.UseXmm(args[1]);
return ctx.reg_alloc.UseXmm(args[2]);
} else {
ctx.reg_alloc.ScratchGpr(HostLoc::RAX);
return ctx.reg_alloc.UseGpr(args[1]);
return ctx.reg_alloc.UseGpr(args[2]);
}
}();
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[1]);
const Xbyak::Reg32 status = ctx.reg_alloc.ScratchGpr().cvt32();
const Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr();
@@ -416,14 +436,14 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
EmitExclusiveLock(code, conf, tmp, eax);
Xbyak::Label end;
SharedLabel end = GenSharedLabel();
code.mov(tmp, mcl::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id)));
code.mov(status, u32(1));
code.cmp(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(0));
code.je(end, code.T_NEAR);
code.je(*end, code.T_NEAR);
code.cmp(qword[tmp], vaddr);
code.jne(end, code.T_NEAR);
code.jne(*end, code.T_NEAR);
EmitExclusiveTestAndClear(code, conf, vaddr, tmp, rax);
@@ -448,10 +468,10 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
const auto fastmem_marker = ShouldFastmem(ctx, inst);
if (fastmem_marker) {
Xbyak::Label abort;
SharedLabel abort = GenSharedLabel();
bool require_abort_handling = false;
const auto dest_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling, tmp);
const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling, tmp);
const auto location = code.getCurr();
@@ -483,24 +503,24 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
code.setnz(status.cvt8());
code.SwitchToFarCode();
code.L(abort);
code.call(wrapped_fn);
ctx.deferred_emits.emplace_back([=, this] {
code.L(*abort);
code.call(wrapped_fn);
fastmem_patch_info.emplace(
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_exclusive_fastmem_failure,
});
fastmem_patch_info.emplace(
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_exclusive_fastmem_failure,
});
code.cmp(al, 0);
code.setz(status.cvt8());
code.movzx(status.cvt32(), status.cvt8());
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
code.cmp(al, 0);
code.setz(status.cvt8());
code.movzx(status.cvt32(), status.cvt8());
code.jmp(*end, code.T_NEAR);
});
} else {
code.call(wrapped_fn);
code.cmp(al, 0);
@@ -508,11 +528,13 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
code.movzx(status.cvt32(), status.cvt8());
}
code.L(end);
code.L(*end);
EmitExclusiveUnlock(code, conf, tmp, eax);
ctx.reg_alloc.DefineValue(inst, status);
EmitCheckMemoryAbort(ctx, inst);
}
#undef AxxEmitX64

View File

@@ -53,19 +53,19 @@ void EmitDetectMisalignedVAddr(BlockOfCode& code, EmitContext& ctx, size_t bitsi
const u32 page_align_mask = static_cast<u32>(page_size - 1) & ~align_mask;
Xbyak::Label detect_boundary, resume;
SharedLabel detect_boundary = GenSharedLabel(), resume = GenSharedLabel();
code.jnz(detect_boundary, code.T_NEAR);
code.L(resume);
code.jnz(*detect_boundary, code.T_NEAR);
code.L(*resume);
code.SwitchToFarCode();
code.L(detect_boundary);
code.mov(tmp, vaddr);
code.and_(tmp, page_align_mask);
code.cmp(tmp, page_align_mask);
code.jne(resume, code.T_NEAR);
// NOTE: We expect to fallthrough into abort code here.
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code] {
code.L(*detect_boundary);
code.mov(tmp, vaddr);
code.and_(tmp, page_align_mask);
code.cmp(tmp, page_align_mask);
code.jne(*resume, code.T_NEAR);
// NOTE: We expect to fallthrough into abort code here.
});
}
template<typename EmitContext>

View File

@@ -112,36 +112,35 @@ void HandleNaNs(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, std::
code.cmp(bitmask, 0);
}
Xbyak::Label end;
Xbyak::Label nan;
SharedLabel end = GenSharedLabel(), nan = GenSharedLabel();
code.jnz(nan, code.T_NEAR);
code.L(end);
code.jnz(*nan, code.T_NEAR);
code.L(*end);
code.SwitchToFarCode();
code.L(nan);
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*nan);
const Xbyak::Xmm result = xmms[0];
const Xbyak::Xmm result = xmms[0];
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
const size_t stack_space = xmms.size() * 16;
code.sub(rsp, 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]);
}
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.mov(code.ABI_PARAM2, ctx.FPCR(fpcr_controlled).Value());
const size_t stack_space = xmms.size() * 16;
code.sub(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]);
}
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.mov(code.ABI_PARAM2, ctx.FPCR(fpcr_controlled).Value());
code.CallFunction(nan_handler);
code.CallFunction(nan_handler);
code.movaps(result, xword[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.add(rsp, stack_space + ABI_SHADOW_SPACE);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
code.movaps(result, xword[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.add(rsp, static_cast<u32>(stack_space + ABI_SHADOW_SPACE));
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(*end, code.T_NEAR);
});
}
template<size_t fsize>
@@ -1117,7 +1116,7 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm xmm_c = ctx.reg_alloc.UseXmm(args[2]);
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm();
Xbyak::Label end, fallback;
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
code.movaps(result, xmm_a);
@@ -1127,19 +1126,19 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.andnps(tmp, result);
FCODE(vcmpeq_uqp)(tmp, tmp, GetSmallestNormalVector<fsize>(code));
code.vptest(tmp, tmp);
code.jnz(fallback, code.T_NEAR);
code.L(end);
code.jnz(*fallback, code.T_NEAR);
code.L(*end);
});
code.SwitchToFarCode();
code.L(fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitFourOpFallbackWithoutRegAlloc(code, ctx, result, xmm_a, xmm_b, xmm_c, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitFourOpFallbackWithoutRegAlloc(code, ctx, result, xmm_a, xmm_b, xmm_c, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(*end, code.T_NEAR);
});
ctx.reg_alloc.DefineValue(inst, result);
return;
@@ -1377,7 +1376,7 @@ static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(args[1]);
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm();
Xbyak::Label end, fallback;
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
code.movaps(result, GetVectorOf<fsize, false, 0, 2>(code));
@@ -1385,19 +1384,19 @@ static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
FCODE(vcmpunordp)(tmp, result, result);
code.vptest(tmp, tmp);
code.jnz(fallback, code.T_NEAR);
code.L(end);
code.jnz(*fallback, code.T_NEAR);
code.L(*end);
});
code.SwitchToFarCode();
code.L(fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(*end, code.T_NEAR);
});
ctx.reg_alloc.DefineValue(inst, result);
return;
@@ -1591,7 +1590,7 @@ static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm();
const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm();
Xbyak::Label end, fallback;
SharedLabel end = GenSharedLabel(), fallback = GenSharedLabel();
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
code.vmovaps(result, GetVectorOf<fsize, false, 0, 3>(code));
@@ -1602,21 +1601,21 @@ static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
FCODE(vandp)(tmp, result, mask);
ICODE(vpcmpeq)(tmp, tmp, mask);
code.ptest(tmp, tmp);
code.jnz(fallback, code.T_NEAR);
code.jnz(*fallback, code.T_NEAR);
FCODE(vmulp)(result, result, GetVectorOf<fsize, false, -1, 1>(code));
code.L(end);
code.L(*end);
});
code.SwitchToFarCode();
code.L(fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(end, code.T_NEAR);
code.SwitchToNearCode();
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.add(rsp, 8);
code.jmp(*end, code.T_NEAR);
});
ctx.reg_alloc.DefineValue(inst, result);
return;

View File

@@ -69,6 +69,10 @@ std::string DisassembleAArch32([[maybe_unused]] bool is_thumb, [[maybe_unused]]
char buffer[1024];
while (length) {
size_t inst_size = LLVMDisasmInstruction(llvm_ctx, const_cast<u8*>(instructions), length, pc, buffer, sizeof(buffer));
const char* const disassembled = inst_size > 0 ? buffer : "<invalid instruction>";
if (inst_size == 0)
inst_size = is_thumb ? 2 : 4;
result += fmt::format("{:08x} ", pc);
for (size_t i = 0; i < 4; i++) {
@@ -78,11 +82,9 @@ std::string DisassembleAArch32([[maybe_unused]] bool is_thumb, [[maybe_unused]]
result += " ";
}
}
result += inst_size > 0 ? buffer : "<invalid instruction>";
result += disassembled;
result += '\n';
if (inst_size == 0)
inst_size = is_thumb ? 2 : 4;
if (length <= inst_size)
break;
@@ -111,7 +113,8 @@ std::string DisassembleAArch64([[maybe_unused]] u32 instruction, [[maybe_unused]
char buffer[80];
size_t inst_size = LLVMDisasmInstruction(llvm_ctx, (u8*)&instruction, sizeof(instruction), pc, buffer, sizeof(buffer));
result = inst_size > 0 ? buffer : "<invalid instruction>";
result = fmt::format("{:016x} {:08x} ", pc, instruction);
result += inst_size > 0 ? buffer : "<invalid instruction>";
result += '\n';
LLVMDisasmDispose(llvm_ctx);

View File

@@ -245,40 +245,40 @@ IR::UAny IREmitter::ReadMemory(size_t bitsize, const IR::U32& vaddr, IR::AccType
}
IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A32ReadMemory8, vaddr, IR::Value{acc_type});
return Inst<IR::U8>(Opcode::A32ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 IREmitter::ReadMemory16(const IR::U32& vaddr, IR::AccType acc_type) {
const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, vaddr, IR::Value{acc_type});
const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
return current_location.EFlag() ? ByteReverseHalf(value) : value;
}
IR::U32 IREmitter::ReadMemory32(const IR::U32& vaddr, IR::AccType acc_type) {
const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, vaddr, IR::Value{acc_type});
const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
return current_location.EFlag() ? ByteReverseWord(value) : value;
}
IR::U64 IREmitter::ReadMemory64(const IR::U32& vaddr, IR::AccType acc_type) {
const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, vaddr, IR::Value{acc_type});
const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
return current_location.EFlag() ? ByteReverseDual(value) : value;
}
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, vaddr, IR::Value{acc_type});
return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U32& vaddr, IR::AccType acc_type) {
const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, vaddr, IR::Value{acc_type});
const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
return current_location.EFlag() ? ByteReverseHalf(value) : value;
}
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U32& vaddr, IR::AccType acc_type) {
const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, vaddr, IR::Value{acc_type});
const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
return current_location.EFlag() ? ByteReverseWord(value) : value;
}
std::pair<IR::U32, IR::U32> IREmitter::ExclusiveReadMemory64(const IR::U32& vaddr, IR::AccType acc_type) {
const auto value = Inst<IR::U64>(Opcode::A32ExclusiveReadMemory64, vaddr, IR::Value{acc_type});
const auto value = Inst<IR::U64>(Opcode::A32ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
const auto lo = LeastSignificantWord(value);
const auto hi = MostSignificantWord(value).result;
if (current_location.EFlag()) {
@@ -303,55 +303,55 @@ void IREmitter::WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny
}
void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) {
Inst(Opcode::A32WriteMemory8, vaddr, value, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type) {
if (current_location.EFlag()) {
const auto v = ByteReverseHalf(value);
Inst(Opcode::A32WriteMemory16, vaddr, v, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, v, IR::Value{acc_type});
} else {
Inst(Opcode::A32WriteMemory16, vaddr, value, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
}
void IREmitter::WriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type) {
if (current_location.EFlag()) {
const auto v = ByteReverseWord(value);
Inst(Opcode::A32WriteMemory32, vaddr, v, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, v, IR::Value{acc_type});
} else {
Inst(Opcode::A32WriteMemory32, vaddr, value, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
}
void IREmitter::WriteMemory64(const IR::U32& vaddr, const IR::U64& value, IR::AccType acc_type) {
if (current_location.EFlag()) {
const auto v = ByteReverseDual(value);
Inst(Opcode::A32WriteMemory64, vaddr, v, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, v, IR::Value{acc_type});
} else {
Inst(Opcode::A32WriteMemory64, vaddr, value, IR::Value{acc_type});
Inst(Opcode::A32WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
}
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory8, vaddr, value, IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type) {
if (current_location.EFlag()) {
const auto v = ByteReverseHalf(value);
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, v, IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, v, IR::Value{acc_type});
} else {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, value, IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
}
IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type) {
if (current_location.EFlag()) {
const auto v = ByteReverseWord(value);
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, v, IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, v, IR::Value{acc_type});
} else {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, value, IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
}
@@ -359,9 +359,9 @@ IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& v
if (current_location.EFlag()) {
const auto vlo = ByteReverseWord(value_lo);
const auto vhi = ByteReverseWord(value_hi);
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(vlo, vhi), IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, Pack2x32To1x64(vlo, vhi), IR::Value{acc_type});
} else {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(value_lo, value_hi), IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, Pack2x32To1x64(value_lo, value_hi), IR::Value{acc_type});
}
}
@@ -439,4 +439,8 @@ void IREmitter::CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer,
Inst(Opcode::A32CoprocStoreWords, IR::Value(coproc_info), address);
}
IR::U64 IREmitter::ImmCurrentLocationDescriptor() {
return Imm64(IR::LocationDescriptor{current_location}.Value());
}
} // namespace Dynarmic::A32

View File

@@ -110,6 +110,7 @@ public:
private:
enum ArchVersion arch_version;
IR::U64 ImmCurrentLocationDescriptor();
};
} // namespace Dynarmic::A32

View File

@@ -29,12 +29,6 @@ struct TranslationOptions {
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
/// This changes what IR we emit when we translate a memory instruction.
/// If this is false, memory accesses are not considered terminal.
/// If this is true, memory access are considered terminal. This allows
/// accurately emulating protection fault handlers.
bool check_halt_on_memory_access = false;
};
/**

View File

@@ -53,15 +53,6 @@ bool TranslatorVisitor::RaiseException(Exception exception) {
return false;
}
bool TranslatorVisitor::MemoryInstructionContinues() {
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(static_cast<s32>(current_instruction_size))});
return false;
}
return true;
}
IR::UAny TranslatorVisitor::I(size_t bitsize, u64 value) {
switch (bitsize) {
case 8:

View File

@@ -41,7 +41,6 @@ struct TranslatorVisitor final {
bool UndefinedInstruction();
bool DecodeError();
bool RaiseException(Exception exception);
bool MemoryInstructionContinues();
struct ImmAndCarry {
u32 imm32;

View File

@@ -119,7 +119,7 @@ bool TranslatorVisitor::v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s
}
}
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t size, size_t align, Reg m) {
@@ -176,7 +176,7 @@ bool TranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s
}
}
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::v8_VLD_all_lanes(bool D, Reg n, size_t Vd, size_t nn, size_t sz, bool T, bool a, Reg m) {
@@ -241,7 +241,7 @@ bool TranslatorVisitor::v8_VLD_all_lanes(bool D, Reg n, size_t Vd, size_t nn, si
}
}
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::v8_VST_single(bool D, Reg n, size_t Vd, size_t sz, size_t nn, size_t index_align, Reg m) {
@@ -305,7 +305,7 @@ bool TranslatorVisitor::v8_VST_single(bool D, Reg n, size_t Vd, size_t sz, size_
}
}
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::v8_VLD_single(bool D, Reg n, size_t Vd, size_t sz, size_t nn, size_t index_align, Reg m) {
@@ -370,6 +370,6 @@ bool TranslatorVisitor::v8_VLD_single(bool D, Reg n, size_t Vd, size_t sz, size_
}
}
return MemoryInstructionContinues();
return true;
}
} // namespace Dynarmic::A32

View File

@@ -83,7 +83,7 @@ bool TranslatorVisitor::arm_LDR_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDR <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -120,7 +120,7 @@ bool TranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDR <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -150,7 +150,7 @@ bool TranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRB <Rt>, [PC, #+/-<imm>]
@@ -170,7 +170,7 @@ bool TranslatorVisitor::arm_LDRB_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRB <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -199,7 +199,7 @@ bool TranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRB <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -223,7 +223,7 @@ bool TranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRD <Rt>, <Rt2>, [PC, #+/-<imm>]
@@ -257,7 +257,7 @@ bool TranslatorVisitor::arm_LDRD_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm
ir.SetRegister(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result);
}
return MemoryInstructionContinues();
return true;
}
// LDRD <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -303,7 +303,7 @@ bool TranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, R
ir.SetRegister(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result);
}
return MemoryInstructionContinues();
return true;
}
// LDRD <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -343,7 +343,7 @@ bool TranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R
ir.SetRegister(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result);
}
return MemoryInstructionContinues();
return true;
}
// LDRH <Rt>, [PC, #-/+<imm>]
@@ -368,7 +368,7 @@ bool TranslatorVisitor::arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, I
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRH <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -397,7 +397,7 @@ bool TranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRH <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -421,7 +421,7 @@ bool TranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRSB <Rt>, [PC, #+/-<imm>]
@@ -442,7 +442,7 @@ bool TranslatorVisitor::arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Im
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRSB <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -471,7 +471,7 @@ bool TranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRSB <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -495,7 +495,7 @@ bool TranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRSH <Rt>, [PC, #-/+<imm>]
@@ -515,7 +515,7 @@ bool TranslatorVisitor::arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Im
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRSH <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -544,7 +544,7 @@ bool TranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRSH <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -568,7 +568,7 @@ bool TranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// STR <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -585,7 +585,7 @@ bool TranslatorVisitor::arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re
const auto offset = ir.Imm32(imm12.ZeroExtend());
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STR <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -606,7 +606,7 @@ bool TranslatorVisitor::arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re
const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STRB <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -627,7 +627,7 @@ bool TranslatorVisitor::arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto offset = ir.Imm32(imm12.ZeroExtend());
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STRB <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -648,7 +648,7 @@ bool TranslatorVisitor::arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STRD <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -686,7 +686,7 @@ bool TranslatorVisitor::arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, R
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
ir.WriteMemory64(address, data, IR::AccType::ATOMIC);
return MemoryInstructionContinues();
return true;
}
// STRD <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -723,7 +723,7 @@ bool TranslatorVisitor::arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
ir.WriteMemory64(address, data, IR::AccType::ATOMIC);
return MemoryInstructionContinues();
return true;
}
// STRH <Rt>, [<Rn>, #+/-<imm>]{!}
@@ -746,7 +746,7 @@ bool TranslatorVisitor::arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STRH <Rt>, [<Rn>, #+/-<Rm>]{!}
@@ -768,31 +768,29 @@ bool TranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
static bool LDMHelper(TranslatorVisitor& v, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
v.ir.SetRegister(static_cast<Reg>(i), v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = v.ir.Add(address, v.ir.Imm32(4));
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = ir.Add(address, ir.Imm32(4));
}
}
if (W && !mcl::bit::get_bit(RegNumber(n), list)) {
v.ir.SetRegister(n, writeback_address);
ir.SetRegister(n, writeback_address);
}
if (mcl::bit::get_bit<15>(list)) {
v.ir.LoadWritePC(v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (v.options.check_halt_on_memory_access)
v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
else if (n == Reg::R13)
v.ir.SetTerm(IR::Term::PopRSBHint{});
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (n == Reg::R13)
ir.SetTerm(IR::Term::PopRSBHint{});
else
v.ir.SetTerm(IR::Term::FastDispatchHint{});
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
return v.MemoryInstructionContinues();
return true;
}
// LDM <Rn>{!}, <reg_list>
@@ -810,7 +808,7 @@ bool TranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4)));
return LDMHelper(*this, W, n, list, start_address, writeback_address);
return LDMHelper(ir, W, n, list, start_address, writeback_address);
}
// LDMDA <Rn>{!}, <reg_list>
@@ -828,7 +826,7 @@ bool TranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list) - 4)));
const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
return LDMHelper(*this, W, n, list, start_address, writeback_address);
return LDMHelper(ir, W, n, list, start_address, writeback_address);
}
// LDMDB <Rn>{!}, <reg_list>
@@ -846,7 +844,7 @@ bool TranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = start_address;
return LDMHelper(*this, W, n, list, start_address, writeback_address);
return LDMHelper(ir, W, n, list, start_address, writeback_address);
}
// LDMIB <Rn>{!}, <reg_list>
@@ -864,7 +862,7 @@ bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
return LDMHelper(*this, W, n, list, start_address, writeback_address);
return LDMHelper(ir, W, n, list, start_address, writeback_address);
}
bool TranslatorVisitor::arm_LDM_usr() {
@@ -875,21 +873,21 @@ bool TranslatorVisitor::arm_LDM_eret() {
return InterpretThisInstruction();
}
static bool STMHelper(TranslatorVisitor& v, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
v.ir.WriteMemory32(address, v.ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = v.ir.Add(address, v.ir.Imm32(4));
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = ir.Add(address, ir.Imm32(4));
}
}
if (W) {
v.ir.SetRegister(n, writeback_address);
ir.SetRegister(n, writeback_address);
}
if (mcl::bit::get_bit<15>(list)) {
v.ir.WriteMemory32(address, v.ir.Imm32(v.ir.PC()), IR::AccType::ATOMIC);
ir.WriteMemory32(address, ir.Imm32(ir.PC()), IR::AccType::ATOMIC);
}
return v.MemoryInstructionContinues();
return true;
}
// STM <Rn>{!}, <reg_list>
@@ -904,7 +902,7 @@ bool TranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4)));
return STMHelper(*this, W, n, list, start_address, writeback_address);
return STMHelper(ir, W, n, list, start_address, writeback_address);
}
// STMDA <Rn>{!}, <reg_list>
@@ -919,7 +917,7 @@ bool TranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list) - 4)));
const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
return STMHelper(*this, W, n, list, start_address, writeback_address);
return STMHelper(ir, W, n, list, start_address, writeback_address);
}
// STMDB <Rn>{!}, <reg_list>
@@ -934,7 +932,7 @@ bool TranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = start_address;
return STMHelper(*this, W, n, list, start_address, writeback_address);
return STMHelper(ir, W, n, list, start_address, writeback_address);
}
// STMIB <Rn>{!}, <reg_list>
@@ -949,7 +947,7 @@ bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
return STMHelper(*this, W, n, list, start_address, writeback_address);
return STMHelper(ir, W, n, list, start_address, writeback_address);
}
bool TranslatorVisitor::arm_STM_usr() {

View File

@@ -29,7 +29,7 @@ bool TranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) {
ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2), IR::AccType::SWAP);
// TODO: Alignment check
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// SWPB<c> <Rt>, <Rt2>, [<Rn>]
@@ -48,7 +48,7 @@ bool TranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2)), IR::AccType::SWAP);
// TODO: Alignment check
ir.SetRegister(t, ir.ZeroExtendByteToWord(data));
return MemoryInstructionContinues();
return true;
}
// LDA<c> <Rt>, [<Rn>]
@@ -63,7 +63,7 @@ bool TranslatorVisitor::arm_LDA(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ReadMemory32(address, IR::AccType::ORDERED));
return MemoryInstructionContinues();
return true;
}
// LDAB<c> <Rt>, [<Rn>]
bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) {
@@ -77,7 +77,7 @@ bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory8(address, IR::AccType::ORDERED)));
return MemoryInstructionContinues();
return true;
}
// LDAH<c> <Rt>, [<Rn>]
bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) {
@@ -91,7 +91,7 @@ bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory16(address, IR::AccType::ORDERED)));
return MemoryInstructionContinues();
return true;
}
// LDAEX<c> <Rt>, [<Rn>]
@@ -106,7 +106,7 @@ bool TranslatorVisitor::arm_LDAEX(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ORDERED));
return MemoryInstructionContinues();
return true;
}
// LDAEXB<c> <Rt>, [<Rn>]
@@ -121,7 +121,7 @@ bool TranslatorVisitor::arm_LDAEXB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ORDERED)));
return MemoryInstructionContinues();
return true;
}
// LDAEXD<c> <Rt>, <Rt2>, [<Rn>]
@@ -139,7 +139,7 @@ bool TranslatorVisitor::arm_LDAEXD(Cond cond, Reg n, Reg t) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo);
ir.SetRegister(t + 1, hi);
return MemoryInstructionContinues();
return true;
}
// LDAEXH<c> <Rt>, [<Rn>]
@@ -154,7 +154,7 @@ bool TranslatorVisitor::arm_LDAEXH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ORDERED)));
return MemoryInstructionContinues();
return true;
}
// STL<c> <Rt>, [<Rn>]
@@ -169,7 +169,7 @@ bool TranslatorVisitor::arm_STL(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED);
return MemoryInstructionContinues();
return true;
}
// STLB<c> <Rt>, [<Rn>]
@@ -184,7 +184,7 @@ bool TranslatorVisitor::arm_STLB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::ORDERED);
return MemoryInstructionContinues();
return true;
}
// STLH<c> <Rd>, <Rt>, [<Rn>]
@@ -199,7 +199,7 @@ bool TranslatorVisitor::arm_STLH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::ORDERED);
return MemoryInstructionContinues();
return true;
}
// STLEXB<c> <Rd>, <Rt>, [<Rn>]
@@ -220,7 +220,7 @@ bool TranslatorVisitor::arm_STLEXB(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// STLEXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
bool TranslatorVisitor::arm_STLEXD(Cond cond, Reg n, Reg d, Reg t) {
@@ -242,7 +242,7 @@ bool TranslatorVisitor::arm_STLEXD(Cond cond, Reg n, Reg d, Reg t) {
const auto value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// STLEXH<c> <Rd>, <Rt>, [<Rn>]
@@ -263,7 +263,7 @@ bool TranslatorVisitor::arm_STLEXH(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// STLEX<c> <Rd>, <Rt>, [<Rn>]
@@ -284,7 +284,7 @@ bool TranslatorVisitor::arm_STLEX(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// LDREX<c> <Rt>, [<Rn>]
@@ -299,7 +299,7 @@ bool TranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC));
return MemoryInstructionContinues();
return true;
}
// LDREXB<c> <Rt>, [<Rn>]
@@ -314,7 +314,7 @@ bool TranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC)));
return MemoryInstructionContinues();
return true;
}
// LDREXD<c> <Rt>, <Rt2>, [<Rn>]
@@ -332,7 +332,7 @@ bool TranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo);
ir.SetRegister(t + 1, hi);
return MemoryInstructionContinues();
return true;
}
// LDREXH<c> <Rt>, [<Rn>]
@@ -347,7 +347,7 @@ bool TranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC)));
return MemoryInstructionContinues();
return true;
}
// STREX<c> <Rd>, <Rt>, [<Rn>]
@@ -368,7 +368,7 @@ bool TranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// STREXB<c> <Rd>, <Rt>, [<Rn>]
@@ -389,7 +389,7 @@ bool TranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
@@ -412,7 +412,7 @@ bool TranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg t) {
const auto value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
// STREXH<c> <Rd>, <Rt>, [<Rn>]
@@ -433,7 +433,7 @@ bool TranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
} // namespace Dynarmic::A32

View File

@@ -449,7 +449,7 @@ bool TranslatorVisitor::thumb16_LDR_literal(Reg t, Imm<8> imm8) {
const auto data = ir.ReadMemory32(ir.Imm32(address), IR::AccType::NORMAL);
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// STR <Rt>, [<Rn>, <Rm>]
@@ -459,7 +459,7 @@ bool TranslatorVisitor::thumb16_STR_reg(Reg m, Reg n, Reg t) {
const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STRH <Rt>, [<Rn>, <Rm>]
@@ -469,7 +469,7 @@ bool TranslatorVisitor::thumb16_STRH_reg(Reg m, Reg n, Reg t) {
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
ir.WriteMemory16(address, data, IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// STRB <Rt>, [<Rn>, <Rm>]
@@ -479,7 +479,7 @@ bool TranslatorVisitor::thumb16_STRB_reg(Reg m, Reg n, Reg t) {
const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
ir.WriteMemory8(address, data, IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// LDRSB <Rt>, [<Rn>, <Rm>]
@@ -489,7 +489,7 @@ bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDR <Rt>, [<Rn>, <Rm>]
@@ -499,7 +499,7 @@ bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) {
const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRH <Rt>, [<Rn>, <Rm>]
@@ -509,7 +509,7 @@ bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRB <Rt>, [<Rn>, <Rm>]
@@ -519,7 +519,7 @@ bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// LDRH <Rt>, [<Rn>, <Rm>]
@@ -529,7 +529,7 @@ bool TranslatorVisitor::thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// STR <Rt>, [<Rn>, #<imm>]
@@ -540,7 +540,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// LDR <Rt>, [<Rn>, #<imm>]
@@ -551,7 +551,7 @@ bool TranslatorVisitor::thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// STRB <Rt>, [<Rn>, #<imm>]
@@ -573,7 +573,7 @@ bool TranslatorVisitor::thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// STRH <Rt>, [<Rn>, #<imm5>]
@@ -583,7 +583,7 @@ bool TranslatorVisitor::thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
ir.WriteMemory16(address, data, IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// LDRH <Rt>, [<Rn>, #<imm5>]
@@ -593,7 +593,7 @@ bool TranslatorVisitor::thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// STR <Rt>, [<Rn>, #<imm>]
@@ -605,7 +605,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t2(Reg t, Imm<8> imm8) {
const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return MemoryInstructionContinues();
return true;
}
// LDR <Rt>, [<Rn>, #<imm>]
@@ -617,7 +617,7 @@ bool TranslatorVisitor::thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
// ADR <Rd>, <label>
@@ -775,7 +775,7 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) {
ir.SetRegister(Reg::SP, final_address);
// TODO(optimization): Possible location for an RSB push.
return MemoryInstructionContinues();
return true;
}
// POP <reg_list>
@@ -804,15 +804,11 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
ir.LoadWritePC(data);
address = ir.Add(address, ir.Imm32(4));
ir.SetRegister(Reg::SP, address);
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}});
} else {
ir.SetTerm(IR::Term::PopRSBHint{});
}
ir.SetTerm(IR::Term::PopRSBHint{});
return false;
} else {
ir.SetRegister(Reg::SP, address);
return MemoryInstructionContinues();
return true;
}
}
@@ -891,7 +887,7 @@ bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) {
}
ir.SetRegister(n, address);
return MemoryInstructionContinues();
return true;
}
// LDM <Rn>!, <reg_list>
@@ -914,7 +910,7 @@ bool TranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) {
if (write_back) {
ir.SetRegister(n, address);
}
return MemoryInstructionContinues();
return true;
}
// CB{N}Z <Rn>, <label>

View File

@@ -34,7 +34,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(v.ir.Imm32(address), IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return v.MemoryInstructionContinues();
return true;
}
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
@@ -49,7 +49,7 @@ static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address, IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return v.MemoryInstructionContinues();
return true;
}
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
@@ -64,7 +64,7 @@ static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U
if (W) {
v.ir.SetRegister(n, offset_address);
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_PLD_lit(bool /*U*/, Imm<12> /*imm12*/) {

View File

@@ -16,7 +16,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory16(v.ir.Imm32(address), IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return v.MemoryInstructionContinues();
return true;
}
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
@@ -31,7 +31,7 @@ static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address, IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return v.MemoryInstructionContinues();
return true;
}
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
@@ -48,7 +48,7 @@ static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U
}
v.ir.SetRegister(t, data);
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) {

View File

@@ -36,11 +36,7 @@ static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) {
v.ir.UpdateUpperLocationDescriptor();
v.ir.BranchWritePC(branch_value);
if (v.options.check_halt_on_memory_access) {
v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
v.ir.SetTerm(IR::Term::FastDispatchHint{});
}
v.ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
@@ -72,7 +68,7 @@ static bool LoadDualImmediate(TranslatorVisitor& v, bool P, bool U, bool W, Reg
if (W) {
v.ir.SetRegister(n, offset_address);
}
return v.MemoryInstructionContinues();
return true;
}
static bool LoadDualLiteral(TranslatorVisitor& v, bool U, bool W, Reg t, Reg t2, Imm<8> imm8) {
@@ -98,7 +94,7 @@ static bool LoadDualLiteral(TranslatorVisitor& v, bool U, bool W, Reg t, Reg t2,
v.ir.SetRegister(t2, v.ir.MostSignificantWord(data).result);
}
return v.MemoryInstructionContinues();
return true;
}
static bool StoreDual(TranslatorVisitor& v, bool P, bool U, bool W, Reg n, Reg t, Reg t2, Imm<8> imm8) {
@@ -127,7 +123,7 @@ static bool StoreDual(TranslatorVisitor& v, bool P, bool U, bool W, Reg n, Reg t
if (W) {
v.ir.SetRegister(n, offset_address);
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDA(Reg n, Reg t) {
@@ -173,7 +169,7 @@ bool TranslatorVisitor::thumb32_LDREX(Reg n, Reg t, Imm<8> imm8) {
const auto value = ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC);
ir.SetRegister(t, value);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) {
@@ -185,7 +181,7 @@ bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) {
const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC));
ir.SetRegister(t, value);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) {
@@ -199,7 +195,7 @@ bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo);
ir.SetRegister(t2, hi);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) {
@@ -211,7 +207,7 @@ bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) {
const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC));
ir.SetRegister(t, value);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) {
@@ -221,7 +217,7 @@ bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) {
@@ -236,7 +232,7 @@ bool TranslatorVisitor::thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) {
const auto value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) {
@@ -251,7 +247,7 @@ bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) {
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) {
@@ -267,7 +263,7 @@ bool TranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) {
const auto value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) {
@@ -282,7 +278,7 @@ bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) {
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_TBB(Reg n, Reg m) {

View File

@@ -12,44 +12,42 @@ static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
static bool LDMHelper(TranslatorVisitor& v, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
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;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
v.ir.SetRegister(static_cast<Reg>(i), v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = v.ir.Add(address, v.ir.Imm32(4));
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = ir.Add(address, ir.Imm32(4));
}
}
if (W && !mcl::bit::get_bit(RegNumber(n), list)) {
v.ir.SetRegister(n, writeback_address);
ir.SetRegister(n, writeback_address);
}
if (mcl::bit::get_bit<15>(list)) {
v.ir.UpdateUpperLocationDescriptor();
v.ir.LoadWritePC(v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (v.options.check_halt_on_memory_access) {
v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else if (n == Reg::R13) {
v.ir.SetTerm(IR::Term::PopRSBHint{});
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (n == Reg::R13) {
ir.SetTerm(IR::Term::PopRSBHint{});
} else {
v.ir.SetTerm(IR::Term::FastDispatchHint{});
ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
return v.MemoryInstructionContinues();
return true;
}
static bool STMHelper(TranslatorVisitor& v, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
v.ir.WriteMemory32(address, v.ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = v.ir.Add(address, v.ir.Imm32(4));
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = ir.Add(address, ir.Imm32(4));
}
}
if (W) {
v.ir.SetRegister(n, writeback_address);
ir.SetRegister(n, writeback_address);
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
@@ -74,7 +72,7 @@ bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
// Start address is the same as the writeback address.
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
return LDMHelper(*this, W, n, regs_imm, start_address, start_address);
return LDMHelper(ir, W, n, regs_imm, start_address, start_address);
}
bool TranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
@@ -99,7 +97,7 @@ bool TranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
return LDMHelper(*this, W, n, regs_imm, start_address, writeback_address);
return LDMHelper(ir, W, n, regs_imm, start_address, writeback_address);
}
bool TranslatorVisitor::thumb32_POP(Imm<16> reg_list) {
@@ -126,7 +124,7 @@ bool TranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
return STMHelper(*this, W, n, regs_imm, start_address, writeback_address);
return STMHelper(ir, W, n, regs_imm, start_address, writeback_address);
}
bool TranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) {
@@ -145,7 +143,7 @@ bool TranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) {
// Start address is the same as the writeback address.
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
return STMHelper(*this, W, n, regs_imm, start_address, start_address);
return STMHelper(ir, W, n, regs_imm, start_address, start_address);
}
} // namespace Dynarmic::A32

View File

@@ -23,16 +23,12 @@ bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) {
if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
@@ -62,9 +58,7 @@ bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, I
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else if (!P && W && n == Reg::R13) {
if (!P && W && n == Reg::R13) {
ir.SetTerm(IR::Term::PopRSBHint{});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
@@ -74,7 +68,7 @@ bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, I
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) {
@@ -90,16 +84,12 @@ bool TranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) {
if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
@@ -119,16 +109,12 @@ bool TranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
ir.SetRegister(t, data);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::thumb32_LDRT(Reg n, Reg t, Imm<8> imm8) {

View File

@@ -1201,7 +1201,7 @@ bool TranslatorVisitor::vfp_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm<8> i
}
}
return MemoryInstructionContinues();
return true;
}
// VPUSH.{F32,F64} <list>
@@ -1242,7 +1242,7 @@ bool TranslatorVisitor::vfp_VPUSH(Cond cond, bool D, size_t Vd, bool sz, Imm<8>
}
}
return MemoryInstructionContinues();
return true;
}
// VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
@@ -1268,7 +1268,7 @@ bool TranslatorVisitor::vfp_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo
ir.SetExtendedRegister(d, ir.ReadMemory32(address, IR::AccType::ATOMIC));
}
return MemoryInstructionContinues();
return true;
}
// VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
@@ -1295,7 +1295,7 @@ bool TranslatorVisitor::vfp_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo
ir.WriteMemory32(address, ir.GetExtendedRegister(d), IR::AccType::ATOMIC);
}
return MemoryInstructionContinues();
return true;
}
// VSTM{mode}<c> <Rn>{!}, <list of double registers>
@@ -1347,7 +1347,7 @@ bool TranslatorVisitor::vfp_VSTM_a1(Cond cond, bool p, bool u, bool D, bool w, R
address = ir.Add(address, ir.Imm32(4));
}
return MemoryInstructionContinues();
return true;
}
// VSTM{mode}<c> <Rn>{!}, <list of single registers>
@@ -1390,7 +1390,7 @@ bool TranslatorVisitor::vfp_VSTM_a2(Cond cond, bool p, bool u, bool D, bool w, R
address = ir.Add(address, ir.Imm32(4));
}
return MemoryInstructionContinues();
return true;
}
// VLDM{mode}<c> <Rn>{!}, <list of double registers>
@@ -1440,7 +1440,7 @@ bool TranslatorVisitor::vfp_VLDM_a1(Cond cond, bool p, bool u, bool D, bool w, R
ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(word1, word2));
}
return MemoryInstructionContinues();
return true;
}
// VLDM{mode}<c> <Rn>{!}, <list of single registers>
@@ -1483,7 +1483,7 @@ bool TranslatorVisitor::vfp_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, R
ir.SetExtendedRegister(d + i, word);
}
return MemoryInstructionContinues();
return true;
}
} // namespace Dynarmic::A32

View File

@@ -107,83 +107,83 @@ void IREmitter::ClearExclusive() {
}
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{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, vaddr, value, IR::Value{acc_type});
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::GetW(Reg reg) {
@@ -262,4 +262,8 @@ 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

@@ -95,6 +95,9 @@ public:
void SetFPCR(const IR::U32& value);
void SetFPSR(const IR::U32& value);
void SetPC(const IR::U64& value);
private:
IR::U64 ImmCurrentLocationDescriptor();
};
} // namespace Dynarmic::A64

View File

@@ -35,12 +35,6 @@ struct TranslationOptions {
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
/// This changes what IR we emit when we translate a memory instruction.
/// If this is false, memory accesses are not considered terminal.
/// If this is true, memory access are considered terminal. This allows
/// accurately emulating protection fault handlers.
bool check_halt_on_memory_access = false;
};
/**

View File

@@ -41,15 +41,6 @@ bool TranslatorVisitor::RaiseException(Exception exception) {
return false;
}
bool TranslatorVisitor::MemoryInstructionContinues() {
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->AdvancePC(4)});
return false;
}
return true;
}
std::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(bool immN, Imm<6> imms, Imm<6> immr, bool immediate) {
const int len = mcl::bit::highest_set_bit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
if (len < 1) {

View File

@@ -30,7 +30,6 @@ struct TranslatorVisitor final {
bool ReservedValue();
bool UnallocatedEncoding();
bool RaiseException(Exception exception);
bool MemoryInstructionContinues();
struct BitMasks {
u64 wmask, tmask;

View File

@@ -72,7 +72,7 @@ static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, s
UNREACHABLE();
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STXR(Imm<2> sz, Reg Rs, Reg Rn, Reg Rt) {
@@ -175,7 +175,7 @@ static bool OrderedSharedDecodeAndOperation(TranslatorVisitor& v, size_t size, b
UNREACHABLE();
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STLLR(Imm<2> sz, Reg Rn, Reg Rt) {

View File

@@ -15,7 +15,7 @@ bool TranslatorVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
const auto data = Mem(ir.Imm64(address), size, IR::AccType::NORMAL);
X(8 * size, Rt, data);
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
@@ -33,7 +33,7 @@ bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
} else {
V(128, Vt, ir.ZeroExtendToQuad(data));
}
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) {
@@ -42,7 +42,7 @@ bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) {
const auto data = Mem(ir.Imm64(address), 4, IR::AccType::NORMAL);
X(64, Rt, ir.SignExtendWordToLong(data));
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::PRFM_lit(Imm<19> /*imm19*/, Imm<5> /*prfop*/) {

View File

@@ -104,7 +104,7 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp
}
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STx_mult_1(bool Q, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) {

View File

@@ -72,7 +72,7 @@ static bool LoadStoreRegisterImmediate(TranslatorVisitor& v, bool wback, bool po
}
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn, Reg Rt) {
@@ -165,7 +165,7 @@ static bool LoadStoreSIMD(TranslatorVisitor& v, bool wback, bool postindex, size
}
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn, Vec Vt) {

View File

@@ -78,7 +78,7 @@ bool TranslatorVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback,
}
}
return MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) {
@@ -148,7 +148,7 @@ bool TranslatorVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wbac
}
}
return MemoryInstructionContinues();
return true;
}
} // namespace Dynarmic::A64

View File

@@ -70,7 +70,7 @@ static bool RegSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 s
UNREACHABLE();
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt) {
@@ -128,7 +128,7 @@ static bool VecSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 s
UNREACHABLE();
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Vec Vt) {

View File

@@ -22,7 +22,7 @@ static bool StoreRegister(TranslatorVisitor& v, const size_t datasize, const Imm
const IR::UAny data = v.X(datasize, Rt);
v.Mem(address, datasize / 8, acctype, data);
return v.MemoryInstructionContinues();
return true;
}
static bool LoadRegister(TranslatorVisitor& v, const size_t datasize, const Imm<9> imm9, const Reg Rn, const Reg Rt) {
@@ -42,7 +42,7 @@ static bool LoadRegister(TranslatorVisitor& v, const size_t datasize, const Imm<
// max is used to zeroextend < 32 to 32, and > 32 to 64
const size_t extended_size = std::max<size_t>(32, datasize);
v.X(extended_size, Rt, v.ZeroExtend(data, extended_size));
return v.MemoryInstructionContinues();
return true;
}
static bool LoadRegisterSigned(TranslatorVisitor& v, const size_t datasize, const Imm<2> opc, const Imm<9> imm9, const Reg Rn, const Reg Rt) {
@@ -90,7 +90,7 @@ static bool LoadRegisterSigned(TranslatorVisitor& v, const size_t datasize, cons
// Prefetch(address, Rt);
break;
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::STTRB(Imm<9> imm9, Reg Rn, Reg Rt) {
@@ -144,6 +144,6 @@ bool TranslatorVisitor::LDTRSW(Imm<9> imm9, Reg Rn, Reg Rt) {
const IR::UAny data = Mem(address, 4, acctype);
X(64, Rt, SignExtend(data, 64));
return MemoryInstructionContinues();
return true;
}
} // namespace Dynarmic::A64

View File

@@ -98,7 +98,7 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp
}
}
return v.MemoryInstructionContinues();
return true;
}
bool TranslatorVisitor::LD1_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {

View File

@@ -229,9 +229,6 @@ struct UserConfig {
// Minimum size is about 8MiB. Maximum size is about 2GiB. Maximum size is limited by
// the maximum length of a x64 jump.
size_t code_cache_size = 256 * 1024 * 1024; // bytes
// Determines the relative size of the near and far code caches. Must be smaller than
// code_cache_size.
size_t far_code_offset = 200 * 1024 * 1024; // bytes
};
} // namespace A32

View File

@@ -288,9 +288,6 @@ struct UserConfig {
// Minimum size is about 8MiB. Maximum size is about 2GiB. Maximum size is limited by
// the maximum length of a x64 jump.
size_t code_cache_size = 256 * 1024 * 1024; // bytes
// Determines the relative size of the near and far code caches. Must be smaller than
// code_cache_size.
size_t far_code_offset = 200 * 1024 * 1024; // bytes
};
} // namespace A64

View File

@@ -12,6 +12,7 @@ namespace Dynarmic {
enum class HaltReason : std::uint32_t {
Step = 0x00000001,
CacheInvalidation = 0x00000002,
MemoryAbort = 0x00000004,
UserDefined1 = 0x01000000,
UserDefined2 = 0x02000000,
UserDefined3 = 0x04000000,

View File

@@ -688,45 +688,45 @@ OPCODE(FPVectorToUnsignedFixed64, U128, U128
// A32 Memory access
A32OPC(ClearExclusive, Void, )
A32OPC(ReadMemory8, U8, U32, AccType )
A32OPC(ReadMemory16, U16, U32, AccType )
A32OPC(ReadMemory32, U32, U32, AccType )
A32OPC(ReadMemory64, U64, U32, AccType )
A32OPC(ExclusiveReadMemory8, U8, U32, AccType )
A32OPC(ExclusiveReadMemory16, U16, U32, AccType )
A32OPC(ExclusiveReadMemory32, U32, U32, AccType )
A32OPC(ExclusiveReadMemory64, U64, U32, AccType )
A32OPC(WriteMemory8, Void, U32, U8, AccType )
A32OPC(WriteMemory16, Void, U32, U16, AccType )
A32OPC(WriteMemory32, Void, U32, U32, AccType )
A32OPC(WriteMemory64, Void, U32, U64, AccType )
A32OPC(ExclusiveWriteMemory8, U32, U32, U8, AccType )
A32OPC(ExclusiveWriteMemory16, U32, U32, U16, AccType )
A32OPC(ExclusiveWriteMemory32, U32, U32, U32, AccType )
A32OPC(ExclusiveWriteMemory64, U32, U32, U64, AccType )
A32OPC(ReadMemory8, U8, U64, U32, AccType )
A32OPC(ReadMemory16, U16, U64, U32, AccType )
A32OPC(ReadMemory32, U32, U64, U32, AccType )
A32OPC(ReadMemory64, U64, U64, U32, AccType )
A32OPC(ExclusiveReadMemory8, U8, U64, U32, AccType )
A32OPC(ExclusiveReadMemory16, U16, U64, U32, AccType )
A32OPC(ExclusiveReadMemory32, U32, U64, U32, AccType )
A32OPC(ExclusiveReadMemory64, U64, U64, U32, AccType )
A32OPC(WriteMemory8, Void, U64, U32, U8, AccType )
A32OPC(WriteMemory16, Void, U64, U32, U16, AccType )
A32OPC(WriteMemory32, Void, U64, U32, U32, AccType )
A32OPC(WriteMemory64, Void, U64, U32, U64, AccType )
A32OPC(ExclusiveWriteMemory8, U32, U64, U32, U8, AccType )
A32OPC(ExclusiveWriteMemory16, U32, U64, U32, U16, AccType )
A32OPC(ExclusiveWriteMemory32, U32, U64, U32, U32, AccType )
A32OPC(ExclusiveWriteMemory64, U32, U64, U32, U64, AccType )
// A64 Memory access
A64OPC(ClearExclusive, Void, )
A64OPC(ReadMemory8, U8, U64, AccType )
A64OPC(ReadMemory16, U16, U64, AccType )
A64OPC(ReadMemory32, U32, U64, AccType )
A64OPC(ReadMemory64, U64, U64, AccType )
A64OPC(ReadMemory128, U128, U64, AccType )
A64OPC(ExclusiveReadMemory8, U8, U64, AccType )
A64OPC(ExclusiveReadMemory16, U16, U64, AccType )
A64OPC(ExclusiveReadMemory32, U32, U64, AccType )
A64OPC(ExclusiveReadMemory64, U64, U64, AccType )
A64OPC(ExclusiveReadMemory128, U128, U64, AccType )
A64OPC(WriteMemory8, Void, U64, U8, AccType )
A64OPC(WriteMemory16, Void, U64, U16, AccType )
A64OPC(WriteMemory32, Void, U64, U32, AccType )
A64OPC(WriteMemory64, Void, U64, U64, AccType )
A64OPC(WriteMemory128, Void, U64, U128, AccType )
A64OPC(ExclusiveWriteMemory8, U32, U64, U8, AccType )
A64OPC(ExclusiveWriteMemory16, U32, U64, U16, AccType )
A64OPC(ExclusiveWriteMemory32, U32, U64, U32, AccType )
A64OPC(ExclusiveWriteMemory64, U32, U64, U64, AccType )
A64OPC(ExclusiveWriteMemory128, U32, U64, U128, AccType )
A64OPC(ReadMemory8, U8, U64, U64, AccType )
A64OPC(ReadMemory16, U16, U64, U64, AccType )
A64OPC(ReadMemory32, U32, U64, U64, AccType )
A64OPC(ReadMemory64, U64, U64, U64, AccType )
A64OPC(ReadMemory128, U128, U64, U64, AccType )
A64OPC(ExclusiveReadMemory8, U8, U64, U64, AccType )
A64OPC(ExclusiveReadMemory16, U16, U64, U64, AccType )
A64OPC(ExclusiveReadMemory32, U32, U64, U64, AccType )
A64OPC(ExclusiveReadMemory64, U64, U64, U64, AccType )
A64OPC(ExclusiveReadMemory128, U128, U64, U64, AccType )
A64OPC(WriteMemory8, Void, U64, U64, U8, AccType )
A64OPC(WriteMemory16, Void, U64, U64, U16, AccType )
A64OPC(WriteMemory32, Void, U64, U64, U32, AccType )
A64OPC(WriteMemory64, Void, U64, U64, U64, AccType )
A64OPC(WriteMemory128, Void, U64, U64, U128, AccType )
A64OPC(ExclusiveWriteMemory8, U32, U64, U64, U8, AccType )
A64OPC(ExclusiveWriteMemory16, U32, U64, U64, U16, AccType )
A64OPC(ExclusiveWriteMemory32, U32, U64, U64, U32, AccType )
A64OPC(ExclusiveWriteMemory64, U32, U64, U64, U64, AccType )
A64OPC(ExclusiveWriteMemory128, U32, U64, U64, U128, AccType )
// Coprocessor
A32OPC(CoprocInternalOperation, Void, CoprocInfo )

View File

@@ -25,7 +25,7 @@ void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
break;
}
const u32 vaddr = inst.GetArg(0).GetU32();
const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) {
const u8 value_from_memory = cb->MemoryRead8(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
@@ -37,7 +37,7 @@ void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
break;
}
const u32 vaddr = inst.GetArg(0).GetU32();
const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) {
const u16 value_from_memory = cb->MemoryRead16(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
@@ -49,7 +49,7 @@ void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
break;
}
const u32 vaddr = inst.GetArg(0).GetU32();
const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) {
const u32 value_from_memory = cb->MemoryRead32(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});
@@ -61,7 +61,7 @@ void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
break;
}
const u32 vaddr = inst.GetArg(0).GetU32();
const u32 vaddr = inst.GetArg(1).GetU32();
if (cb->IsReadOnlyMemory(vaddr)) {
const u64 value_from_memory = cb->MemoryRead64(vaddr);
inst.ReplaceUsesWith(IR::Value{value_from_memory});