ARM64 emitter: Default to non-extend instruction forms (LSL 0), fix bugs. also fixes to disasm.

This commit is contained in:
Henrik Rydgard 2015-03-18 16:02:25 +01:00
parent d3669daba4
commit 70f44c3894
3 changed files with 59 additions and 41 deletions

View file

@ -496,7 +496,7 @@ void ARM64XEmitter::EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, A
Rn = DecodeReg(Rn);
Rm = DecodeReg(Rm);
Write32((b64Bit << 31) | (flags << 29) | (ArithEnc[instenc] << 21) | \
(Option.GetType() == ArithOption::TYPE_EXTENDEDREG ? 1 << 21 : 0) | (Rm << 16) | Option.GetData() | (Rn << 5) | Rd);
(Option.GetType() == ArithOption::TYPE_EXTENDEDREG ? (1 << 21) : 0) | (Rm << 16) | Option.GetData() | (Rn << 5) | Rd);
}
void ARM64XEmitter::EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
@ -589,7 +589,7 @@ void ARM64XEmitter::EncodeLogicalInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM
Rd = DecodeReg(Rd);
Rm = DecodeReg(Rm);
Rn = DecodeReg(Rn);
Write32((b64Bit << 31) | (LogicalEnc[instenc][0] << 29) | (0x50 << 21) | (LogicalEnc[instenc][1] << 21) | \
Write32((b64Bit << 31) | (LogicalEnc[instenc][0] << 29) | (0x5 << 25) | (LogicalEnc[instenc][1] << 21) | \
Shift.GetData() | (Rm << 16) | (Rn << 5) | Rd);
}
@ -1103,7 +1103,7 @@ void ARM64XEmitter::ISB(BarrierType type)
// Add/Subtract (extended register)
void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
ADD(Rd, Rn, Rm, ArithOption(Rd));
ADD(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0));
}
void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option)
@ -1113,7 +1113,7 @@ void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Optio
void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
EncodeArithmeticInst(0, true, Rd, Rn, Rm, ArithOption(Rd));
EncodeArithmeticInst(0, true, Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0));
}
void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option)
@ -1123,7 +1123,7 @@ void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Opti
void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
SUB(Rd, Rn, Rm, ArithOption(Rd));
SUB(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0));
}
void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option)
@ -1133,7 +1133,7 @@ void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Optio
void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
EncodeArithmeticInst(1, false, Rd, Rn, Rm, ArithOption(Rd));
EncodeArithmeticInst(1, true, Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0));
}
void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option)
@ -1143,22 +1143,22 @@ void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Opti
void ARM64XEmitter::CMN(ARM64Reg Rn, ARM64Reg Rm)
{
CMN(Rn, Rm, ArithOption(Rn));
CMN(Rn, Rm, ArithOption(Rn, ST_LSL, 0));
}
void ARM64XEmitter::CMN(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option)
{
EncodeArithmeticInst(0, true, SP, Rn, Rm, Option);
EncodeArithmeticInst(0, true, Is64Bit(Rn) ? ZR : WZR, Rn, Rm, Option);
}
void ARM64XEmitter::CMP(ARM64Reg Rn, ARM64Reg Rm)
{
CMP(Rn, Rm, ArithOption(Rn));
CMP(Rn, Rm, ArithOption(Rn, ST_LSL, 0));
}
void ARM64XEmitter::CMP(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option)
{
EncodeArithmeticInst(1, true, SP, Rn, Rm, Option);
EncodeArithmeticInst(1, true, Is64Bit(Rn) ? ZR : WZR, Rn, Rm, Option);
}
// Add/Subtract (with carry)

View file

