mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
ARM64: Guess what? more emitter & disasm
This commit is contained in:
parent
1e9fdf08c5
commit
5a5f3c94fd
4 changed files with 122 additions and 53 deletions
|
@ -1485,6 +1485,14 @@ void ARM64XEmitter::UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms)
|
|||
{
|
||||
EncodeBitfieldMOVInst(2, Rd, Rn, immr, imms);
|
||||
}
|
||||
void ARM64XEmitter::EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift) {
|
||||
bool sf = Is64Bit(Rd);
|
||||
bool N = sf;
|
||||
Rd = DecodeReg(Rd);
|
||||
Rn = DecodeReg(Rn);
|
||||
Rm = DecodeReg(Rm);
|
||||
Write32((sf << 31) | (0x27 << 23) | (N << 22) | (Rm << 16) | (shift << 10) | (Rm << 5) | Rd);
|
||||
}
|
||||
void ARM64XEmitter::SXTB(ARM64Reg Rd, ARM64Reg Rn)
|
||||
{
|
||||
SBFM(Rd, Rn, 0, 7);
|
||||
|
@ -1496,7 +1504,6 @@ void ARM64XEmitter::SXTH(ARM64Reg Rd, ARM64Reg Rn)
|
|||
void ARM64XEmitter::SXTW(ARM64Reg Rd, ARM64Reg Rn)
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Is64Bit(Rd), "%s requires 64bit register as destination", __FUNCTION__);
|
||||
|
||||
SBFM(Rd, Rn, 0, 31);
|
||||
}
|
||||
void ARM64XEmitter::UXTB(ARM64Reg Rd, ARM64Reg Rn)
|
||||
|
@ -1817,8 +1824,8 @@ void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize)
|
|||
|
||||
if (!imm)
|
||||
{
|
||||
// Zero immediate, just clear the register
|
||||
EOR(Rd, Rd, Rd, ArithOption(Rd, ST_LSL, 0));
|
||||
// Zero immediate, just clear the register. EOR is pointless when we have MOVZ, which looks clearer in disasm too.
|
||||
MOVZ(Rd, 0, SHIFT_0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2638,10 +2645,30 @@ void ARM64FloatEmitter::ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn)
|
|||
}
|
||||
|
||||
// Scalar - 1 Source
|
||||
void ARM64FloatEmitter::FMOV(ARM64Reg Rd, ARM64Reg Rn)
|
||||
void ARM64FloatEmitter::FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top)
|
||||
{
|
||||
EmitScalar1Source(0, 0, IsDouble(Rd), 0, Rd, Rn);
|
||||
if (IsScalar(Rd) && IsScalar(Rn)) {
|
||||
EmitScalar1Source(0, 0, IsDouble(Rd), 0, Rd, Rn);
|
||||
} else {
|
||||
int type = 0;
|
||||
int rmode = 0;
|
||||
int opcode = 6;
|
||||
int sf = 0;
|
||||
if (IsSingle(Rd) && !Is64Bit(Rn) && !top) {
|
||||
// GPR to scalar single
|
||||
opcode |= 1;
|
||||
} else if (!Is64Bit(Rd) && IsSingle(Rn) && !top) {
|
||||
// Scalar single to GPR - defaults are correct
|
||||
} else {
|
||||
// TODO
|
||||
_assert_msg_(JIT, 0, "FMOV: Unhandled case");
|
||||
}
|
||||
Rd = DecodeReg(Rd);
|
||||
Rn = DecodeReg(Rn);
|
||||
Write32((sf << 31) | (0x1e2 << 20) | (rmode << 19) | (opcode << 16) | (Rn << 5) | Rd);
|
||||
}
|
||||
}
|
||||
|
||||
void ARM64FloatEmitter::FABS(ARM64Reg Rd, ARM64Reg Rn)
|
||||
{
|
||||
EmitScalar1Source(0, 0, IsDouble(Rd), 1, Rd, Rn);
|
||||
|
@ -2949,41 +2976,41 @@ void ARM64FloatEmitter::FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn)
|
|||
Emit1Source(0, 0, src_encoding, 4 | dst_encoding, Rd, Rn);
|
||||
}
|
||||
|
||||
// Conversion between float and integer
|
||||
void ARM64FloatEmitter::FMOV(u8 size, bool top, ARM64Reg Rd, ARM64Reg Rn)
|
||||
{
|
||||
bool sf = size == 64 ? true : false;
|
||||
u32 type = 0;
|
||||
u32 rmode = top ? 1 : 0;
|
||||
if (size == 64)
|
||||
{
|
||||
if (top)
|
||||
type = 2;
|
||||
else
|
||||
type = 1;
|
||||
}
|
||||
|
||||
EmitConversion(sf, 0, type, rmode, IsVector(Rd) ? 7 : 6, Rd, Rn);
|
||||
}
|
||||
|
||||
void ARM64FloatEmitter::SCVTF(ARM64Reg Rd, ARM64Reg Rn)
|
||||
{
|
||||
bool sf = Is64Bit(Rn);
|
||||
u32 type = 0;
|
||||
if (IsDouble(Rd))
|
||||
type = 1;
|
||||
|
||||
EmitConversion(sf, 0, type, 0, 2, Rd, Rn);
|
||||
if (IsScalar(Rn)) {
|
||||
// Source is in FP register (like destination!). We must use a vector encoding.
|
||||
bool sign = false;
|
||||
Rd = DecodeReg(Rd);
|
||||
Rn = DecodeReg(Rn);
|
||||
int sz = IsDouble(Rn);
|
||||
Write32((0x5e << 24) | (sign << 29) | (sz << 22) | (0x876 << 10) | (Rn << 5) | Rd);
|
||||
} else {
|
||||
bool sf = Is64Bit(Rn);
|
||||
u32 type = 0;
|
||||
if (IsDouble(Rd))
|
||||
type = 1;
|
||||
EmitConversion(sf, 0, type, 0, 2, Rd, Rn);
|
||||
}
|
||||
}
|
||||
|
||||
void ARM64FloatEmitter::UCVTF(ARM64Reg Rd, ARM64Reg Rn)
|
||||
{
|
||||
bool sf = Is64Bit(Rn);
|
||||
u32 type = 0;
|
||||
if (IsDouble(Rd))
|
||||
type = 1;
|
||||
if (IsScalar(Rn)) {
|
||||
// Source is in FP register (like destination!). We must use a vector encoding.
|
||||
bool sign = true;
|
||||
Rd = DecodeReg(Rd);
|
||||
Rn = DecodeReg(Rn);
|
||||
int sz = IsDouble(Rn);
|
||||
Write32((0x5e << 24) | (sign << 29) | (sz << 22) | (0x876 << 10) | (Rn << 5) | Rd);
|
||||
} else {
|
||||
bool sf = Is64Bit(Rn);
|
||||
u32 type = 0;
|
||||
if (IsDouble(Rd))
|
||||
type = 1;
|
||||
|
||||
EmitConversion(sf, 0, type, 0, 3, Rd, Rn);
|
||||
EmitConversion(sf, 0, type, 0, 3, Rd, Rn);
|
||||
}
|
||||
}
|
||||
|
||||
void ARM64FloatEmitter::SCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale)
|
||||
|
|
|
@ -548,6 +548,8 @@ public:
|
|||
void MOV(ARM64Reg Rd, ARM64Reg Rm, ArithOption Shift);
|
||||
void MOV(ARM64Reg Rd, ARM64Reg Rm);
|
||||
void MVN(ARM64Reg Rd, ARM64Reg Rm);
|
||||
|
||||
// TODO: These are "slow" as they use arith+shift, should be replaced with UBFM/EXTR variants.
|
||||
void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
void LSL(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
void ASR(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
|
@ -576,12 +578,21 @@ public:
|
|||
void BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||
void SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||
void UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||
|
||||
// Extract register (ROR with two inputs, if same then faster on A67)
|
||||
void EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift);
|
||||
|
||||
// Aliases
|
||||
void SXTB(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void SXTH(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void SXTW(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UXTB(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UXTH(ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
void UBFX(ARM64Reg Rd, ARM64Reg Rn, int lsb, int width) {
|
||||
UBFM(Rd, Rn, lsb, lsb + width <= (Is64Bit(Rn) ? 64 : 32));
|
||||
}
|
||||
|
||||
// Load Register (Literal)
|
||||
void LDR(ARM64Reg Rt, u32 imm);
|
||||
void LDRSW(ARM64Reg Rt, u32 imm);
|
||||
|
@ -743,10 +754,10 @@ public:
|
|||
void ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn);
|
||||
|
||||
// Scalar - 1 Source
|
||||
void FMOV(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FABS(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FNEG(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FSQRT(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP
|
||||
|
||||
// Scalar - 2 Source
|
||||
void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
|
@ -791,9 +802,6 @@ public:
|
|||
// One source
|
||||
void FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// Conversion or movement between float and integer
|
||||
void FMOV(u8 size, bool top, ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// Scalar convert float to int, in a lot of variants.
|
||||
// Note that the scalar version of this operation has two encodings, one that goes to an integer register
|
||||
// and one that outputs to a scalar fp register.
|
||||
|
|
|
@ -169,6 +169,13 @@ static void DataProcessingImmediate(uint32_t w, uint64_t addr, Instruction *inst
|
|||
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, #0x%x%08x", opname[opc], r, Rd, r, Rn, (wmask >> 32), (wmask & 0xFFFFFFFF));
|
||||
else
|
||||
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, #0x%x", opname[opc], r, Rd, r, Rn, (uint32_t)wmask);
|
||||
} else if (((w >> 23) & 0x3f) == 0x26) {
|
||||
int N = (w >> 22) & 1;
|
||||
int opc = (w >> 29) & 3;
|
||||
int immr = (w >> 16) & 0x3f;
|
||||
int imms = (w >> 10) & 0x3f;
|
||||
const char *opname[4] = { "sbfm", "bfm", "ubfm" };
|
||||
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, #%d, #%d", opname[opc], r, Rd, r, Rn, immr, imms);
|
||||
} else {
|
||||
snprintf(instr->text, sizeof(instr->text), "(DPI %08x)", w);
|
||||
}
|
||||
|
@ -458,6 +465,7 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) {
|
|||
snprintf(instr->text, sizeof(instr->text), "(float<->fixed %08x)", w);
|
||||
}
|
||||
} else if (((w >> 21) & 0x2F9) == 0xF1) {
|
||||
int opcode = (w >> 16) & 7;
|
||||
if (((w >> 10) & 3) == 0) {
|
||||
if (((w >> 10) & 7) == 4) {
|
||||
snprintf(instr->text, sizeof(instr->text), "(float imm %08x)", w);
|
||||
|
@ -476,14 +484,28 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) {
|
|||
const char *opnames[4] = { "fmov", "fabs", "fneg", "fsqrt" };
|
||||
int opc = (w >> 15) & 0x3;
|
||||
snprintf(instr->text, sizeof(instr->text), "%s s%d, s%d", opnames[opc], Rd, Rn); // TODO: Support doubles too
|
||||
} else if (((w >> 10) & 0x3f) == 0x0) {
|
||||
} else if (((w >> 10) & 0x1bf) == 0x180) {
|
||||
// Generalized FMOV
|
||||
char ir = sf ? 'x' : 'w';
|
||||
bool tosimd = (opcode & 0x1);
|
||||
char fr = ((w >> 22) & 1) ? 'd' : 's';
|
||||
if (tosimd) {
|
||||
snprintf(instr->text, sizeof(instr->text), "fmov %c%d, %c%d", fr, Rd, ir, Rn);
|
||||
} else {
|
||||
snprintf(instr->text, sizeof(instr->text), "fmov %c%d, %c%d", ir, Rd, fr, Rn);
|
||||
}
|
||||
} else if (((w >> 10) & 0x3f) == 0x0 && opcode == 0) {
|
||||
char ir = sf ? 'x' : 'w';
|
||||
char roundmode = "npmz"[(w >> 19) & 3];
|
||||
int opcode = (w >> 16) & 7;
|
||||
if (opcode & 0x4)
|
||||
roundmode = 'a';
|
||||
char fr = ((w >> 22) & 1) ? 'd' : 's';
|
||||
snprintf(instr->text, sizeof(instr->text), "fcvt%cs %c%d, %c%d", roundmode, ir, Rd, fr, Rn);
|
||||
} else if ((opcode & 6) == 2) {
|
||||
char ir = sf ? 'x' : 'w';
|
||||
char fr = ((w >> 22) & 1) ? 'd' : 's';
|
||||
char sign = (opcode & 1) ? 'u' : 's';
|
||||
snprintf(instr->text, sizeof(instr->text), "%ccvtf %c%d, %c%d", sign, fr, Rd, ir, Rn);
|
||||
}
|
||||
} else if (((w >> 10) & 3) == 1) {
|
||||
snprintf(instr->text, sizeof(instr->text), "(float cond compare %08x)", w);
|
||||
|
@ -567,8 +589,10 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) {
|
|||
} else if (sign_prefix) {
|
||||
char sign = U ? 'u' : 's';
|
||||
snprintf(instr->text, sizeof(instr->text), "%c%s %c%d, %c%d", sign, opname, r, Rd, r, Rn);
|
||||
} else {
|
||||
snprintf(instr->text, sizeof(instr->text), "%s (asimd scalar two-reg misc %08x)", opname, w);
|
||||
} else if (!zero) {
|
||||
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d", opname, r, Rd, r, Rn);
|
||||
} else if (zero) {
|
||||
snprintf(instr->text, sizeof(instr->text), "%s %c%d, #0.0", opname, r, Rd);
|
||||
}
|
||||
} else {
|
||||
snprintf(instr->text, sizeof(instr->text), "(asimd scalar two-reg misc %08x)", w);
|
||||
|
|
|
@ -35,10 +35,19 @@ bool TestArm64Emitter() {
|
|||
u32 code[512];
|
||||
ARM64XEmitter emitter((u8 *)code);
|
||||
ARM64FloatEmitter fp(&emitter);
|
||||
//fp.FMOV(32, false, S1, X3);
|
||||
//RET(CheckLast(emitter, "aa023be1 fmov s1, w3"));
|
||||
//fp.FMOV(32, false, X1, S3);
|
||||
//RET(CheckLast(emitter, "aa023be1 fmov x1, s3"));
|
||||
|
||||
//emitter.EXTR(W1, W3, 0, 7);
|
||||
//RET(CheckLast(emitter, "53033061 extr w1, w3, w7"));
|
||||
fp.SCVTF(S13, W7);
|
||||
RET(CheckLast(emitter, "1e2200ed scvtf s13, w7"));
|
||||
emitter.UBFM(W1, W3, 0, 7);
|
||||
RET(CheckLast(emitter, "53001c61 ubfm w1, w3, #0, #7"));
|
||||
fp.FMOV(W1, S3);
|
||||
RET(CheckLast(emitter, "1e260061 fmov w1, s3"));
|
||||
fp.FMOV(S1, W3);
|
||||
RET(CheckLast(emitter, "1e270061 fmov s1, w3"));
|
||||
fp.SCVTF(S13, S12);
|
||||
RET(CheckLast(emitter, "5e21d98d scvtf s13, s12"));
|
||||
fp.FCVTS(S13, S12, ROUND_N);
|
||||
RET(CheckLast(emitter, "5e21a98d fcvtns s13, s12"));
|
||||
fp.FCVTS(D13, D12, ROUND_P);
|
||||
|
@ -46,13 +55,15 @@ bool TestArm64Emitter() {
|
|||
fp.FCVTS(W13, S12, ROUND_N);
|
||||
RET(CheckLast(emitter, "1e20018d fcvtns w13, s12"));
|
||||
fp.FCVTS(S22, S12, ROUND_Z);
|
||||
RET(CheckLast(emitter, "9e03e06c fcvtzs s22, s12"));
|
||||
RET(CheckLast(emitter, "5ea1b996 fcvtzs s22, s12"));
|
||||
fp.FCVTS(X3, D2, ROUND_M);
|
||||
RET(CheckLast(emitter, "9e03e06c fcvtms x3, d2"));
|
||||
RET(CheckLast(emitter, "9e700043 fcvtms x3, d2"));
|
||||
fp.UCVTF(S12, X3, 8);
|
||||
RET(CheckLast(emitter, "9e03e06c ucvtf s12, x3"));
|
||||
//fp.FCVTZS(W12, S3, 12);
|
||||
//RET(CheckLast(emitter, "b86c6877 fcvtzs w12, s3, #12"));
|
||||
RET(CheckLast(emitter, "9e03e06c ucvtf s12, x3, #8"));
|
||||
fp.SCVTF(S12, W13, 12);
|
||||
RET(CheckLast(emitter, "1e02d1ac scvtf s12, w13, #12"));
|
||||
fp.FCVTS(W12, S3, ROUND_Z);
|
||||
RET(CheckLast(emitter, "1e38006c fcvtzs w12, s3"));
|
||||
emitter.LSLV(W1, W2, W3);
|
||||
RET(CheckLast(emitter, "1ac32041 lslv w1, w2, w3"));
|
||||
emitter.UDIV(W1, W2, W3);
|
||||
|
@ -103,7 +114,6 @@ bool TestArm64Emitter() {
|
|||
RET(CheckLast(emitter, "6a1e0041 ands w1, w2, w30"));
|
||||
emitter.ORR(X1, X2, X30);
|
||||
RET(CheckLast(emitter, "aa1e0041 orr x1, x2, x30"));
|
||||
|
||||
fp.FMUL(S0, S12, S22);
|
||||
RET(CheckLast(emitter, "1e360980 fmul s0, s12, s22"));
|
||||
emitter.ADD(X23, X30, 123, false);
|
||||
|
@ -119,9 +129,9 @@ bool TestArm64Emitter() {
|
|||
fp.FMOV(S20, S25);
|
||||
RET(CheckLast(emitter, "1e204334 fmov s20, s25"));
|
||||
fp.FCMP(S7);
|
||||
RET(CheckLast(emitter, "1e6320e0 fcmp s7, #0.0"));
|
||||
RET(CheckLast(emitter, "1e2020e8 fcmp s7, #0.0"));
|
||||
fp.FCMP(D7, D3);
|
||||
RET(CheckLast(emitter, "1e2020e8 fcmp d7, d3"));
|
||||
RET(CheckLast(emitter, "1e6320e0 fcmp d7, d3"));
|
||||
emitter.ORI2R(X1, X3, 0x3F, INVALID_REG);
|
||||
RET(CheckLast(emitter, "b2401461 orr x1, x3, #0x3f"));
|
||||
emitter.EORI2R(X1, X3, 0x3F0000003F0, INVALID_REG);
|
||||
|
|
Loading…
Add table
Reference in a new issue