From c248a6926817dc2523c35d1c2fbb36c2af0c9a44 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 3 Jun 2023 09:24:10 +0200 Subject: JitArm64: Add utility for calling a function with arguments With this, situations where multiple arguments need to be moved from multiple registers become easy to handle, and we also get compile-time checking that the number of arguments is correct. --- Source/Core/Common/Arm64Emitter.cpp | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'Source/Core/Common/Arm64Emitter.cpp') diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 296b9976c7..93a05fc144 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -1795,6 +1795,62 @@ void ARM64XEmitter::ADRP(ARM64Reg Rd, s64 imm) EncodeAddressInst(1, Rd, static_cast(imm >> 12)); } +// This is using a hand-rolled algorithm. The goal is zero memory allocations, not necessarily +// the best JIT-time time complexity. (The number of moves is usually very small.) +void ARM64XEmitter::ParallelMoves(RegisterMove* begin, RegisterMove* end, + std::array* source_gpr_usages) +{ + // X0-X7 are used for passing arguments. + // X18-X31 are either callee saved or used for special purposes. + constexpr size_t temp_reg_begin = 8; + constexpr size_t temp_reg_end = 18; + + while (begin != end) + { + bool removed_moves_during_this_loop_iteration = false; + + RegisterMove* move = end; + while (move != begin) + { + RegisterMove* prev_move = move; + --move; + if ((*source_gpr_usages)[DecodeReg(move->dst)] == 0) + { + MOV(move->dst, move->src); + (*source_gpr_usages)[DecodeReg(move->src)]--; + std::move(prev_move, end, move); + --end; + removed_moves_during_this_loop_iteration = true; + } + } + + if (!removed_moves_during_this_loop_iteration) + { + // We need to break a cycle using a temporary register. + + size_t temp_reg = temp_reg_begin; + while ((*source_gpr_usages)[temp_reg] != 0) + { + ++temp_reg; + ASSERT_MSG(COMMON, temp_reg != temp_reg_end, "Out of registers"); + } + + const ARM64Reg src = begin->src; + const ARM64Reg dst = + (Is64Bit(src) ? EncodeRegTo64 : EncodeRegTo32)(static_cast(temp_reg)); + + MOV(dst, src); + (*source_gpr_usages)[DecodeReg(dst)] = (*source_gpr_usages)[DecodeReg(src)]; + (*source_gpr_usages)[DecodeReg(src)] = 0; + + std::for_each(begin, end, [src, dst](RegisterMove& move) { + if (move.src == src) + move.src = dst; + }); + } + } +} + template void ARM64XEmitter::MOVI2RImpl(ARM64Reg Rd, T imm) { -- cgit v1.2.3