@ -133,14 +133,6 @@ enum ShiftAmount
SHIFT_48 = 3,
};
enum ExtendType
{
EXTEND_UXTW = 2,
EXTEND_LSL = 3, // Default for zero shift amount
EXTEND_SXTW = 6,
EXTEND_SXTX = 7,
};
// The only system registers accessible from EL0 (user space)
enum SystemRegister { // Three digits : Op1, CRm, Op2
SYSREG_NZCV = 0x320,
@ -272,6 +264,7 @@ public:
m_width = WIDTH_32BIT;
m_extend = EXTEND_UXTW;
}
m_shifttype = ST_LSL;
}
ArithOption(ARM64Reg Rd, ShiftType shift_type, u32 shift)
{
@ -532,14 +525,14 @@ public:
void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift);
// Wrap the above for saner syntax
void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { AND(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BIC(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORR(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORN(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EOR(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EON(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ANDS(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BICS(Rd, Rn, Rm, ArithOption(Rd, 0)); }
void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { AND(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BIC(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORR(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORN(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EOR(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EON(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ANDS(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BICS(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); }
// Convenience wrappers around ORR. These match the official convenience syntax.
void MOV(ARM64Reg Rd, ARM64Reg Rm);

View file

@ -33,6 +33,9 @@ struct Instruction {
bool oddbits;
};
static const char * const shiftnames[4] = { "lsl", "lsr", "asr", "ror" };
static const char * const extendnames[8] = { "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx" };
int SignExtend26(int x) {
return (x & 0x02000000) ? (0xFC000000 | x) : (x & 0x3FFFFFF);
}
@ -58,14 +61,14 @@ int HighestSetBit(int value) {
return highest;
}
uint64_t Ones(int len) {
static uint64_t Ones(int len) {
if (len == 0x40) {
return 0xFFFFFFFFFFFFFFFF;
}
return (1ULL << len) - 1;
}
uint64_t Replicate(uint64_t value, int esize) {
static uint64_t Replicate(uint64_t value, int esize) {
uint64_t out = 0;
value &= Ones(esize);
for (int i = 0; i < 64; i += esize) {
@ -74,7 +77,7 @@ uint64_t Replicate(uint64_t value, int esize) {
return out;
}
uint64_t ROR(uint64_t value, int amount, int esize) {
static uint64_t ROR(uint64_t value, int amount, int esize) {
uint64_t rotated = (value >> amount) | (value << (esize - amount));
return rotated & Ones(esize);
}
@ -144,8 +147,9 @@ static void DataProcessingImmediate(uint32_t w, uint64_t addr, Instruction *inst
int op = (w >> 30) & 1;
int imm = ((w >> 10) & 0xFFF);
int shift = ((w >> 22) & 0x3) * 16;
const char *s = ((w >> 29) & 1) ? "s" : "";
imm <<= shift;
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, #%d", op == 0 ? "add" : "sub", r, Rd, r, Rn, imm);
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, #%d", op == 0 ? "add" : "sub", s, r, Rd, r, Rn, imm);
} else if (((w >> 23) & 0x3f) == 0x24) {
int immr = (w >> 16) & 0x3f;
int imms = (w >> 10) & 0x3f;
@ -249,16 +253,7 @@ static void DataProcessingRegister(uint32_t w, uint64_t addr, Instruction *instr
int Rm = (w >> 16) & 0x1F;
char r = ((w >> 31) & 1) ? 'x' : 'w';
if (((w >> 21) & 0xF) == 9) {
bool S = (w >> 29) & 1;
bool sub = (w >> 30) & 1;
if (Rd == 31 && S) {
// It's a CMP
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d", "cmp", S ? "s" : "", r, Rn, r, Rm);
} else {
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, %c%d", sub ? "sub" : "add", S ? "s" : "", r, Rd, r, Rn, r, Rm);
}
} else if (((w >> 21) & 0x2FF) == 0x2D6) {
if (((w >> 21) & 0x2FF) == 0x2D6) {
// Data processing
int opcode2 = (w >> 16) & 0x1F;
if (opcode2 == 0) {
@ -281,12 +276,42 @@ static void DataProcessingRegister(uint32_t w, uint64_t addr, Instruction *instr
if (opc == 2 && Rn == 31) {
// Special case for MOV (which is constructed from an ORR)
snprintf(instr->text, sizeof(instr->text), "mov %c%d, %c%d", r, Rd, r, Rm);
} else if (imm6 == 0) {
} else if (imm6 == 0 && shift == 0) {
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opnames[opc], r, Rd, r, Rn, r, Rm);
} else {
snprintf(instr->text, sizeof(instr->text), "(logical-shifted-register %08x", w);
}
} else if (((w >> 24) & 0x1f) == 0xB) {
// Arithmetic (shifted register)
bool S = (w >> 29) & 1;
int shift = (w >> 22) & 0x3;
int imm6 = (w >> 10) & 0x3f;
int opc = ((w >> 29) & 3);
const char *opnames[8] = { "add", "adds", "sub", "subs"};
if (imm6 == 0 && shift == 0) {
if (Rd == 31 && opc == 3) {
// It's a CMP
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d", "cmp", r, Rn, r, Rm);
} else {
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opnames[opc], r, Rd, r, Rn, r, Rm);
}
} else {
snprintf(instr->text, sizeof(instr->text), "(logical-shifted-register %08x", w);
}
} else if (((w >> 21) & 0xF) == 9) {
// Add/sub (extended register)
bool S = (w >> 29) & 1;
bool sub = (w >> 30) & 1;
int option = (w >> 13) & 0x7;
int imm3 = (w >> 10) & 0x7;
if (Rd == 31 && sub && S) {
// It's a CMP
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, %s", "cmp", S ? "s" : "", r, Rn, r, Rm, extendnames[option]);
} else {
snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, %c%d, %s", sub ? "sub" : "add", S ? "s" : "", r, Rd, r, Rn, r, Rm, extendnames[option]);
}
} else {
// Logical (extended register)
snprintf(instr->text, sizeof(instr->text), "(DPR %08x)", w);
}
}