Skip to content

Commit

Permalink
x64Emitter: Eliminate redundant logic for different function call par…
Browse files Browse the repository at this point in the history
…ameter types using variadic templates.
  • Loading branch information
jordan-woyak committed May 19, 2019
1 parent 3bcee22 commit 0255d5d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 115 deletions.
140 changes: 49 additions & 91 deletions Source/Core/Common/x64Emitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,88 +1019,20 @@ class XEmitter
}
}

template <typename FunctionPointer>
void ABI_CallFunctionC16(FunctionPointer func, u16 param1)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionCC16(FunctionPointer func, u32 param1, u16 param2)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionC(FunctionPointer func, u32 param1)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionCC(FunctionPointer func, u32 param1, u32 param2)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionCP(FunctionPointer func, u32 param1, const void* param2)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(64, R(ABI_PARAM2), Imm64(reinterpret_cast<u64>(param2)));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionCCC(FunctionPointer func, u32 param1, u32 param2, u32 param3)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
MOV(32, R(ABI_PARAM3), Imm32(param3));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionCCP(FunctionPointer func, u32 param1, u32 param2, const void* param3)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
MOV(64, R(ABI_PARAM3), Imm64(reinterpret_cast<u64>(param3)));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionCCCP(FunctionPointer func, u32 param1, u32 param2, u32 param3,
const void* param4)
template <typename FunctionPointer, typename... Args>
void ABI_CallFunction(FunctionPointer func, Args... args)
{
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
MOV(32, R(ABI_PARAM3), Imm32(param3));
MOV(64, R(ABI_PARAM4), Imm64(reinterpret_cast<u64>(param4)));
ABI_CallFunction(func);
}
static_assert(std::is_invocable_v<FunctionPointer, Args...>, "Wrong argument types.");

template <typename FunctionPointer>
void ABI_CallFunctionPC(FunctionPointer func, const void* param1, u32 param2)
{
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(param1)));
MOV(32, R(ABI_PARAM2), Imm32(param2));
MOVArgs(args...);
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionPPC(FunctionPointer func, const void* param1, const void* param2, u32 param3)
template <typename T, typename... Args>
void ABI_CallLambda(const std::function<T(Args...)>* func, Args... args)
{
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(param1)));
MOV(64, R(ABI_PARAM2), Imm64(reinterpret_cast<u64>(param2)));
MOV(32, R(ABI_PARAM3), Imm32(param3));
ABI_CallFunction(func);
const auto trampoline = &XEmitter::CallLambdaTrampoline<T, Args...>;
ABI_CallFunction(trampoline, func, args...);
}

// Pass a register as a parameter.
Expand All @@ -1120,20 +1052,12 @@ class XEmitter
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionAC(int bits, FunctionPointer func, const Gen::OpArg& arg1, u32 param2)
{
if (!arg1.IsSimpleReg(ABI_PARAM1))
MOV(bits, R(ABI_PARAM1), arg1);
MOV(32, R(ABI_PARAM2), Imm32(param2));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionA(int bits, FunctionPointer func, const Gen::OpArg& arg1)
template <typename FunctionPointer, typename... Args>
void ABI_CallFunctionA(int bits, FunctionPointer func, const Gen::OpArg& arg1, Args... args)
{
if (!arg1.IsSimpleReg(ABI_PARAM1))
MOV(bits, R(ABI_PARAM1), arg1);
MOVArgs<2>(args...);
ABI_CallFunction(func);
}

Expand All @@ -1148,6 +1072,7 @@ class XEmitter
void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
size_t needed_frame_size = 0);

private:
// Utility to generate a call to a std::function object.
//
// Unfortunately, calling operator() directly is undefined behavior in C++
Expand All @@ -1159,11 +1084,44 @@ class XEmitter
return (*f)(args...);
}

