ARM64: More emitter/disasm

This commit is contained in:
Henrik Rydgård 2015-04-05 22:40:05 +02:00 committed by Henrik Rydgard
parent 459ba28655
commit 39be916d8a
4 changed files with 77 additions and 14 deletions

View File

@ -2074,7 +2074,7 @@ void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type,
if (type == INDEX_UNSIGNED)
{
_assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size!", __FUNCTION__);
_assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", __FUNCTION__, imm, m_emit->GetCodePtr());
_assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", __FUNCTION__);
if (size == 16)
imm >>= 1;
@ -2301,7 +2301,6 @@ void ARM64FloatEmitter::EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64R
void ARM64FloatEmitter::EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn)
{
_assert_msg_(DYNA_REC, immh, "%s bad encoding! Can't have zero immh", __FUNCTION__);
Rd = DecodeReg(Rd);
@ -2310,6 +2309,14 @@ void ARM64FloatEmitter::EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opc
Write32((Q << 30) | (U << 29) | (0xF << 24) | (immh << 19) | (immb << 16) | \
(opcode << 11) | (1 << 10) | (Rn << 5) | Rd);
}
void ARM64FloatEmitter::EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) {
Rd = DecodeReg(Rd);
Rn = DecodeReg(Rn);
Write32((2 << 30) | (U << 29) | (0x3E << 23) | (immh << 19) | (immb << 16) | (opcode << 11) | (1 << 10) | (Rn << 5) | Rd);
}
void ARM64FloatEmitter::EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn)
{
bool quad = IsQuad(Rt);
@ -2911,6 +2918,16 @@ void ARM64FloatEmitter::UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn)
{
Emit2RegMisc(IsQuad(Rd), 1, size >> 6, 0x1D, Rd, Rn);
}
void ARM64FloatEmitter::SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale)
{
int imm = size * 2 - scale;
EmitShiftImm(IsQuad(Rd), 0, imm >> 3, imm & 7, 0x1C, Rd, Rn);
}
void ARM64FloatEmitter::UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale)
{
int imm = size * 2 - scale;
EmitShiftImm(IsQuad(Rd), 1, imm >> 3, imm & 7, 0x1C, Rd, Rn);
}
void ARM64FloatEmitter::XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn)
{

View File

@ -101,6 +101,7 @@ int CountLeadingZeros(uint64_t value, int width);
inline ARM64Reg DecodeReg(ARM64Reg reg) { return (ARM64Reg)(reg & 0x1F); }
inline ARM64Reg EncodeRegTo64(ARM64Reg reg) { return (ARM64Reg)(reg | 0x20); }
inline ARM64Reg EncodeRegToSingle(ARM64Reg reg) { return (ARM64Reg)(DecodeReg(reg) + S0); }
inline ARM64Reg EncodeRegToDouble(ARM64Reg reg) { return (ARM64Reg)((reg & ~0xC0) | 0x80); }
inline ARM64Reg EncodeRegToQuad(ARM64Reg reg) { return (ARM64Reg)(reg | 0xC0); }
@ -823,6 +824,8 @@ public:
void REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn);
void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn);
void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn);
void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale);
void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale);
void XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn);
// Move
@ -915,6 +918,7 @@ private:
void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64Reg Rd, u32 imm8);
void EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn);
void EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);

View File

