From bd79603c66b54e77ca5b627460b6bdfd1936b2f4 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 9 Oct 2013 23:03:39 +0000 Subject: [PATCH] [ARM-JitArmIL] Enable a bunch of instructions. --- .../Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp | 150 ++++++++++++++++-- Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h | 1 + .../Src/PowerPC/JitArmIL/JitIL_Tables.cpp | 56 +++---- 3 files changed, 169 insertions(+), 38 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp b/Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp index f9aad96ba4..5215f00fb3 100644 --- a/Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp @@ -56,7 +56,6 @@ static void regClearInst(RegInfo& RI, InstLoc I) { if (RI.regs[RegAllocOrder[i]] == I) RI.regs[RegAllocOrder[i]] = 0; } - static void regNormalRegClear(RegInfo& RI, InstLoc I) { if (RI.IInfo[I - RI.FirstI] & 4) regClearInst(RI, getOp1(I)); @@ -125,6 +124,25 @@ static ARMReg regLocForInst(RegInfo& RI, InstLoc I) { RI.Jit->LDR(reg, R14, 0); return reg; } +static ARMReg regBinLHSReg(RegInfo& RI, InstLoc I) { + ARMReg reg = regFindFreeReg(RI); + RI.Jit->MOV(reg, regLocForInst(RI, getOp1(I))); + return reg; +} + +// If the lifetime of the register used by an operand ends at I, +// return the register. Otherwise return a free register. +static ARMReg regBinReg(RegInfo& RI, InstLoc I) { + // FIXME: When regLocForInst() is extracted as a local variable, + // "Retrieving unknown spill slot?!" is shown. + if (RI.IInfo[I - RI.FirstI] & 4) + return regLocForInst(RI, getOp1(I)); + else if (RI.IInfo[I - RI.FirstI] & 8) + return regLocForInst(RI, getOp2(I)); + + return regFindFreeReg(RI); +} + static void regSpillCallerSaved(RegInfo& RI) { regSpill(RI, R0); regSpill(RI, R1); @@ -144,17 +162,28 @@ static void regWriteExit(RegInfo& RI, InstLoc dest) { } } static void regStoreInstToPPCState(RegInfo& RI, unsigned width, InstLoc I, s32 offset) { - if (width != 32) { - PanicAlert("Not implemented!"); - return; + void (JitArmIL::*op)(ARMReg, ARMReg, Operand2, bool); + switch(width) + { + case 32: + op = &JitArmIL::STR; + break; + case 8: + op = &JitArmIL::STRB; + break; + default: + PanicAlert("Not implemented!"); + return; + break; } + if (isImm(*I)) { RI.Jit->MOVI2R(R12, RI.Build->GetImmValue(I)); - RI.Jit->STR(R12, R9, offset); + (RI.Jit->*op)(R12, R9, offset, true); return; } ARMReg reg = regEnsureInReg(RI, I); - RI.Jit->STR(reg, R9, offset); + (RI.Jit->*op)(reg, R9, offset, true); } // @@ -177,6 +206,10 @@ void JitArmIL::BIN_XOR(ARMReg reg, Operand2 op2) { EOR(reg, reg, op2); } +void JitArmIL::BIN_OR(ARMReg reg, Operand2 op2) +{ + ORR(reg, reg, op2); +} void JitArmIL::BIN_AND(ARMReg reg, Operand2 op2) { AND(reg, reg, op2); @@ -185,6 +218,19 @@ void JitArmIL::BIN_ADD(ARMReg reg, Operand2 op2) { ADD(reg, reg, op2); } +static void regEmitShiftInst(RegInfo& RI, InstLoc I, void (JitArmIL::*op)(ARMReg, ARMReg, Operand2)) +{ + ARMReg reg = regBinLHSReg(RI, I); + if (isImm(*getOp2(I))) { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + (RI.Jit->*op)(reg, reg, RHS); + RI.regs[reg] = I; + return; + } + (RI.Jit->*op)(reg, reg, regLocForInst(RI, getOp2(I))); + RI.regs[reg] = I; + regNormalRegClear(RI, I); +} static void regEmitBinInst(RegInfo& RI, InstLoc I, void (JitArmIL::*op)(ARMReg, Operand2), @@ -202,10 +248,13 @@ static void regEmitBinInst(RegInfo& RI, InstLoc I, } if (isImm(*getOp2(I))) { unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - if (RHS + 128 < 256) { - (RI.Jit->*op)(reg, RHS); - } else { - (RI.Jit->*op)(reg, RHS); + Operand2 RHSop; + if (TryMakeOperand2(RHS, RHSop)) + (RI.Jit->*op)(reg, RHSop); + else + { + RI.Jit->MOVI2R(R12, RHS); + (RI.Jit->*op)(reg, R12); } } else if (commuted) { (RI.Jit->*op)(reg, regLocForInst(RI, getOp1(I))); @@ -215,6 +264,22 @@ static void regEmitBinInst(RegInfo& RI, InstLoc I, RI.regs[reg] = I; regNormalRegClear(RI, I); } +static void regEmitCmp(RegInfo& RI, InstLoc I) { + if (isImm(*getOp2(I))) { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + Operand2 op; + if (TryMakeOperand2(RHS, op)) + RI.Jit->CMP(regLocForInst(RI, getOp1(I)), op); + else + { + RI.Jit->MOVI2R(R12, RHS); + RI.Jit->CMP(regLocForInst(RI, getOp1(I)), R12); + } + } else { + ARMReg reg = regEnsureInReg(RI, getOp1(I)); + RI.Jit->CMP(reg, regLocForInst(RI, getOp2(I))); + } +} static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) { RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts()); @@ -447,6 +512,18 @@ static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) { break; } + case StoreGReg: { + unsigned ppcreg = *I >> 16; + regStoreInstToPPCState(RI, 32, getOp1(I), PPCSTATE_OFF(gpr[ppcreg])); + regNormalRegClear(RI, I); + break; + } + case StoreCR: { + unsigned ppcreg = *I >> 16; + regStoreInstToPPCState(RI, 8, getOp1(I), PPCSTATE_OFF(cr_fast[ppcreg])); + regNormalRegClear(RI, I); + break; + } case StoreLink: { regStoreInstToPPCState(RI, 32, getOp1(I), PPCSTATE_OFF(spr[SPR_LR])); regNormalRegClear(RI, I); @@ -565,11 +642,39 @@ static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) { Jit->WriteRfiExitDestInR(rA); // rA gets unlocked here break; } + case Shl: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &JitArmIL::LSL); + break; + } + case Shrl: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &JitArmIL::LSR); + break; + } + case Sarl: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &JitArmIL::ASR); + break; + } case And: { if (!thisUsed) break; regEmitBinInst(RI, I, &JitArmIL::BIN_AND, true); break; } + case Not: { + if (!thisUsed) break; + ARMReg reg = regBinLHSReg(RI, I); + Jit->MVN(reg, reg); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case Or: { + if (!thisUsed) break; + regEmitBinInst(RI, I, &JitArmIL::BIN_OR, true); + break; + } case Xor: { if (!thisUsed) break; regEmitBinInst(RI, I, &JitArmIL::BIN_XOR, true); @@ -580,6 +685,31 @@ static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) { regEmitBinInst(RI, I, &JitArmIL::BIN_ADD, true); break; } + case ICmpCRUnsigned: { + if (!thisUsed) break; + regEmitCmp(RI, I); + ARMReg reg = regBinReg(RI, I); + Jit->MOV(reg, 0x2); // Result == 0 + Jit->SetCC(CC_LO); Jit->MOV(reg, 0x8); // Result < 0 + Jit->SetCC(CC_HI); Jit->MOV(reg, 0x4); // Result > 0 + Jit->SetCC(); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + + case ICmpCRSigned: { + if (!thisUsed) break; + regEmitCmp(RI, I); + ARMReg reg = regBinReg(RI, I); + Jit->MOV(reg, 0x2); // Result == 0 + Jit->SetCC(CC_LT); Jit->MOV(reg, 0x8); // Result < 0 + Jit->SetCC(CC_GT); Jit->MOV(reg, 0x4); // Result > 0 + Jit->SetCC(); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } case Int3: Jit->BKPT(0x321); break; diff --git a/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h b/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h index ccbf35bc28..e0462cf852 100644 --- a/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h +++ b/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h @@ -86,6 +86,7 @@ public: // Binary ops void BIN_AND(ARMReg reg, Operand2 op2); void BIN_XOR(ARMReg reg, Operand2 op2); + void BIN_OR(ARMReg reg, Operand2 op2); void BIN_ADD(ARMReg reg, Operand2 op2); // Branches diff --git a/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp b/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp index 31d7504d64..2f6677c952 100644 --- a/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp @@ -47,23 +47,23 @@ static GekkoOPTemplate primarytable[] = {7, &JitArmIL::Default}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}}, {8, &JitArmIL::Default}, //"subfic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, - {10, &JitArmIL::Default}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, - {11, &JitArmIL::Default}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, + {10, &JitArmIL::cmpXX}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, + {11, &JitArmIL::cmpXX}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, {12, &JitArmIL::Default}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, {13, &JitArmIL::Default}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}}, - {14, &JitArmIL::Default}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, - {15, &JitArmIL::Default}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, + {14, &JitArmIL::reg_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, + {15, &JitArmIL::reg_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, {20, &JitArmIL::Default}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}}, {21, &JitArmIL::Default}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {23, &JitArmIL::Default}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}}, - {24, &JitArmIL::Default}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {25, &JitArmIL::Default}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {26, &JitArmIL::Default}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {27, &JitArmIL::Default}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {28, &JitArmIL::Default}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, - {29, &JitArmIL::Default}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {24, &JitArmIL::reg_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {25, &JitArmIL::reg_imm}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {26, &JitArmIL::reg_imm}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {27, &JitArmIL::reg_imm}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {28, &JitArmIL::reg_imm}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {29, &JitArmIL::reg_imm}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {32, &JitArmIL::Default}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {33, &JitArmIL::Default}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, @@ -162,14 +162,14 @@ static GekkoOPTemplate table19[] = { {528, &JitArmIL::bcctrx}, //"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}}, {16, &JitArmIL::bclrx}, //"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}}, - {257, &JitArmIL::Default}, //"crand", OPTYPE_CR, FL_EVIL}}, - {129, &JitArmIL::Default}, //"crandc", OPTYPE_CR, FL_EVIL}}, - {289, &JitArmIL::Default}, //"creqv", OPTYPE_CR, FL_EVIL}}, - {225, &JitArmIL::Default}, //"crnand", OPTYPE_CR, FL_EVIL}}, - {33, &JitArmIL::Default}, //"crnor", OPTYPE_CR, FL_EVIL}}, - {449, &JitArmIL::Default}, //"cror", OPTYPE_CR, FL_EVIL}}, - {417, &JitArmIL::Default}, //"crorc", OPTYPE_CR, FL_EVIL}}, - {193, &JitArmIL::Default}, //"crxor", OPTYPE_CR, FL_EVIL}}, + {257, &JitArmIL::crXX}, //"crand", OPTYPE_CR, FL_EVIL}}, + {129, &JitArmIL::crXX}, //"crandc", OPTYPE_CR, FL_EVIL}}, + {289, &JitArmIL::crXX}, //"creqv", OPTYPE_CR, FL_EVIL}}, + {225, &JitArmIL::crXX}, //"crnand", OPTYPE_CR, FL_EVIL}}, + {33, &JitArmIL::crXX}, //"crnor", OPTYPE_CR, FL_EVIL}}, + {449, &JitArmIL::crXX}, //"cror", OPTYPE_CR, FL_EVIL}}, + {417, &JitArmIL::crXX}, //"crorc", OPTYPE_CR, FL_EVIL}}, + {193, &JitArmIL::crXX}, //"crxor", OPTYPE_CR, FL_EVIL}}, {150, &JitArmIL::Default}, //"isync", OPTYPE_ICACHE, FL_EVIL}}, {0, &JitArmIL::Default}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}}, @@ -181,16 +181,16 @@ static GekkoOPTemplate table19[] = static GekkoOPTemplate table31[] = { - {28, &JitArmIL::Default}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {60, &JitArmIL::Default}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {444, &JitArmIL::Default}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {124, &JitArmIL::Default}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {316, &JitArmIL::Default}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {412, &JitArmIL::Default}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {476, &JitArmIL::Default}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {284, &JitArmIL::Default}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {0, &JitArmIL::Default}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, - {32, &JitArmIL::Default}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, + {28, &JitArmIL::boolX}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {60, &JitArmIL::boolX}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {444, &JitArmIL::boolX}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {124, &JitArmIL::boolX}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {316, &JitArmIL::boolX}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {412, &JitArmIL::boolX}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {476, &JitArmIL::boolX}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {284, &JitArmIL::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {0, &JitArmIL::cmpXX}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, + {32, &JitArmIL::cmpXX}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {26, &JitArmIL::Default}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {922, &JitArmIL::Default}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {954, &JitArmIL::Default}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},