From 30a6a5d10ff4045e705b345b391d74bfc9b59c62 Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 7 Mar 2014 02:52:36 +1000 Subject: [PATCH] ARMJIT: Implement VLDM/VSTM load/store combinations and use in armjit. Also add them to disassembler. --- Common/ArmEmitter.cpp | 25 ++++++++++++++ Common/ArmEmitter.h | 5 +++ Core/MIPS/ARM/ArmCompVFPU.cpp | 51 +++++++++++++++++++++++------ ext/disarm.cpp | 61 +++++++++++++++++++++++++++++------ 4 files changed, 123 insertions(+), 19 deletions(-) diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index e4e7d86bf..3c2ac9ab5 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -1026,6 +1026,11 @@ void ARMXEmitter::WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegLi { Write32(condition | (op << 20) | (WriteBack << 21) | (dest << 16) | RegList); } +void ARMXEmitter::WriteVRegStoreOp(u32 op, ARMReg Rn, bool Double, bool WriteBack, ARMReg Vd, u8 numregs) +{ + ARMReg Dest = SubBase(Vd); + Write32(condition | (op << 20) | (WriteBack << 21) | (Rn << 16) | ((Dest & 0x1) << 22) | ((Dest & 0x1E) << 11) | ((0xA | Double) << 8) | (numregs << Double) ); +} void ARMXEmitter::STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...) { u16 RegList = 0; @@ -1287,6 +1292,26 @@ void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(13, Vd, D4, Vm); } void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(12, Vd, D5, D0); } void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(13, Vd, D5, D0); } +void ARMXEmitter::VLDMIA(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs) +{ + WriteVRegStoreOp(0x80 | 0x40 | 0x8 | 1, dest, false, WriteBack, firstreg, numregs); +} + +void ARMXEmitter::VSTMIA(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs) +{ + WriteVRegStoreOp(0x80 | 0x40 | 0x8, dest, false, WriteBack, firstreg, numregs); +} + +void ARMXEmitter::VLDMDB(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs) +{ + WriteVRegStoreOp(0x80 | 0x040 | 0x10 | 1, dest, false, WriteBack, firstreg, numregs); +} + +void ARMXEmitter::VSTMDB(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs) +{ + WriteVRegStoreOp(0x80 | 0x040 | 0x10, dest, false, WriteBack, firstreg, numregs); +} + void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) { _assert_msg_(JIT, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index 865439d83..4563c5ec4 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -392,6 +392,7 @@ private: void WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 op2, bool RegAdd); void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList); + void WriteVRegStoreOp(u32 op, ARMReg dest, bool Double, bool WriteBack, ARMReg firstreg, u8 numregs); void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2); void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2); void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2); @@ -584,6 +585,10 @@ public: void VSUB(IntegerSize size, ARMReg Vd, ARMReg Vn, ARMReg Vm); // VFP Only + void VLDMIA(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs); + void VSTMIA(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs); + void VLDMDB(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs); + void VSTMDB(ARMReg dest, bool WriteBack, ARMReg firstreg, int numregs); void VLDR(ARMReg Dest, ARMReg Base, s16 offset); void VSTR(ARMReg Src, ARMReg Base, s16 offset); void VCMP(ARMReg Vd, ARMReg Vm); diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 95161ea41..5e3431dd7 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -364,16 +364,32 @@ namespace MIPSComp skip = B_CC(CC_EQ); } - for (int i = 0; i < 4; i++) - VLDR(fpr.V(vregs[i]), R0, i * 4); + bool consecutive = true; + for (int i = 0; i < 3 && consecutive; i++) + if ((fpr.V(vregs[i]) + 1) != fpr.V(vregs[i+1])) + consecutive = false; + if (consecutive) { + VLDMIA(R0, false, fpr.V(vregs[0]), 4); + } else { + for (int i = 0; i < 4; i++) + VLDR(fpr.V(vregs[i]), R0, i * 4); + } if (doCheck) { SetJumpTarget(skip); SetCC(CC_AL); } #else - for (int i = 0; i < 4; i++) - VLDR(fpr.V(vregs[i]), R0, i * 4); + bool consecutive = true; + for (int i = 0; i < 3 && consecutive; i++) + if ((fpr.V(vregs[i]) + 1) != fpr.V(vregs[i+1])) + consecutive = false; + if (consecutive) { + VLDMIA(R0, false, fpr.V(vregs[0]), 4); + } else { + for (int i = 0; i < 4; i++) + VLDR(fpr.V(vregs[i]), R0, i * 4); + } if (doCheck) { SetCC(CC_EQ); @@ -413,16 +429,32 @@ namespace MIPSComp skip = B_CC(CC_EQ); } - for (int i = 0; i < 4; i++) - VSTR(fpr.V(vregs[i]), R0, i * 4); + bool consecutive = true; + for (int i = 0; i < 3 && consecutive; i++) + if ((fpr.V(vregs[i]) + 1) != fpr.V(vregs[i+1])) + consecutive = false; + if (consecutive) { + VSTMIA(R0, false, fpr.V(vregs[0]), 4); + } else { + for (int i = 0; i < 4; i++) + VSTR(fpr.V(vregs[i]), R0, i * 4); + } if (doCheck) { SetJumpTarget(skip); SetCC(CC_AL); } #else - for (int i = 0; i < 4; i++) - VSTR(fpr.V(vregs[i]), R0, i * 4); + bool consecutive = true; + for (int i = 0; i < 3 && consecutive; i++) + if ((fpr.V(vregs[i]) + 1) != fpr.V(vregs[i+1])) + consecutive = false; + if (consecutive) { + VSTMIA(R0, false, fpr.V(vregs[0]), 4); + } else { + for (int i = 0; i < 4; i++) + VSTR(fpr.V(vregs[i]), R0, i * 4); + } if (doCheck) { SetCC(CC_AL); @@ -1812,8 +1844,7 @@ namespace MIPSComp VMOV(R0, fpr.V(sreg)); QuickCallFunction(R1, negSin ? (void *)&SinCosNegSin : (void *)&SinCos); gpr.SetRegImm(R0, (u32)(&sincostemp[0])); - VLDR(S0, R0, 0); - VLDR(S1, R0, 4); + VLDMIA(R0, false, S0, 2); char what[4] = {'0', '0', '0', '0'}; if (((imm >> 2) & 3) == (imm & 3)) { diff --git a/ext/disarm.cpp b/ext/disarm.cpp index 21e332113..166ff9858 100644 --- a/ext/disarm.cpp +++ b/ext/disarm.cpp @@ -125,18 +125,61 @@ bool DisasmVFP(uint32_t op, char *text) { #else const char *cond = CCFlagsStr[op >> 28]; switch ((op >> 24) & 0xF) { - case 0xD: - // VLDR/VSTR + case 0xC: + // VLDMIA/VSTMIA { - int base = (op >> 16) & 0xF; - bool add = (op >> 23) & 1; - int freg = ((op >> 11) & 0x1E) | ((op >> 22) & 1); - int offset = (op & 0xFF) << 2; - if (!add) offset = -offset; - bool vldr = (op >> 20) & 1; bool single_reg = ((op >> 8) & 0xF) == 10; + int freg = ((op >> 11) & 0x1E) | ((op >> 22) & 1); + int base = (op >> 16) & 0xF; + bool load = (op >> 20) & 1; + bool writeback = (op >> 21) & 1; + int numregs = op & 0xF; + bool add = (op >> 23) & 1; + if (add && writeback && load && base == 13) { + if (single_reg) + sprintf(text, "VPOP%s {s%i-s%i}", cond, freg, freg-1+numregs); + else + sprintf(text, "VPOP%s {d%i-d%i}", cond, freg, freg-1+(numregs/2)); + + return true; + } + if (single_reg) + sprintf(text, "%s%s r%i%s, {s%i-s%i}", load ? "VLDMIA" : "VSTMIA", cond, base, writeback ? "!":"", freg, freg-1+numregs); + else + sprintf(text, "%s%s r%i%s, {d%i-d%i}", load ? "VLDMIA" : "VSTMIA", cond, base, writeback ? "!":"", freg, freg-1+(numregs/2)); + + return true; + } + case 0xD: + // VLDR/VSTR/VLDMDB/VSTMDB + { + bool single_reg = ((op >> 8) & 0xF) == 10; + int freg = ((op >> 11) & 0x1E) | ((op >> 22) & 1); + int base = (op >> 16) & 0xF; + bool load = (op >> 20) & 1; + bool add = (op >> 23) & 1; + bool writeback = (op >> 21) & 1; + if (writeback) { // Multiple + int numregs = op & 0xF; + if (!add && !load && base == 13) { + if (single_reg) + sprintf(text, "VPUSH%s {s%i-s%i}", cond, freg, freg-1+numregs); + else + sprintf(text, "VPUSH%s {d%i-d%i}", cond, freg, freg-1+(numregs/2)); + + return true; + } + + if (single_reg) + sprintf(text, "%s%s r%i, {s%i-s%i}", load ? "VLDMDB" : "VSTMDB", cond, base, freg, freg-1+numregs); + else + sprintf(text, "%s%s r%i, {d%i-d%i}", load ? "VLDMDB" : "VSTMDB", cond, base, freg, freg-1+(numregs/2)); + } else { + int offset = (op & 0xFF) << 2; + if (!add) offset = -offset; + sprintf(text, "%s%s s%i, [r%i, #%i]", load ? "VLDR" : "VSTR", cond, freg, base, offset); + } - sprintf(text, "%s%s s%i, [r%i, #%i]", vldr ? "VLDR" : "VSTR", cond, freg, base, offset); return true; }