@ -249,17 +249,18 @@ static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) {
bool index_unsigned = ((w >> 24) & 3) == 1;
bool index_post = !index_unsigned && ((w >> 10) & 3) == 1;
bool index_pre = !index_unsigned && ((w >> 10) & 3) == 3;
int imm12 = SignExtend12((w >> 10) & 0xFFF) << size;
if (V == 0) {
const char *signExt = ((opc & 0x2) && size < 3) ? "s" : "";
int imm12 = SignExtend12((w >> 10) & 0xFFF) << size;
// Integer type
if (index_unsigned) {
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, [x%d, #%d]", opname[opc], sizeSuffix[size], r, Rt, Rn, imm12);
snprintf(instr->text, sizeof(instr->text), "%s%s%s %c%d, [x%d, #%d]", opname[opc], signExt, sizeSuffix[size], r, Rt, Rn, imm12);
return;
} else if (index_post) {
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, [x%d], #%d", opname[opc], sizeSuffix[size], r, Rt, Rn, SignExtend9(imm9));
snprintf(instr->text, sizeof(instr->text), "%s%s%s %c%d, [x%d], #%d", opname[opc], signExt, sizeSuffix[size], r, Rt, Rn, SignExtend9(imm9));
return;
} else if (index_pre) {
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, [x%d, #%d]!", opname[opc], sizeSuffix[size], r, Rt, Rn, SignExtend9(imm9));
snprintf(instr->text, sizeof(instr->text), "%s%s%s %c%d, [x%d, #%d]!", opname[opc], signExt, sizeSuffix[size], r, Rt, Rn, SignExtend9(imm9));
return;
} else {
// register offset
@ -271,15 +272,20 @@ static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) {
}
} else {
// FP/Vector type
char vr = '!';
if (opc == 3 && size == 0) {
vr = 'q';
} else {
vr = "bhsd"[size];
if ((opc & 2) && size == 0) {
size = 4;
}
char vr = "bhsdq"[size];
int imm12 = SignExtend12((w >> 10) & 0xFFF) << size;
if (index_unsigned) {
snprintf(instr->text, sizeof(instr->text), "%s %c%d, [x%d, #%d]", opname[opc], vr, Rt, Rn, imm12);
return;
} else if (index_post) {
snprintf(instr->text, sizeof(instr->text), "%s %c%d, [x%d], #%d", opname[opc], vr, Rt, Rn, SignExtend9(imm9));
return;
} else if (index_pre) {
snprintf(instr->text, sizeof(instr->text), "%s %c%d, [x%d, #%d]!", opname[opc], vr, Rt, Rn, SignExtend9(imm9));
return;
} else {
snprintf(instr->text, sizeof(instr->text), "(loadstore-fp-vector %08x)", w);
return;
@ -614,7 +620,12 @@ static void FPandASIMD1(uint32_t w, uint64_t addr, Instruction *instr) {
};
const char *opname = U ? opnamesU1[opcode] : opnamesU0[opcode];
const char *two = Q ? "2" : ""; // TODO: This doesn't apply to all the ops
if (opname) {
if (opname && (!strcmp(opname, "scvtf") || !strcmp(opname, "ucvtf"))) {
int esize = (8 << HighestSetBit(immh));
int shift = 2 * esize - ((immh << 3) | immb);
int r = Q ? 'q' : 'd';
snprintf(instr->text, sizeof(instr->text), "%ccvtf %c%d.s, %c%d.s, #%d", U ? 'u' : 's', r, Rd, r, Rn, shift);
} else if (opname) {
int esize = (8 << HighestSetBit(immh));
int shift = ((immh << 3) | immb) - esize;
if (shift == 0 && opcode == 0x14) {

View File

@ -39,6 +39,15 @@ bool TestArm64Emitter() {
ARM64XEmitter emitter((u8 *)code);
ARM64FloatEmitter fp(&emitter);
emitter.LDRH(INDEX_UNSIGNED, W3, X7, 18);
RET(CheckLast(emitter, "794024e3 ldrh w3, [x7, #18]"));
emitter.LDRSH(INDEX_UNSIGNED, W3, X7, 18);
RET(CheckLast(emitter, "79c024e3 ldrsh w3, [x7, #18]"));
fp.SCVTF(32, Q3, Q7, 7);
RET(CheckLast(emitter, "4f39e4e3 scvtf q3.s, q7.s, #7"));
fp.UCVTF(32, D3, D7, 15);
RET(CheckLast(emitter, "2f31e4e3 ucvtf d3.s, d7.s, #15"));
fp.LDP(INDEX_SIGNED, Q3, Q7, X3, 32);
RET(CheckLast(emitter, "ad411c63 ldp q3, q7, [x3, #32]"));
fp.STP(INDEX_SIGNED, Q3, Q7, X3, 32);
@ -48,8 +57,30 @@ bool TestArm64Emitter() {
RET(CheckLast(emitter, "4e1c07c1 dup q1, q30.s[3]"));
fp.UXTL(8, Q1, D8);
RET(CheckLast(emitter, "2f08a501 uxtl.16.8 q1, d8"));
fp.LDR(16, INDEX_UNSIGNED, Q1, X1, 64);
RET(CheckLast(emitter, "7d408021 ldr h1, [x1, #64]"));
fp.LDR(8, INDEX_PRE, Q1, X1, 96);
RET(CheckLast(emitter, "3c460c21 ldr b1, [x1, #96]!"));
fp.LDR(8, INDEX_POST, Q1, X1, 96);
RET(CheckLast(emitter, "3c460421 ldr b1, [x1], #96"));
fp.LDR(8, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "3d418021 ldr b1, [x1, #96]"));
fp.LDR(16, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "7d40c021 ldr h1, [x1, #96]"));
fp.LDR(32, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "bd406021 ldr s1, [x1, #96]"));
fp.LDR(64, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "fd403021 ldr d1, [x1, #96]"));
fp.LDR(128, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "3dc01821 ldr q1, [x1, #96]"));
fp.STR(8, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "3d018021 str b1, [x1, #96]"));
fp.STR(16, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "7d00c021 str h1, [x1, #96]"));
fp.STR(32, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "bd006021 str s1, [x1, #96]"));
fp.STR(64, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "fd003021 str d1, [x1, #96]"));
fp.STR(128, INDEX_UNSIGNED, Q1, X1, 96);
RET(CheckLast(emitter, "3d801821 str q1, [x1, #96]"));
fp.FMLA(32, D1, D2, D3);
RET(CheckLast(emitter, "0e23cc41 fmla.32 d1, d2, d3"));
fp.FMLS(64, Q1, Q2, Q3);