diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index 5c6f94ad56..dcfbc4e59b 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -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) { diff --git a/Common/Arm64Emitter.h b/Common/Arm64Emitter.h index db2502c502..d3d2a118a9 100644 --- a/Common/Arm64Emitter.h +++ b/Common/Arm64Emitter.h @@ -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); diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index 0ba712860c..11d0d21b18 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -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) { diff --git a/unittest/TestArm64Emitter.cpp b/unittest/TestArm64Emitter.cpp index 90db15c37d..a36fd66ab0 100644 --- a/unittest/TestArm64Emitter.cpp +++ b/unittest/TestArm64Emitter.cpp @@ -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);