early-access version 2836
This commit is contained in:
2
externals/dynarmic/.gitignore
vendored
2
externals/dynarmic/.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
# Built files
|
||||
build/
|
||||
build-*/
|
||||
cmake-build-*/
|
||||
.idea/
|
||||
docs/Doxygen/
|
||||
# Generated files
|
||||
src/dynarmic/backend/x64/mig/
|
||||
|
2
externals/dynarmic/CMakeLists.txt
vendored
2
externals/dynarmic/CMakeLists.txt
vendored
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
project(dynarmic LANGUAGES C CXX ASM VERSION 6.1.1)
|
||||
project(dynarmic LANGUAGES C CXX ASM VERSION 6.2.0)
|
||||
|
||||
# Determine if we're built as a subproject (using add_subdirectory)
|
||||
# or if this is the master project.
|
||||
|
31
externals/dynarmic/README.md
vendored
31
externals/dynarmic/README.md
vendored
@@ -267,21 +267,30 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
```
|
||||
|
||||
### mp
|
||||
### mcl & oaknut
|
||||
|
||||
```
|
||||
Copyright (C) 2017 MerryMage
|
||||
MIT License
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
Copyright (c) 2022 merryhime <https://mary.rs>
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
### robin-map
|
||||
|
@@ -3,36 +3,38 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
test_on_ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on ${{ matrix.distro }} ${{ matrix.arch }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: aarch64
|
||||
distro: ubuntu_latest
|
||||
name: g++-10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Build and Test
|
||||
id: build
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
distro: ${{ matrix.distro }}
|
||||
shell: /bin/bash
|
||||
- name: Checkout oaknut repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
install: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y make cmake g++ git
|
||||
- name: Install dependencies
|
||||
run: >
|
||||
sudo apt-get install -q -y
|
||||
gcc-10-aarch64-linux-gnu
|
||||
g++-10-aarch64-linux-gnu
|
||||
ninja-build
|
||||
qemu-user
|
||||
|
||||
pushd /tmp
|
||||
git clone https://github.com/catchorg/Catch2.git
|
||||
cd Catch2
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||
cmake --build build/ --target install
|
||||
popd
|
||||
- name: Checkout Catch2 v3 repo
|
||||
run: git clone https://github.com/catchorg/Catch2.git externals/catch
|
||||
|
||||
run: |
|
||||
cmake -Bbuild -H.
|
||||
cmake --build build
|
||||
./build/oaknut-tests
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CC: aarch64-linux-gnu-gcc-10
|
||||
CXX: aarch64-linux-gnu-g++-10
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build
|
||||
-H.
|
||||
-GNinja
|
||||
-DDYNARMIC_USE_BUNDLED_CATCH=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ninja
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: qemu-aarch64 -L /usr/aarch64-linux-gnu ./oaknut-tests -d yes
|
||||
|
@@ -39,7 +39,11 @@ target_compile_features(oaknut INTERFACE cxx_std_20)
|
||||
|
||||
# Tests
|
||||
if (MASTER_PROJECT)
|
||||
find_package(Catch2 3 REQUIRED)
|
||||
if (DYNARMIC_USE_BUNDLED_CATCH)
|
||||
add_subdirectory(externals/catch)
|
||||
else()
|
||||
find_package(Catch2 3 REQUIRED)
|
||||
endif()
|
||||
|
||||
add_executable(oaknut-tests
|
||||
tests/basic.cpp
|
||||
@@ -49,9 +53,4 @@ if (MASTER_PROJECT)
|
||||
target_include_directories(oaknut-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||
target_link_libraries(oaknut-tests PRIVATE Catch2::Catch2WithMain merry::oaknut)
|
||||
target_compile_options(oaknut-tests PRIVATE -Wall -Wextra -Wcast-qual -pedantic -pedantic-errors -Wfatal-errors -Wno-missing-braces)
|
||||
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(oaknut-tests)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
@@ -1,6 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
|
@@ -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) {
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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() {
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
|
@@ -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};
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -110,6 +110,7 @@ public:
|
||||
|
||||
private:
|
||||
enum ArchVersion arch_version;
|
||||
IR::U64 ImmCurrentLocationDescriptor();
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -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:
|
||||
|
@@ -41,7 +41,6 @@ struct TranslatorVisitor final {
|
||||
bool UndefinedInstruction();
|
||||
bool DecodeError();
|
||||
bool RaiseException(Exception exception);
|
||||
bool MemoryInstructionContinues();
|
||||
|
||||
struct ImmAndCarry {
|
||||
u32 imm32;
|
||||
|
@@ -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
|
||||
|
@@ -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() {
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -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*/) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -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) {
|
||||
|
@@ -30,7 +30,6 @@ struct TranslatorVisitor final {
|
||||
bool ReservedValue();
|
||||
bool UnallocatedEncoding();
|
||||
bool RaiseException(Exception exception);
|
||||
bool MemoryInstructionContinues();
|
||||
|
||||
struct BitMasks {
|
||||
u64 wmask, tmask;
|
||||
|
@@ -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) {
|
||||
|
@@ -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*/) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -12,6 +12,7 @@ namespace Dynarmic {
|
||||
enum class HaltReason : std::uint32_t {
|
||||
Step = 0x00000001,
|
||||
CacheInvalidation = 0x00000002,
|
||||
MemoryAbort = 0x00000004,
|
||||
UserDefined1 = 0x01000000,
|
||||
UserDefined2 = 0x02000000,
|
||||
UserDefined3 = 0x04000000,
|
||||
|
72
externals/dynarmic/src/dynarmic/ir/opcodes.inc
vendored
72
externals/dynarmic/src/dynarmic/ir/opcodes.inc
vendored
@@ -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 )
|
||||
|
@@ -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});
|
||||
|
3
externals/dynarmic/tests/A32/fuzz_arm.cpp
vendored
3
externals/dynarmic/tests/A32/fuzz_arm.cpp
vendored
@@ -398,9 +398,8 @@ static void RunTestInstance(Dynarmic::A32::Jit& jit,
|
||||
}
|
||||
|
||||
if (uni.GetRegisters()[15] > jit.Regs()[15]) {
|
||||
const u32 final_pc = jit.Regs()[15];
|
||||
int trials = 0;
|
||||
while (final_pc >= initial_pc && final_pc < expected_end_pc && trials++ < 100) {
|
||||
while (jit.Regs()[15] >= initial_pc && jit.Regs()[15] < expected_end_pc && trials++ < 100 && uni.GetRegisters()[15] != jit.Regs()[15]) {
|
||||
fmt::print("Warning: Possible unicorn overrrun, attempt recovery\n");
|
||||
jit.Step();
|
||||
}
|
||||
|
Reference in New Issue
Block a user