mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-13 10:24:39 +00:00
ARM64: More emitter/disasm
This commit is contained in:
parent
459ba28655
commit
39be916d8a
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user