mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-17 16:30:30 +02:00
ARM emitter: Complete VLD1/VST1 for lanes and to-all-lanes.
This commit is contained in:
1 parent
b794060dba
commit
cda4e9cbf3
2 files changed
+100
-48
No files matched your search
+68
-23
@@ -1177,6 +1177,21 @@ u32 EncodeVm(ARMReg Vm)
|
||||
}
|
||||
}
|
||||
|
||||
u32 encodedSize(u32 value)
|
||||
{
|
||||
if (value & I_8)
|
||||
return 0;
|
||||
else if (value & I_16)
|
||||
return 1;
|
||||
else if ((value & I_32) || (value & F_32))
|
||||
return 2;
|
||||
else if (value & I_64)
|
||||
return 3;
|
||||
else
|
||||
_dbg_assert_msg_(JIT, false, "Passed invalid size to integer NEON instruction");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ARMReg SubBase(ARMReg Reg)
|
||||
{
|
||||
if (Reg >= S0)
|
||||
@@ -2369,43 +2384,72 @@ static int RegCountToType(int nRegs, NEONAlignment align) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ARMXEmitter::VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm)
|
||||
void ARMXEmitter::VLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm)
|
||||
{
|
||||
u32 spacing = RegCountToType(regCount, align); // Only support loading to 1 reg
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
|
||||
Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (1 << 21) | (Rn << 16)
|
||||
Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (load << 21) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
|
||||
| (align << 4) | Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm)
|
||||
void ARMXEmitter::VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) {
|
||||
VLDST1(true, Size, Vd, Rn, regCount, align, Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) {
|
||||
VLDST1(false, Size, Vd, Rn, regCount, align, Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm)
|
||||
{
|
||||
u32 spacing = RegCountToType(regCount, align); // Only support loading to 1 reg
|
||||
// Gets encoded as a double register
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Vd = SubBase(Vd);
|
||||
// Support quad lanes by converting to D lanes
|
||||
if (register_quad && lane > 1) {
|
||||
Vd = (ARMReg)((int)Vd + 1);
|
||||
lane -= 2;
|
||||
}
|
||||
int encSize = encodedSize(Size);
|
||||
int index_align = 0;
|
||||
switch (encSize) {
|
||||
case 0: index_align = lane << 1; break;
|
||||
case 1: index_align = lane << 2; if (aligned) index_align |= 1; break;
|
||||
case 2: index_align = lane << 3; if (aligned) index_align |= 3; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Write32((0xF4 << 24) | (1 << 23) | ((Vd & 0x10) << 18) | (load << 21) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (encSize << 10)
|
||||
| (index_align << 4) | Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) {
|
||||
VLDST1_lane(true, Size, Vd, Rn, lane, aligned, Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) {
|
||||
VLDST1_lane(false, Size, Vd, Rn, lane, aligned, Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VLD1_all_lanes(u32 Size, ARMReg Vd, ARMReg Rn, bool aligned, ARMReg Rm) {
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Vd = SubBase(Vd);
|
||||
|
||||
Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
|
||||
| (align << 4) | Rm);
|
||||
int T = register_quad; // two D registers
|
||||
|
||||
Write32((0xF4 << 24) | (1 << 23) | ((Vd & 0x10) << 18) | (1 << 21) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (0xC << 8) | (encodedSize(Size) << 6)
|
||||
| (T << 5) | (aligned << 4) | Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm) {
|
||||
_dbg_assert_msg_(JIT, false, "VLD1_lane not done yet");
|
||||
// TODO
|
||||
}
|
||||
|
||||
void ARMXEmitter::VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm) {
|
||||
_dbg_assert_msg_(JIT, false, "VST1_lane not done yet");
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ARMXEmitter::VLD2(u32 Size, ARMReg Vd, ARMReg Rn, NEONAlignment align, ARMReg Rm)
|
||||
/*
|
||||
void ARMXEmitter::VLD2(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm)
|
||||
{
|
||||
u32 spacing = 0x8; // Single spaced registers
|
||||
// Gets encoded as a double register
|
||||
@@ -2415,6 +2459,7 @@ void ARMXEmitter::VLD2(u32 Size, ARMReg Vd, ARMReg Rn, NEONAlignment align, ARMR
|
||||
| ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
|
||||
| (align << 4) | Rm);
|
||||
}
|
||||
*/
|
||||
|
||||
void ARMXEmitter::VREVX(u32 size, u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
|
||||
+32
-25
@@ -70,6 +70,9 @@ enum ARMReg
|
||||
// ASIMD Quad-Word registers
|
||||
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
|
||||
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
|
||||
|
||||
// for NEON VLD/VST instructions
|
||||
REG_UPDATE = R13,
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
@@ -360,6 +363,8 @@ u32 EncodeVd(ARMReg Vd);
|
||||
u32 EncodeVn(ARMReg Vn);
|
||||
u32 EncodeVm(ARMReg Vm);
|
||||
|
||||
u32 encodedSize(u32 value);
|
||||
|
||||
// Subtracts the base from the register to give us the real one
|
||||
ARMReg SubBase(ARMReg Reg);
|
||||
|
||||
@@ -720,26 +725,44 @@ public:
|
||||
|
||||
// Notes:
|
||||
// Rm == _PC is interpreted as no offset, otherwise, effective address is sum of Rn and Rm
|
||||
// Rm == R13 is interpreted as VLD1, .... [Rn]!
|
||||
|
||||
// Rm == R13 is interpreted as VLD1, .... [Rn]! Added a REG_UPDATE pseudo register.
|
||||
|
||||
// Load/store multiple registers full of elements (a register is a D register)
|
||||
// Specifying alignment when it can be guaranteed is documented to improve load/store performance.
|
||||
// For example, when loading a set of four 64-bit registers that we know is 32-byte aligned, we should specify ALIGN_256.
|
||||
void VLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm);
|
||||
void VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
void VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
|
||||
// Load/store single lanes of D registers
|
||||
// TODO
|
||||
void VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
void VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
|
||||
|
||||
// TODO: Make quad-oriented wrappers for the above.
|
||||
|
||||
void VLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm);
|
||||
void VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm = _PC);
|
||||
void VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm = _PC);
|
||||
|
||||
// Load one value into all lanes of a D or a Q register (either supported, all formats should work).
|
||||
void VLD1_all_lanes(u32 Size, ARMReg Vd, ARMReg Rn, bool aligned, ARMReg Rm = _PC);
|
||||
|
||||
/*
|
||||
// Deinterleave two loads... or something. TODO
|
||||
void VLD2(u32 Size, ARMReg Vd, ARMReg Rn, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
void VLD2(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
void VST2(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
|
||||
void VLD2_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
void VST2_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
|
||||
void VLD3(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
void VST3(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
|
||||
void VLD3_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
void VST3_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
|
||||
void VLD4(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
void VST4(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
|
||||
void VLD4_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
void VST4_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
|
||||
*/
|
||||
|
||||
void VMRS_APSR();
|
||||
void VMRS(ARMReg Rt);
|
||||
@@ -761,22 +784,6 @@ public:
|
||||
void CMPI2R(ARMReg rs, u32 val, ARMReg scratch);
|
||||
void TSTI2R(ARMReg rs, u32 val, ARMReg scratch);
|
||||
void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||
|
||||
inline u32 encodedSize(u32 value)
|
||||
{
|
||||
if (value & I_8)
|
||||
return 0;
|
||||
else if (value & I_16)
|
||||
return 1;
|
||||
else if ((value & I_32) || (value & F_32))
|
||||
return 2;
|
||||
else if (value & I_64)
|
||||
return 3;
|
||||
else
|
||||
_dbg_assert_msg_(JIT, false, "Passed invalid size to integer NEON instruction");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}; // class ARMXEmitter
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user