// Copyright 2014 Dolphin Emulator Project // Licensed under GPLv2 // Refer to the license.txt file included. #include "Common/Arm64Emitter.h" #include "Common/Common.h" #include "Common/StringUtil.h" #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitArm64/JitAsm.h" using namespace Arm64Gen; void JitArm64::ps_abs(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == b); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FABS(64, VD, VB); } void JitArm64::ps_add(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FADD(64, VD, VA, VB); } void JitArm64::ps_div(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FDIV(64, VD, VA, VB); } void JitArm64::ps_madd(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.FMUL(64, V0, VA, VC); m_float_emit.FADD(64, VD, V0, VB); fpr.Unlock(V0); } void JitArm64::ps_madds0(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.DUP(64, V0, VC, 0); m_float_emit.FMUL(64, V0, V0, VA); m_float_emit.FADD(64, VD, V0, VB); fpr.Unlock(V0); } void JitArm64::ps_madds1(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.DUP(64, V0, VC, 1); m_float_emit.FMUL(64, V0, V0, VA); m_float_emit.FADD(64, VD, V0, VB); fpr.Unlock(V0); } void JitArm64::ps_merge00(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.TRN1(64, VD, VA, VB); } void JitArm64::ps_merge01(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.INS(64, VD, 0, VA, 0); m_float_emit.INS(64, VD, 1, VB, 1); } void JitArm64::ps_merge10(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); if (d != a && d != b) { m_float_emit.INS(64, VD, 0, VA, 1); m_float_emit.INS(64, VD, 1, VB, 0); } else { ARM64Reg V0 = fpr.GetReg(); m_float_emit.INS(64, V0, 0, VA, 1); m_float_emit.INS(64, V0, 1, VB, 0); m_float_emit.ORR(VD, V0, V0); fpr.Unlock(V0); } } void JitArm64::ps_merge11(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.TRN2(64, VD, VA, VB); } void JitArm64::ps_mr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; if (d == b) return; fpr.BindToRegister(d, false); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.ORR(VD, VB, VB); } void JitArm64::ps_mul(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); m_float_emit.FMUL(64, VD, VA, VC); } void JitArm64::ps_muls0(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.DUP(64, V0, VC, 0); m_float_emit.FMUL(64, VD, VA, V0); fpr.Unlock(V0); } void JitArm64::ps_muls1(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.DUP(64, V0, VC, 1); m_float_emit.FMUL(64, VD, VA, V0); fpr.Unlock(V0); } void JitArm64::ps_msub(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.FMUL(64, V0, VA, VC); m_float_emit.FSUB(64, VD, V0, VB); fpr.Unlock(V0); } void JitArm64::ps_nabs(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == b); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FABS(64, VD, VB); m_float_emit.FNEG(64, VD, VD); } void JitArm64::ps_neg(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == b); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FNEG(64, VD, VB); } void JitArm64::ps_nmadd(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.FMUL(64, V0, VA, VC); m_float_emit.FADD(64, VD, V0, VB); m_float_emit.FNEG(64, VD, VD); fpr.Unlock(V0); } void JitArm64::ps_nmsub(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.FMUL(64, V0, VA, VC); m_float_emit.FSUB(64, VD, V0, VB); m_float_emit.FNEG(64, VD, VD); fpr.Unlock(V0); } void JitArm64::ps_res(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == b); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FRSQRTE(64, VD, VB); } void JitArm64::ps_sel(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); if (d != a && d != b && d != c) { m_float_emit.FCMGE(64, VD, VA); m_float_emit.BSL(VD, VC, VB); } else { ARM64Reg V0 = fpr.GetReg(); m_float_emit.FCMGE(64, V0, VA); m_float_emit.BSL(V0, VC, VB); m_float_emit.ORR(VD, V0, V0); fpr.Unlock(V0); } } void JitArm64::ps_sub(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, d = inst.FD; fpr.BindToRegister(d, d == a || d == b); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); m_float_emit.FSUB(64, VD, VA, VB); } void JitArm64::ps_sum0(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.DUP(64, V0, VB, 1); if (d != c) { m_float_emit.FADD(64, VD, V0, VA); m_float_emit.INS(64, VD, 1, VC, 1); } else { m_float_emit.FADD(64, V0, V0, VA); m_float_emit.INS(64, VD, 0, V0, 0); } fpr.Unlock(V0); } void JitArm64::ps_sum1(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; fpr.BindToRegister(d, d == a || d == b || d == c); ARM64Reg VA = fpr.R(a); ARM64Reg VB = fpr.R(b); ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); ARM64Reg V0 = fpr.GetReg(); m_float_emit.DUP(64, V0, VA, 0); if (d != c) { m_float_emit.FADD(64, VD, V0, VB); m_float_emit.INS(64, VD, 0, VC, 0); } else { m_float_emit.FADD(64, V0, V0, VB); m_float_emit.INS(64, VD, 1, V0, 1); } fpr.Unlock(V0); }