diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index b6cf8a904d..992d445b0e 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -1820,6 +1820,11 @@ void ARM64XEmitter::ADRP(ARM64Reg Rd, s32 imm) EncodeAddressInst(1, Rd, imm >> 12); } +// LLVM is unhappy about the regular abs function, so here we go. +inline int64_t abs64(int64_t x) { + return x >= 0 ? x : -x; +} + // Wrapper around MOVZ+MOVK (and later MOVN) void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize) { @@ -1868,11 +1873,11 @@ void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize) u64 aligned_pc = (u64)GetCodePtr() & ~0xFFF; s64 aligned_offset = (s64)imm - (s64)aligned_pc; - if (upload_part.Count() > 1 && std::abs(aligned_offset) < 0xFFFFFFFFLL) + if (upload_part.Count() > 1 && abs64(aligned_offset) < 0xFFFFFFFFLL) { // Immediate we are loading is within 4GB of our aligned range // Most likely a address that we can load in one or two instructions - if (!(std::abs(aligned_offset) & 0xFFF)) + if (!(abs64(aligned_offset) & 0xFFF)) { // Aligned ADR ADRP(Rd, (s32)aligned_offset); diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index af9a9031f3..cbb4c2bd45 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -433,9 +433,82 @@ static void FPandASIMD1(uint32_t w, uint64_t addr, Instruction *instr) { int Rm = (w >> 16) & 0x1f; if (((w >> 21) & 0x4F9) == 0x71) { switch ((w >> 10) & 3) { - case 1: case 3: - snprintf(instr->text, sizeof(instr->text), "(asimd three-same %08x)", w); + case 1: case 3: { + int opcode = (w >> 11) & 0x1f; + int sz = (w >> 22) & 3; + int Q = GetQ(w); + int U = GetU(w); + const char *opnames000[32] = { + "shadd", "sqadd", "srhadd", 0, + "shsub", "sqsub", "cmgt", "cmge", + "sshl", "sqshl", "srshl", "sqrshl", + "smax", "smin", "sabd", "saba", + "add", "cmtst", "mla", "mul", + "smaxp", "sminp", "sqdmulh", "addp", + "fmaxnm", "fmla", "fadd", "fmulx", + "fcmeq", 0, "fmax", "frecps", + }; + const char *opnames100[32] = { + "uhadd", "uqadd", "urhadd", 0, + "uhsub", "uqsub", "cmhi", "cmhs", + "ushl", "uqshl", "urshl", "uqrshl", + "umax", "umin", "uabd", "uaba", + "sub", "cmeq", "mls", "pmul", + "umaxp", "uminp", "sqrdmulh", "addp", + "fmaxnmp", 0, "faddp", "fmul", + "fcmge", "facge", "fmaxp", "fdiv", + }; + const char *opnames010[8] = { + "fminm", "fmls", "fsub", 0, + 0, 0, "fmin", "frsqrts", + }; + const char *opnames110[8] = { + "fminnmp", 0, "fabd", 0, + "fcmgt", "facgt", "fminp", 0, + }; + char r = Q ? 'q' : 'd'; + const char *opname = nullptr; + bool fp = false; + if (U == 0) { + if (opcode < 0x18) { + opname = opnames000[opcode]; + } else if ((sz & 0x2) == 0) { + opname = opnames000[opcode]; + fp = true; + } else if ((sz & 0x2) == 2) { + opname = opnames010[opcode - 0x18]; + fp = true; + } + if (!opname && opcode == 3 && (sz & 2) == 0) { + opname = !(sz & 1) ? "and" : "bic"; + } else if (!opname && opcode == 3 && (sz & 2) == 2) { + opname = !(sz & 1) ? "orr" : "orn"; + } + } else if (U == 1) { + if (opcode < 0x18) { + opname = opnames100[opcode]; + } else if ((sz & 0x2) == 0) { + opname = opnames100[opcode]; + fp = true; + } else if ((sz & 0x2) == 2) { + opname = opnames110[opcode - 0x18]; + fp = true; + } + if (!opname && opcode == 3 && (sz & 2) == 0) { + opname = !(sz & 1) ? "eor" : "bsl"; + } else if (!opname && opcode == 3 && (sz & 2) == 2) { + opname = !(sz & 1) ? "bit" : "bif"; + } + } + + int size = (fp ? ((sz & 1) ? 64 : 32) : (sz << 3)); + if (opname != nullptr) { + snprintf(instr->text, sizeof(instr->text), "%s.%d %c%d, %c%d, %c%d", opname, size, r, Rd, r, Rn, r, Rm); + } else { + snprintf(instr->text, sizeof(instr->text), "(asimd three-same %08x)", w); + } break; + } case 0: snprintf(instr->text, sizeof(instr->text), "(asimd three-different %08x)", w); break; diff --git a/unittest/TestArm64Emitter.cpp b/unittest/TestArm64Emitter.cpp index 89c75aad6d..f72afabd1d 100644 --- a/unittest/TestArm64Emitter.cpp +++ b/unittest/TestArm64Emitter.cpp @@ -40,6 +40,10 @@ bool TestArm64Emitter() { ARM64FloatEmitter fp(&emitter); + fp.FADD(32, Q1, Q13, Q21); + RET(CheckLast(emitter, "4e35d5a1 fadd.32 q1, q13, q21")); + fp.FMUL(32, D1, D13, D21); + RET(CheckLast(emitter, "2e35dda1 fmul.32 d1, d13, d21")); fp.INS(32, Q3, 1, Q12, 3); RET(CheckLast(emitter, "6e0c6583 ins q3.d[1], q12.d[3]")); fp.INS(8, D4, 5, D11, 2);