template <typename T, typename... Args>
void ABI_CallLambdaC(const std::function<T(Args...)>* f, u32 p1)
template <u32 ParamNumber = 1, typename Arg1, typename... Args>
void MOVArgs(Arg1 arg1, Args... args)
{
constexpr X64Reg ABI_PARAMS[] = {
ABI_PARAM1,
ABI_PARAM2,
ABI_PARAM3,
ABI_PARAM4,
};

static_assert(ParamNumber <= ArraySize(ABI_PARAMS), "Too many parameters!");

MOVArg(ABI_PARAMS[ParamNumber - 1], arg1);
MOVArgs<ParamNumber + 1>(args...);
}

template <u32 = 1>
void MOVArgs()
{
}

// Handle integer/pointer parameters.
template <typename T>
void MOVArg(X64Reg reg, T arg)
{
if constexpr (std::is_pointer_v<T>)
MOV(64, R(reg), ImmPtr(arg));
else if constexpr (sizeof(arg) == sizeof(u64))
MOV(64, R(reg), Imm64(static_cast<u64>(arg)));
else if constexpr (sizeof(arg) == sizeof(u32) || sizeof(arg) == sizeof(u16))
MOV(32, R(reg), Imm32(static_cast<u32>(arg)));
}

// Handle reference parameters passed with std::ref.
template <typename T>
void MOVArg(X64Reg reg, std::reference_wrapper<T> arg)
{
auto trampoline = &XEmitter::CallLambdaTrampoline<T, Args...>;
ABI_CallFunctionPC(trampoline, reinterpret_cast<const void*>(f), p1);
MOVArg(reg, &arg.get());
}
}; // class XEmitter

Expand Down
7 changes: 3 additions & 4 deletions Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)

m_gpr.PushRegs();
ASSERT_MSG(DSPLLE, interpreter_function != nullptr, "No function for %04x", inst);
ABI_CallFunctionC16(interpreter_function, inst);
ABI_CallFunction(interpreter_function, inst);
m_gpr.PopRegs();
}

Expand All @@ -171,7 +171,7 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
const auto interpreter_function = Interpreter::GetExtOp(inst);

m_gpr.PushRegs();
ABI_CallFunctionC16(interpreter_function, inst);
ABI_CallFunction(interpreter_function, inst);
m_gpr.PopRegs();
INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x", inst);
ext_is_jit = false;
Expand Down Expand Up @@ -400,8 +400,7 @@ void DSPEmitter::CompileCurrent(DSPEmitter& emitter)
const u8* DSPEmitter::CompileStub()
{
const u8* entryPoint = AlignCode16();
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(this)));
ABI_CallFunction(CompileCurrent);
ABI_CallFunction(CompileCurrent, std::ref(*this));
XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed
JMP(m_return_dispatcher);
return entryPoint;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/DSP/Jit/x64/DSPJitUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ void DSPEmitter::dmem_read_imm(u16 address)
case 0xf: // Fxxx HW regs
{
m_gpr.PushRegs();
ABI_CallFunctionC16(gdsp_ifx_read, address);
ABI_CallFunction(gdsp_ifx_read, address);
m_gpr.PopRegs();
break;
}
Expand Down
16 changes: 8 additions & 8 deletions Source/Core/Core/PowerPC/Jit64/Jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
}
Interpreter::Instruction instr = PPCTables::GetInterpreterOp(inst);
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(instr, inst.hex);
ABI_CallFunction(instr, inst.hex);
ABI_PopRegistersAndAdjustStack({}, 0);
if (js.op->opinfo->flags & FL_ENDBLOCK)
{
Expand All @@ -434,7 +434,7 @@ void Jit64::HLEFunction(UGeckoInstruction _inst)
gpr.Flush();
fpr.Flush();
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionCC(HLE::Execute, js.compilerPC, _inst.hex);
ABI_CallFunction(HLE::Execute, js.compilerPC, _inst.hex);
ABI_PopRegistersAndAdjustStack({}, 0);
}

