More ARM32 NEON encoding horrors (VMOVL, VSHLL)

This commit is contained in:
Henrik Rydgard 2015-07-10 23:56:42 +02:00
parent cd1665e8f6
commit 0be2b93ceb
3 changed files with 60 additions and 8 deletions

View File

@ -2723,7 +2723,22 @@ void ARMXEmitter::VSHL(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) {
} }
void ARMXEmitter::VSHLL(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) { void ARMXEmitter::VSHLL(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) {
EncodeShiftByImm((Size & ~I_UNSIGNED), Vd, Vm, shiftAmount, 0xA, false, false, false); if (shiftAmount == (8 * (Size & 0xF))) {
// Entirely different encoding (A2) for size == shift! Bleh.
int sz = 0;
switch (Size & 0xF) {
case I_8: sz = 0; break;
case I_16: sz = 1; break;
case I_32: sz = 2; break;
case I_64:
_dbg_assert_msg_(JIT, false, "Cannot VSHLL 64-bit elements");
}
int imm6 = 0x32 | (sz << 2);
u32 value = (0xF3 << 24) | (1 << 23) | (imm6 << 16) | EncodeVd(Vd) | (0x3 << 8) | EncodeVm(Vm);
Write32(value);
} else {
EncodeShiftByImm((Size & ~I_UNSIGNED), Vd, Vm, shiftAmount, 0xA, false, false, false);
}
} }
void ARMXEmitter::VSHR(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) { void ARMXEmitter::VSHR(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) {

View File

@ -476,10 +476,10 @@ static bool DisasmNeon2Op(uint32_t op, char *text) {
if (op & (1 << 16)) if (op & (1 << 16))
opname = "NEG"; opname = "NEG";
int type = (op >> 6) & 0xF; int opcode = (op >> 6) & 0xF;
int sz = (op >> 18) & 3; int sz = (op >> 18) & 3;
const char *size = "f32"; const char *size = "f32";
switch (type) { switch (opcode) {
case 0xE: case 0xE:
opname = "NEG"; opname = "NEG";
size = GetISizeString(sz); size = GetISizeString(sz);
@ -499,13 +499,24 @@ static bool DisasmNeon2Op(uint32_t op, char *text) {
quadD = false; quadD = false;
doubleD = true; doubleD = true;
break; break;
case 0xC:
opname = "SHLL"; // widen and shift
size = GetISizeString(sz);
quad = false;
quadD = true;
doubleD = true;
break;
} }
int Vd = GetVd(op, quadD, doubleD); int Vd = GetVd(op, quadD, doubleD);
int Vm = GetVm(op, quad, false); int Vm = GetVm(op, quad, false);
char cD = quadD ? 'q' : 'd'; char cD = quadD ? 'q' : 'd';
char c = quad ? 'q' : 'd'; char c = quad ? 'q' : 'd';
sprintf(text, "V%s%s%s %c%i, %c%i", opname, strlen(size) ? "." : "", size, cD, Vd, c, Vm); if (opcode == 0xC) {
sprintf(text, "V%s%s%s %c%i, %c%i, #%d", opname, strlen(size) ? "." : "", size, cD, Vd, c, Vm, 8 << sz);
} else {
sprintf(text, "V%s%s%s %c%i, %c%i", opname, strlen(size) ? "." : "", size, cD, Vd, c, Vm);
}
return true; return true;
} }
@ -605,6 +616,7 @@ to64:
return "i32"; return "i32";
} }
// What a horror show!
static bool DisasmNeon2RegShiftImm(uint32_t op, char *text) { static bool DisasmNeon2RegShiftImm(uint32_t op, char *text) {
bool U = (op >> 24) & 1; bool U = (op >> 24) & 1;
bool quadDest = false; bool quadDest = false;
@ -617,7 +629,7 @@ static bool DisasmNeon2RegShiftImm(uint32_t op, char *text) {
bool sign = false; bool sign = false;
switch (opcode) { switch (opcode) {
case 0x5: opname = "VSHL"; quadDest = quadSrc = ((op >> 6) & 1); break; case 0x5: opname = "VSHL"; quadDest = quadSrc = ((op >> 6) & 1); break;
case 0xA: opname = "VSHLL"; quadDest = true; quadSrc = false; break; case 0xA: opname = "VSHLL"; quadDest = true; quadSrc = false; sign = true; break;
case 0x0: opname = "VSHR"; sign = true; quadDest = quadSrc = ((op >> 6) & 1); inverse = true; break; case 0x0: opname = "VSHR"; sign = true; quadDest = quadSrc = ((op >> 6) & 1); inverse = true; break;
case 0x8: opname = "VSHRN"; quadDest = false; quadSrc = true; inverse = true; incSize = true; break; case 0x8: opname = "VSHRN"; quadDest = false; quadSrc = true; inverse = true; incSize = true; break;
default: default:
@ -632,8 +644,23 @@ static bool DisasmNeon2RegShiftImm(uint32_t op, char *text) {
char c2 = quadSrc ? 'q' : 'd'; char c2 = quadSrc ? 'q' : 'd';
int imm7 = ((op >> 16) & 0x3f) | ((op & 0x80) >> 1); int imm7 = ((op >> 16) & 0x3f) | ((op & 0x80) >> 1);
int shift; int shift;
const char *size = DecodeSizeAndShiftImm7(U, sign, inverse, imm7, incSize, &shift);
sprintf(text, "%s.%s %c%i, %c%i, #%i", opname, size, c1, Vd, c2, Vm, shift); const char *size;
if (opcode == 0xA) {
if (imm7 & 0x40) {
sprintf(text, "neon2regshiftimm undefined %08x", op);
return true;
}
}
size = DecodeSizeAndShiftImm7(U, sign, inverse, imm7, incSize, &shift);
if (opcode == 0xA && shift == 0) {
opname = "VMOVL";
sprintf(text, "%s.%s %c%i, %c%i", opname, size, c1, Vd, c2, Vm);
} else {
sprintf(text, "%s.%s %c%i, %c%i, #%i", opname, size, c1, Vd, c2, Vm, shift);
}
return true; return true;
} }

View File

@ -32,6 +32,16 @@ bool TestArmEmitter() {
u32 code[512]; u32 code[512];
ARMXEmitter emitter((u8 *)code); ARMXEmitter emitter((u8 *)code);
emitter.VSHLL(I_16, Q0, D0, 16);
RET(CheckLast(emitter, "f3b60300 VSHLL.i16 q0, d0, #16"));
emitter.VSHLL(I_8, Q0, D0, 4);
RET(CheckLast(emitter, "f28c0a10 VSHLL.s8 q0, d0, #4"));
emitter.VSHLL(I_8, Q0, D0, 8);
RET(CheckLast(emitter, "f3b20300 VSHLL.i8 q0, d0, #8"));
emitter.VMOVL(I_16 | I_UNSIGNED, Q0, D0);
RET(CheckLast(emitter, "f3900a10 VMOVL.u16 q0, d0"));
emitter.VMOVL(I_32 | I_SIGNED, Q0, D0);
RET(CheckLast(emitter, "f2a00a10 VMOVL.s32 q0, d0"));
emitter.VSHRN(I_32, D0, Q0, 16); emitter.VSHRN(I_32, D0, Q0, 16);
RET(CheckLast(emitter, "f2900810 VSHRN.i32 d0, q0, #16")); RET(CheckLast(emitter, "f2900810 VSHRN.i32 d0, q0, #16"));
emitter.VSHRN(I_64, D1, Q2, 24); emitter.VSHRN(I_64, D1, Q2, 24);
@ -53,7 +63,7 @@ bool TestArmEmitter() {
emitter.VSHL(I_8, D1, D2, 7); emitter.VSHL(I_8, D1, D2, 7);
RET(CheckLast(emitter, "f28f1512 VSHL.i8 d1, d2, #7")); RET(CheckLast(emitter, "f28f1512 VSHL.i8 d1, d2, #7"));
emitter.VSHLL(I_32, Q1, D2, 17); emitter.VSHLL(I_32, Q1, D2, 17);
RET(CheckLast(emitter, "f2b12a12 VSHLL.i32 q1, d2, #17")); RET(CheckLast(emitter, "f2b12a12 VSHLL.s32 q1, d2, #17"));
emitter.LDR(R3, R7); emitter.LDR(R3, R7);
RET(CheckLast(emitter, "e5973000 LDR r3, [r7, #0]")); RET(CheckLast(emitter, "e5973000 LDR r3, [r7, #0]"));
emitter.VLDR(S3, R8, 48); emitter.VLDR(S3, R8, 48);