aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorMerry <[email protected]>2023-01-20 11:52:23 +0000
committerMerry <[email protected]>2023-01-20 11:52:23 +0000
commit191125a208fca341985eeec001812f1c165d2c37 (patch)
tree4facb4c340cb847a4ca2479898ea4589d040746e /src
parent2a87337141a9d848276bed4188dbdeab2bd0a770 (diff)
downloaddynarmic-191125a208fca341985eeec001812f1c165d2c37.tar.gz
dynarmic-191125a208fca341985eeec001812f1c165d2c37.zip
backend/arm64: Add verbose debugging output
Diffstat (limited to 'src')
-rw-r--r--src/dynarmic/CMakeLists.txt2
-rw-r--r--src/dynarmic/backend/arm64/a32_address_space.cpp3
-rw-r--r--src/dynarmic/backend/arm64/a64_address_space.cpp2
-rw-r--r--src/dynarmic/backend/arm64/emit_arm64.cpp9
-rw-r--r--src/dynarmic/backend/arm64/emit_arm64.h3
-rw-r--r--src/dynarmic/backend/arm64/reg_alloc.cpp32
-rw-r--r--src/dynarmic/backend/arm64/reg_alloc.h3
-rw-r--r--src/dynarmic/backend/arm64/verbose_debugging_output.cpp104
-rw-r--r--src/dynarmic/backend/arm64/verbose_debugging_output.h58
9 files changed, 216 insertions, 0 deletions
diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt
index 6e39253c..5b084d9a 100644
--- a/src/dynarmic/CMakeLists.txt
+++ b/src/dynarmic/CMakeLists.txt
@@ -373,6 +373,8 @@ if ("arm64" IN_LIST ARCHITECTURE)
backend/arm64/reg_alloc.cpp
backend/arm64/reg_alloc.h
backend/arm64/stack_layout.h
+ backend/arm64/verbose_debugging_output.cpp
+ backend/arm64/verbose_debugging_output.h
common/spin_lock_arm64.cpp
common/spin_lock_arm64.h
)
diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp
index 8a630c93..8723326b 100644
--- a/src/dynarmic/backend/arm64/a32_address_space.cpp
+++ b/src/dynarmic/backend/arm64/a32_address_space.cpp
@@ -174,6 +174,7 @@ IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
Optimization::ConstantPropagation(ir_block);
Optimization::DeadCodeElimination(ir_block);
}
+ Optimization::IdentityRemovalPass(ir_block);
Optimization::VerificationPass(ir_block);
return ir_block;
@@ -385,6 +386,8 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
.state_exclusive_state_offset = offsetof(A32JitState, exclusive_state),
.coprocessors = conf.coprocessors,
+
+ .very_verbose_debugging_output = conf.very_verbose_debugging_output,
};
}
diff --git a/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/backend/arm64/a64_address_space.cpp
index 06966695..28016384 100644
--- a/src/dynarmic/backend/arm64/a64_address_space.cpp
+++ b/src/dynarmic/backend/arm64/a64_address_space.cpp
@@ -562,6 +562,8 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
.state_exclusive_state_offset = offsetof(A64JitState, exclusive_state),
.coprocessors{},
+
+ .very_verbose_debugging_output = conf.very_verbose_debugging_output,
};
}
diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp
index e5ad165c..05358731 100644
--- a/src/dynarmic/backend/arm64/emit_arm64.cpp
+++ b/src/dynarmic/backend/arm64/emit_arm64.cpp
@@ -11,6 +11,7 @@
#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/reg_alloc.h"
+#include "dynarmic/backend/arm64/verbose_debugging_output.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
@@ -175,6 +176,10 @@ static void EmitAddCycles(oaknut::CodeGenerator& code, EmitContext& ctx, size_t
}
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf, FastmemManager& fastmem_manager) {
+ if (conf.very_verbose_debugging_output) {
+ std::puts(IR::DumpBlock(block).c_str());
+ }
+
EmittedBlockInfo ebi;
FpsrManager fpsr_manager{code, conf.state_fpsr_offset};
@@ -223,6 +228,10 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
reg_alloc.UpdateAllUses();
reg_alloc.AssertAllUnlocked();
+
+ if (conf.very_verbose_debugging_output) {
+ EmitVerboseDebuggingOutput(code, ctx);
+ }
}
fpsr_manager.Spill();
diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h
index c15d9266..6d13e7e3 100644
--- a/src/dynarmic/backend/arm64/emit_arm64.h
+++ b/src/dynarmic/backend/arm64/emit_arm64.h
@@ -155,6 +155,9 @@ struct EmitConfig {
// A32 specific
std::array<std::shared_ptr<A32::Coprocessor>, 16> coprocessors{};
+
+ // Debugging
+ bool very_verbose_debugging_output;
};
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& emit_conf, FastmemManager& fastmem_manager);
diff --git a/src/dynarmic/backend/arm64/reg_alloc.cpp b/src/dynarmic/backend/arm64/reg_alloc.cpp
index 83accac2..a8fd2ec7 100644
--- a/src/dynarmic/backend/arm64/reg_alloc.cpp
+++ b/src/dynarmic/backend/arm64/reg_alloc.cpp
@@ -7,14 +7,18 @@
#include <algorithm>
#include <array>
+#include <iterator>
#include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp>
+#include <mcl/bit_cast.hpp>
#include <mcl/mp/metavalue/lift_value.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/arm64/abi.h"
+#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
+#include "dynarmic/backend/arm64/verbose_debugging_output.h"
#include "dynarmic/common/always_false.h"
namespace Dynarmic::Backend::Arm64 {
@@ -234,6 +238,34 @@ void RegAlloc::AssertNoMoreUses() const {
ASSERT(std::all_of(spills.begin(), spills.end(), is_empty));
}
+void RegAlloc::EmitVerboseDebuggingOutput(EmitContext& ctx) {
+ code.MOV(X19, mcl::bit_cast<u64>(&PrintVerboseDebuggingOutputLine)); // Non-volatile register
+
+ const auto do_location = [&](HostLocInfo& info, HostLocType type, size_t index) {
+ using namespace oaknut::util;
+ for (const IR::Inst* value : info.values) {
+ const auto inst_offset = std::distance(ctx.block.begin(), IR::Block::iterator(const_cast<IR::Inst*>(value)));
+ code.MOV(X0, SP);
+ code.MOV(X1, static_cast<u64>(type));
+ code.MOV(X2, index);
+ code.MOV(X3, mcl::bit_cast<u64>(inst_offset));
+ code.MOV(X4, static_cast<u64>(value->GetType()));
+ code.BLR(X19);
+ }
+ };
+
+ for (size_t i = 0; i < gprs.size(); i++) {
+ do_location(gprs[i], HostLocType::X, i);
+ }
+ for (size_t i = 0; i < fprs.size(); i++) {
+ do_location(fprs[i], HostLocType::Q, i);
+ }
+ do_location(flags, HostLocType::Nzcv, 0);
+ for (size_t i = 0; i < spills.size(); i++) {
+ do_location(spills[i], HostLocType::Spill, i);
+ }
+}
+
template<HostLoc::Kind kind>
int RegAlloc::GenerateImmediate(const IR::Value& value) {
ASSERT(value.GetType() != IR::Type::U1);
diff --git a/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/backend/arm64/reg_alloc.h
index a101ee6d..6c97d4af 100644
--- a/src/dynarmic/backend/arm64/reg_alloc.h
+++ b/src/dynarmic/backend/arm64/reg_alloc.h
@@ -23,6 +23,7 @@
namespace Dynarmic::Backend::Arm64 {
+struct EmitContext;
class FpsrManager;
class RegAlloc;
@@ -290,6 +291,8 @@ public:
void AssertAllUnlocked() const;
void AssertNoMoreUses() const;
+ void EmitVerboseDebuggingOutput(EmitContext& ctx);
+
private:
friend struct Argument;
template<typename>
diff --git a/src/dynarmic/backend/arm64/verbose_debugging_output.cpp b/src/dynarmic/backend/arm64/verbose_debugging_output.cpp
new file mode 100644
index 00000000..fbb26bc4
--- /dev/null
+++ b/src/dynarmic/backend/arm64/verbose_debugging_output.cpp
@@ -0,0 +1,104 @@
+/* This file is part of the dynarmic project.
+ * Copyright (c) 2023 MerryMage
+ * SPDX-License-Identifier: 0BSD
+ */
+
+#include "dynarmic/backend/arm64/verbose_debugging_output.h"
+
+#include <fmt/format.h>
+#include <oaknut/oaknut.hpp>
+
+#include "dynarmic/backend/arm64/emit_context.h"
+#include "dynarmic/ir/type.h"
+
+namespace Dynarmic::Backend::Arm64 {
+
+using namespace oaknut::util;
+
+void EmitVerboseDebuggingOutput(oaknut::CodeGenerator& code, EmitContext& ctx) {
+ code.SUB(SP, SP, sizeof(RegisterData));
+ for (int i = 0; i < 30; i++) {
+ if (i == 18) {
+ continue; // Platform register
+ }
+ code.STR(oaknut::XReg{i}, SP, offsetof(RegisterData, x) + i * sizeof(u64));
+ }
+ for (int i = 0; i < 32; i++) {
+ code.STR(oaknut::QReg{i}, SP, offsetof(RegisterData, q) + i * sizeof(Vector));
+ }
+ code.MRS(X0, oaknut::SystemReg::NZCV);
+ code.STR(X0, SP, offsetof(RegisterData, nzcv));
+ code.ADD(X0, SP, sizeof(RegisterData) + offsetof(StackLayout, spill));
+ code.STR(X0, SP, offsetof(RegisterData, spill));
+
+ ctx.reg_alloc.EmitVerboseDebuggingOutput(ctx);
+
+ code.LDR(X0, SP, offsetof(RegisterData, nzcv));
+ code.MSR(oaknut::SystemReg::NZCV, X0);
+ for (int i = 0; i < 32; i++) {
+ code.LDR(oaknut::QReg{i}, SP, offsetof(RegisterData, q) + i * sizeof(Vector));
+ }
+ for (int i = 0; i < 30; i++) {
+ if (i == 18) {
+ continue; // Platform register
+ }
+ code.LDR(oaknut::XReg{i}, SP, offsetof(RegisterData, x) + i * sizeof(u64));
+ }
+ code.ADD(SP, SP, sizeof(RegisterData));
+}
+
+void PrintVerboseDebuggingOutputLine(RegisterData& reg_data, HostLocType reg_type, size_t reg_index, size_t inst_index, IR::Type inst_type) {
+ fmt::print("dynarmic debug: %{:05} = ", inst_index);
+
+ Vector value = [&]() -> Vector {
+ switch (reg_type) {
+ case HostLocType::X:
+ return {reg_data.x[reg_index], 0};
+ case HostLocType::Q:
+ return reg_data.q[reg_index];
+ case HostLocType::Nzcv:
+ return {reg_data.nzcv, 0};
+ case HostLocType::Spill:
+ return (*reg_data.spill)[reg_index];
+ }
+ fmt::print("invalid reg_type! ");
+ return {0, 0};
+ }();
+
+ switch (inst_type) {
+ case IR::Type::U1:
+ case IR::Type::U8:
+ fmt::print("{:02x}", value[0] & 0xff);
+ break;
+ case IR::Type::U16:
+ fmt::print("{:04x}", value[0] & 0xffff);
+ break;
+ case IR::Type::U32:
+ case IR::Type::NZCVFlags:
+ fmt::print("{:08x}", value[0] & 0xffffffff);
+ break;
+ case IR::Type::U64:
+ fmt::print("{:016x}", value[0]);
+ break;
+ case IR::Type::U128:
+ fmt::print("{:016x}{:016x}", value[1], value[0]);
+ break;
+ case IR::Type::A32Reg:
+ case IR::Type::A32ExtReg:
+ case IR::Type::A64Reg:
+ case IR::Type::A64Vec:
+ case IR::Type::CoprocInfo:
+ case IR::Type::Cond:
+ case IR::Type::Void:
+ case IR::Type::Table:
+ case IR::Type::AccType:
+ case IR::Type::Opaque:
+ default:
+ fmt::print("invalid inst_type!");
+ break;
+ }
+
+ fmt::print("\n");
+}
+
+} // namespace Dynarmic::Backend::Arm64 \ No newline at end of file
diff --git a/src/dynarmic/backend/arm64/verbose_debugging_output.h b/src/dynarmic/backend/arm64/verbose_debugging_output.h
new file mode 100644
index 00000000..1099edc4
--- /dev/null
+++ b/src/dynarmic/backend/arm64/verbose_debugging_output.h
@@ -0,0 +1,58 @@
+/* This file is part of the dynarmic project.
+ * Copyright (c) 2023 MerryMage
+ * SPDX-License-Identifier: 0BSD
+ */
+
+#pragma once
+
+#include <array>
+
+#include <mcl/stdint.hpp>
+
+#include "dynarmic/backend/arm64/stack_layout.h"
+
+namespace oaknut {
+struct PointerCodeGeneratorPolicy;
+template<typename>
+class BasicCodeGenerator;
+using CodeGenerator = BasicCodeGenerator<PointerCodeGeneratorPolicy>;
+struct Label;
+} // namespace oaknut
+
+namespace Dynarmic::IR {
+enum class Type;
+} // namespace Dynarmic::IR
+
+namespace Dynarmic::Backend::Arm64 {
+
+struct EmitContext;
+
+using Vector = std::array<u64, 2>;
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4324) // Structure was padded due to alignment specifier
+#endif
+
+enum class HostLocType {
+ X,
+ Q,
+ Nzcv,
+ Spill,
+};
+
+struct alignas(16) RegisterData {
+ std::array<u64, 30> x;
+ std::array<Vector, 32> q;
+ u32 nzcv;
+ decltype(StackLayout::spill)* spill;
+};
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+void EmitVerboseDebuggingOutput(oaknut::CodeGenerator& code, EmitContext& ctx);
+void PrintVerboseDebuggingOutputLine(RegisterData& reg_data, HostLocType reg_type, size_t reg_index, size_t inst_index, IR::Type inst_type);
+
+} // namespace Dynarmic::Backend::Arm64 \ No newline at end of file