From 47e47891d4f11b39b71e6051d399c6c53ebec146 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 18 Sep 2014 16:33:03 -0500 Subject: [PATCH] [AArch64] Implement a bunch of integer instructions 16 new instructions for AArch64. --- Source/Core/Core/CMakeLists.txt | 1 + Source/Core/Core/PowerPC/JitArm64/Jit.h | 9 + .../PowerPC/JitArm64/JitArm64_Integer.cpp | 229 ++++++++++++++++++ .../Core/PowerPC/JitArm64/JitArm64_Tables.cpp | 32 +-- 4 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 39800a448e..7b0e00a595 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -225,6 +225,7 @@ elseif(_M_ARM_64) PowerPC/JitArm64/JitArm64Cache.cpp PowerPC/JitArm64/JitArm64_RegCache.cpp PowerPC/JitArm64/JitArm64_Branch.cpp + PowerPC/JitArm64/JitArm64_Integer.cpp PowerPC/JitArm64/JitArm64_LoadStore.cpp PowerPC/JitArm64/JitArm64_SystemRegisters.cpp PowerPC/JitArm64/JitArm64_Tables.cpp) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 2915215294..160f72fd2f 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -77,6 +77,10 @@ public: void bcctrx(UGeckoInstruction inst); void bclrx(UGeckoInstruction inst); + // Integer + void arith_imm(UGeckoInstruction inst); + void boolX(UGeckoInstruction inst); + // System Registers void mtmsr(UGeckoInstruction inst); @@ -102,5 +106,10 @@ private: void WriteExitDestInR(ARM64Reg dest); FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set); + + void ComputeRC(u32 d); + + typedef u32 (*Operation)(u32, u32); + void reg_imm(u32 d, u32 a, bool binary, u32 value, Operation do_op, void (ARM64XEmitter::*op)(ARM64Reg, ARM64Reg, ARM64Reg, ArithOption), bool Rc = false); }; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp new file mode 100644 index 0000000000..7d8824d75a --- /dev/null +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -0,0 +1,229 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "Common/Arm64Emitter.h" +#include "Common/Common.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::ComputeRC(u32 d) +{ + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + + if (gpr.IsImm(d)) + { + MOVI2R(XA, gpr.GetImm(d)); + SXTW(XA, XA); + } + else + { + SXTW(XA, gpr.R(d)); + } + + STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val[0])); + gpr.Unlock(WA); +} + +// Following static functions are used in conjunction with reg_imm +static u32 Add(u32 a, u32 b) +{ + return a + b; +} + +static u32 Or(u32 a, u32 b) +{ + return a | b; +} + +static u32 And(u32 a, u32 b) +{ + return a & b; +} + +static u32 Xor(u32 a, u32 b) +{ + return a ^ b; +} + +void JitArm64::reg_imm(u32 d, u32 a, bool binary, u32 value, Operation do_op, void (ARM64XEmitter::*op)(ARM64Reg, ARM64Reg, ARM64Reg, ArithOption), bool Rc) +{ + if (a || binary) + { + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, do_op(gpr.GetImm(a), value)); + } + else + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, value); + (this->*op)(gpr.R(d), gpr.R(a), WA, ArithOption(WA, ST_LSL, 0)); + gpr.Unlock(WA); + } + + if (Rc) + ComputeRC(d); + } + else if (do_op == Add) + { + // a == 0, implies zero register + gpr.SetImmediate(d, value); + if (Rc) + ComputeRC(d); + } + else + { + _assert_msg_(DYNA_REC, false, "Hit impossible condition in reg_imm!"); + } +} + +void JitArm64::arith_imm(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 d = inst.RD, a = inst.RA, s = inst.RS; + + switch (inst.OPCD) + { + case 14: // addi + reg_imm(d, a, false, (u32)(s32)inst.SIMM_16, Add, &ARM64XEmitter::ADD); + break; + case 15: // addis + reg_imm(d, a, false, (u32)inst.SIMM_16 << 16, Add, &ARM64XEmitter::ADD); + break; + case 24: // ori + if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) //check for nop + { + // NOP + return; + } + reg_imm(a, s, true, inst.UIMM, Or, &ARM64XEmitter::ORR); + break; + case 25: // oris + reg_imm(a, s, true, inst.UIMM << 16, Or, &ARM64XEmitter::ORR); + break; + case 28: // andi + reg_imm(a, s, true, inst.UIMM, And, &ARM64XEmitter::AND, true); + break; + case 29: // andis + reg_imm(a, s, true, inst.UIMM << 16, And, &ARM64XEmitter::AND, true); + break; + case 26: // xori + reg_imm(a, s, true, inst.UIMM, Xor, &ARM64XEmitter::EOR); + break; + case 27: // xoris + reg_imm(a, s, true, inst.UIMM << 16, Xor, &ARM64XEmitter::EOR); + break; + } +} + +void JitArm64::boolX(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, s = inst.RS, b = inst.RB; + + if (gpr.IsImm(s) && gpr.IsImm(b)) + { + if (inst.SUBOP10 == 28) // andx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) & (u32)gpr.GetImm(b)); + else if (inst.SUBOP10 == 476) // nandx + gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) & (u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 60) // andcx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) & (~(u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 444) // orx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) | (u32)gpr.GetImm(b)); + else if (inst.SUBOP10 == 124) // norx + gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) | (u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 412) // orcx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) | (~(u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 316) // xorx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) ^ (u32)gpr.GetImm(b)); + else if (inst.SUBOP10 == 284) // eqvx + gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) ^ (u32)gpr.GetImm(b))); + + if (inst.Rc) + ComputeRC(a); + } + else if (s == b) + { + if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */)) + { + if (a != s) + { + MOV(gpr.R(a), gpr.R(s)); + } + } + else if ((inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */)) + { + MVN(gpr.R(a), gpr.R(s)); + } + else if ((inst.SUBOP10 == 412 /* orcx */) || (inst.SUBOP10 == 284 /* eqvx */)) + { + gpr.SetImmediate(a, 0xFFFFFFFF); + } + else if ((inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 316 /* xorx */)) + { + gpr.SetImmediate(a, 0); + } + else + { + PanicAlert("WTF!"); + } + if (inst.Rc) + ComputeRC(a); + } + else + { + if (inst.SUBOP10 == 28) // andx + { + AND(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 476) // nandx + { + AND(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + MVN(gpr.R(a), gpr.R(a)); + } + else if (inst.SUBOP10 == 60) // andcx + { + BIC(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 444) // orx + { + ORR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 124) // norx + { + ORR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + MVN(gpr.R(a), gpr.R(a)); + } + else if (inst.SUBOP10 == 412) // orcx + { + ORN(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 316) // xorx + { + EOR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 284) // eqvx + { + EON(gpr.R(a), gpr.R(b), gpr.R(s), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else + { + PanicAlert("WTF!"); + } + if (inst.Rc) + ComputeRC(a); + } +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index 704329eaee..f8a246280a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -51,19 +51,19 @@ static GekkoOPTemplate primarytable[] = {11, &JitArm64::FallBackToInterpreter}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, {12, &JitArm64::FallBackToInterpreter}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, {13, &JitArm64::FallBackToInterpreter}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}}, - {14, &JitArm64::FallBackToInterpreter}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, - {15, &JitArm64::FallBackToInterpreter}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, + {14, &JitArm64::arith_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, + {15, &JitArm64::arith_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, {20, &JitArm64::FallBackToInterpreter}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}}, {21, &JitArm64::FallBackToInterpreter}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {23, &JitArm64::FallBackToInterpreter}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}}, - {24, &JitArm64::FallBackToInterpreter}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {25, &JitArm64::FallBackToInterpreter}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {26, &JitArm64::FallBackToInterpreter}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {27, &JitArm64::FallBackToInterpreter}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {28, &JitArm64::FallBackToInterpreter}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, - {29, &JitArm64::FallBackToInterpreter}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {24, &JitArm64::arith_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {25, &JitArm64::arith_imm}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {26, &JitArm64::arith_imm}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {27, &JitArm64::arith_imm}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {28, &JitArm64::arith_imm}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {29, &JitArm64::arith_imm}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {32, &JitArm64::FallBackToInterpreter}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {33, &JitArm64::FallBackToInterpreter}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, @@ -181,14 +181,14 @@ static GekkoOPTemplate table19[] = static GekkoOPTemplate table31[] = { - {28, &JitArm64::FallBackToInterpreter}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {60, &JitArm64::FallBackToInterpreter}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {444, &JitArm64::FallBackToInterpreter}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {124, &JitArm64::FallBackToInterpreter}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {316, &JitArm64::FallBackToInterpreter}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {412, &JitArm64::FallBackToInterpreter}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {476, &JitArm64::FallBackToInterpreter}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {284, &JitArm64::FallBackToInterpreter}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {28, &JitArm64::boolX}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {60, &JitArm64::boolX}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {444, &JitArm64::boolX}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {124, &JitArm64::boolX}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {316, &JitArm64::boolX}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {412, &JitArm64::boolX}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {476, &JitArm64::boolX}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {284, &JitArm64::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {0, &JitArm64::FallBackToInterpreter}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {32, &JitArm64::FallBackToInterpreter}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {26, &JitArm64::FallBackToInterpreter}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},