ARM emitter: Complete VLD1/VST1 for lanes and to-all-lanes.

This commit is contained in:
Henrik Rydgard committed 2013-11-23 13:36:26 +01:00
1 parent b794060dba
commit cda4e9cbf3
2 files changed
+100 -48

No files matched your search

+68 -23
View File
@@ -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
View File
@@ -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