Expand Down Expand Up @@ -488,8 +488,8 @@ bool Jit64::Cleanup()
if (MMCR0.Hex || MMCR1.Hex)
{
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionCCC(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
js.numFloatingPointInst);
ABI_CallFunction(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
js.numFloatingPointInst);
ABI_PopRegistersAndAdjustStack({}, 0);
did_something = true;
}
Expand Down Expand Up @@ -850,8 +850,8 @@ u8* Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
const u8* target = GetCodePtr();
MOV(32, PPCSTATE(pc), Imm32(js.blockStart));
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(JitInterface::CompileExceptionCheck,
static_cast<u32>(JitInterface::ExceptionType::PairedQuantize));
ABI_CallFunction(JitInterface::CompileExceptionCheck,
JitInterface::ExceptionType::PairedQuantize);
ABI_PopRegistersAndAdjustStack({}, 0);
JMP(asm_routines.dispatcher_no_check, true);
SwitchToNearCode();
Expand Down Expand Up @@ -1138,8 +1138,8 @@ void Jit64::IntializeSpeculativeConstants()
target = GetCodePtr();
MOV(32, PPCSTATE(pc), Imm32(js.blockStart));
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(JitInterface::CompileExceptionCheck,
static_cast<u32>(JitInterface::ExceptionType::SpeculativeConstants));
ABI_CallFunction(JitInterface::CompileExceptionCheck,
JitInterface::ExceptionType::SpeculativeConstants);
ABI_PopRegistersAndAdjustStack({}, 0);
JMP(asm_routines.dispatcher, true);
SwitchToNearCode();
Expand Down
3 changes: 1 addition & 2 deletions Source/Core/Core/PowerPC/Jit64/JitAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ void Jit64AsmRoutineManager::Generate()

// Ok, no block, let's call the slow dispatcher
ABI_PushRegistersAndAdjustStack({}, 0);
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(&m_jit)));
ABI_CallFunction(JitBase::Dispatch);
ABI_CallFunction(JitBase::Dispatch, std::ref(m_jit));
ABI_PopRegistersAndAdjustStack({}, 0);

TEST(64, R(ABI_RETURN), R(ABI_RETURN));
Expand Down
18 changes: 9 additions & 9 deletions Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
void CallLambda(int sbits, const std::function<T(u32)>* lambda)
{
m_code->ABI_PushRegistersAndAdjustStack(m_registers_in_use, 0);
m_code->ABI_CallLambdaC(lambda, m_address);
m_code->ABI_CallLambda(lambda, m_address);
m_code->ABI_PopRegistersAndAdjustStack(m_registers_in_use, 0);
MoveOpArgToReg(sbits, R(ABI_RETURN));
}
Expand Down Expand Up @@ -458,16 +458,16 @@ void EmuCodeBlock::SafeLoadToRegImmediate(X64Reg reg_value, u32 address, int acc
switch (accessSize)
{
case 64:
ABI_CallFunctionC(PowerPC::Read_U64, address);
ABI_CallFunction(PowerPC::Read_U64, address);
break;
case 32:
ABI_CallFunctionC(PowerPC::Read_U32, address);
ABI_CallFunction(PowerPC::Read_U32, address);
break;
case 16:
ABI_CallFunctionC(PowerPC::Read_U16_ZX, address);
ABI_CallFunction(PowerPC::Read_U16_ZX, address);
break;
case 8:
ABI_CallFunctionC(PowerPC::Read_U8_ZX, address);
ABI_CallFunction(PowerPC::Read_U8_ZX, address);
break;
}
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
Expand Down Expand Up @@ -655,16 +655,16 @@ bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address,
switch (accessSize)
{
case 64:
ABI_CallFunctionAC(64, PowerPC::Write_U64, arg, address);
ABI_CallFunctionA(64, PowerPC::Write_U64, arg, address);
break;
case 32:
ABI_CallFunctionAC(32, PowerPC::Write_U32, arg, address);
ABI_CallFunctionA(32, PowerPC::Write_U32, arg, address);
break;
case 16:
ABI_CallFunctionAC(16, PowerPC::Write_U16, arg, address);
ABI_CallFunctionA(16, PowerPC::Write_U16, arg, address);
break;
case 8:
ABI_CallFunctionAC(8, PowerPC::Write_U8, arg, address);
ABI_CallFunctionA(8, PowerPC::Write_U8, arg, address);
break;
}
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
Expand Down

0 comments on commit 0255d5d

Please sign in to comment.