From 17ae7f9ce168c2a7a1f0981f4082f0bb01f8f34a Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 23 May 2021 15:37:24 +0100 Subject: [PATCH] IR: Implement IR instruction CallHostFunction --- src/dynarmic/backend/x64/emit_x64.cpp | 15 +++++++++++---- src/dynarmic/backend/x64/reg_alloc.cpp | 2 +- src/dynarmic/ir/ir_emitter.cpp | 17 +++++++++++++++++ src/dynarmic/ir/ir_emitter.h | 4 ++++ src/dynarmic/ir/microinstruction.cpp | 1 + src/dynarmic/ir/opcodes.inc | 1 + 6 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/backend/x64/emit_x64.cpp index abdda42d..68ecbe51 100644 --- a/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/backend/x64/emit_x64.cpp @@ -59,10 +59,6 @@ std::optional EmitX64::GetBasicBlock(IR::LocationDescr void EmitX64::EmitVoid(EmitContext&, IR::Inst*) { } -void EmitX64::EmitBreakpoint(EmitContext&, IR::Inst*) { - code.int3(); -} - void EmitX64::EmitIdentity(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (!args[0].IsImmediate()) { @@ -70,6 +66,17 @@ void EmitX64::EmitIdentity(EmitContext& ctx, IR::Inst* inst) { } } +void EmitX64::EmitBreakpoint(EmitContext&, IR::Inst*) { + code.int3(); +} + +void EmitX64::EmitCallHostFunction(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + ctx.reg_alloc.HostCall(nullptr, args[1], args[2], args[3]); + code.mov(rax, args[0].GetImmediateU64()); + code.call(rax); +} + void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, IR::LocationDescriptor target) { using namespace Xbyak::util; diff --git a/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/backend/x64/reg_alloc.cpp index aea61a17..e418dc6f 100644 --- a/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/backend/x64/reg_alloc.cpp @@ -408,7 +408,7 @@ void RegAlloc::HostCall(IR::Inst* result_def, } for (size_t i = 0; i < args_count; i++) { - if (args[i]) { + if (args[i] && !args[i]->get().IsVoid()) { UseScratch(*args[i], args_hostloc[i]); #if defined(__llvm__) && !defined(_WIN32) // LLVM puts the burden of zero-extension of 8 and 16 bit values on the caller instead of the callee diff --git a/src/dynarmic/ir/ir_emitter.cpp b/src/dynarmic/ir/ir_emitter.cpp index 2477067c..bd6c1ebc 100644 --- a/src/dynarmic/ir/ir_emitter.cpp +++ b/src/dynarmic/ir/ir_emitter.cpp @@ -6,6 +6,7 @@ #include "dynarmic/ir/ir_emitter.h" #include "dynarmic/common/assert.h" +#include "dynarmic/common/cast_util.h" #include "dynarmic/ir/opcodes.h" namespace Dynarmic::IR { @@ -2652,6 +2653,22 @@ void IREmitter::Breakpoint() { Inst(Opcode::Breakpoint); } +void IREmitter::CallHostFunction(void (*fn)(void)) { + Inst(Opcode::CallHostFunction, Imm64(Common::BitCast(fn))); +} + +void IREmitter::CallHostFunction(void (*fn)(u64), const U64& arg1) { + Inst(Opcode::CallHostFunction, Imm64(Common::BitCast(fn)), arg1); +} + +void IREmitter::CallHostFunction(void (*fn)(u64, u64), const U64& arg1, const U64& arg2) { + Inst(Opcode::CallHostFunction, Imm64(Common::BitCast(fn)), arg1, arg2); +} + +void IREmitter::CallHostFunction(void (*fn)(u64, u64, u64), const U64& arg1, const U64& arg2, const U64& arg3) { + Inst(Opcode::CallHostFunction, Imm64(Common::BitCast(fn)), arg1, arg2, arg3); +} + void IREmitter::SetTerm(const Terminal& terminal) { block.SetTerminal(terminal); } diff --git a/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/ir/ir_emitter.h index 7e2ea317..db542136 100644 --- a/src/dynarmic/ir/ir_emitter.h +++ b/src/dynarmic/ir/ir_emitter.h @@ -393,6 +393,10 @@ public: U128 FPVectorToUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true); void Breakpoint(); + void CallHostFunction(void (*fn)(void)); + void CallHostFunction(void (*fn)(u64), const U64& arg1); + void CallHostFunction(void (*fn)(u64, u64), const U64& arg1, const U64& arg2); + void CallHostFunction(void (*fn)(u64, u64, u64), const U64& arg1, const U64& arg2, const U64& arg3); void SetTerm(const Terminal& terminal); diff --git a/src/dynarmic/ir/microinstruction.cpp b/src/dynarmic/ir/microinstruction.cpp index 48e5be35..a499c327 100644 --- a/src/dynarmic/ir/microinstruction.cpp +++ b/src/dynarmic/ir/microinstruction.cpp @@ -526,6 +526,7 @@ bool Inst::IsSetCheckBitOperation() const { bool Inst::MayHaveSideEffects() const { return op == Opcode::PushRSB + || op == Opcode::CallHostFunction || op == Opcode::A64DataCacheOperationRaised || op == Opcode::A64InstructionCacheOperationRaised || IsSetCheckBitOperation() diff --git a/src/dynarmic/ir/opcodes.inc b/src/dynarmic/ir/opcodes.inc index d8a0fd6e..50c36439 100644 --- a/src/dynarmic/ir/opcodes.inc +++ b/src/dynarmic/ir/opcodes.inc @@ -3,6 +3,7 @@ OPCODE(Void, Void, ) OPCODE(Identity, Opaque, Opaque ) OPCODE(Breakpoint, Void, ) +OPCODE(CallHostFunction, Void, U64, Opaque, Opaque, Opaque ) // A32 Context getters/setters A32OPC(SetCheckBit, Void, U1 )