switch (op) {
case Xalu_MOV: return "mov";
case Xalu_CMP: return "cmp";
- case Xalu_TEST: return "test";
case Xalu_ADD: return "add";
case Xalu_SUB: return "sub";
case Xalu_ADC: return "adc";
i->Xin.Alu32M.op = op;
i->Xin.Alu32M.src = src;
i->Xin.Alu32M.dst = dst;
+ vassert(op != Xalu_MUL);
+ return i;
+}
+X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Sh32;
+ i->Xin.Sh32.op = op;
+ i->Xin.Sh32.src = src;
+ i->Xin.Sh32.dst = dst;
+ return i;
+}
+X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Test32;
+ i->Xin.Test32.src = src;
+ i->Xin.Test32.dst = dst;
return i;
}
X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ) {
i->Xin.Div.src = src;
return i;
}
-X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
- X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
- i->tag = Xin_Sh32;
- i->Xin.Sh32.op = op;
- i->Xin.Sh32.src = src;
- i->Xin.Sh32.dst = dst;
- return i;
-}
X86Instr* X86Instr_Sh3232 ( X86ShiftOp op, UInt amt, HReg rHi, HReg rLo ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_Sh3232;
vex_printf(",");
ppX86AMode(i->Xin.Alu32M.dst);
return;
+ case Xin_Sh32:
+ vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
+ if (i->Xin.Sh32.src == 0)
+ vex_printf(" %%cl,");
+ else
+ vex_printf(" $%d,", i->Xin.Sh32.src);
+ ppX86RM(i->Xin.Sh32.dst);
+ return;
+ case Xin_Test32:
+ vex_printf("testl ");
+ ppX86RI(i->Xin.Test32.src);
+ vex_printf(",");
+ ppX86RM(i->Xin.Test32.dst);
+ return;
case Xin_Unary32:
vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op));
ppX86RM(i->Xin.Unary32.dst);
showX86ScalarSz(i->Xin.Div.ssz));
ppX86RM(i->Xin.Div.src);
return;
- case Xin_Sh32:
- vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
- if (i->Xin.Sh32.src == 0)
- vex_printf(" %%cl,");
- else
- vex_printf(" $%d,", i->Xin.Sh32.src);
- ppX86RM(i->Xin.Sh32.dst);
- return;
case Xin_Sh3232:
vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op));
if (i->Xin.Sh3232.amt == 0)
addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst);
return;
}
- if (i->Xin.Alu32R.op == Xalu_CMP
- || i->Xin.Alu32R.op == Xalu_TEST) {
+ if (i->Xin.Alu32R.op == Xalu_CMP) {
addHRegUse(u, HRmRead, i->Xin.Alu32R.dst);
return;
}
addRegUsage_X86RI(u, i->Xin.Alu32M.src);
addRegUsage_X86AMode(u, i->Xin.Alu32M.dst);
return;
+ case Xin_Sh32:
+ addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify);
+ if (i->Xin.Sh32.src == 0)
+ addHRegUse(u, HRmRead, hregX86_ECX());
+ return;
+ case Xin_Test32:
+ addRegUsage_X86RI(u, i->Xin.Test32.src);
+ addRegUsage_X86RM(u, i->Xin.Test32.dst, HRmRead);
+ return;
case Xin_Unary32:
addRegUsage_X86RM(u, i->Xin.Unary32.dst, HRmModify);
return;
addHRegUse(u, HRmModify, hregX86_EAX());
addHRegUse(u, HRmModify, hregX86_EDX());
return;
- case Xin_Sh32:
- addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify);
- if (i->Xin.Sh32.src == 0)
- addHRegUse(u, HRmRead, hregX86_ECX());
- return;
case Xin_Sh3232:
addHRegUse(u, HRmRead, i->Xin.Sh3232.rLo);
addHRegUse(u, HRmModify, i->Xin.Sh3232.rHi);
mapRegs_X86RI(m, i->Xin.Alu32M.src);
mapRegs_X86AMode(m, i->Xin.Alu32M.dst);
return;
+ case Xin_Sh32:
+ mapRegs_X86RM(m, i->Xin.Sh32.dst);
+ return;
+ case Xin_Test32:
+ mapRegs_X86RI(m, i->Xin.Test32.src);
+ mapRegs_X86RM(m, i->Xin.Test32.dst);
+ return;
case Xin_Unary32:
mapRegs_X86RM(m, i->Xin.Unary32.dst);
return;
case Xin_Div:
mapRegs_X86RM(m, i->Xin.Div.src);
return;
- case Xin_Sh32:
- mapRegs_X86RM(m, i->Xin.Sh32.dst);
- return;
case Xin_Sh3232:
mapReg(m, &i->Xin.Sh3232.rLo);
mapReg(m, &i->Xin.Sh3232.rHi);
Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
{
- UInt opc, opc_rr, subopc_imm, opc_imma;
+ UInt opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
UChar* p = &buf[0];
vassert(nbuf >= 32);
goto bad;
}
}
- /* ADD/SUB/ADC/SBB/AND/OR/XOR/TEST/CMP */
+ /* MUL */
+ if (i->Xin.Alu32R.op == Xalu_MUL) {
+ switch (i->Xin.Alu32R.src->tag) {
+case Xrmi_Reg:
+ *p++ = 0x0F;
+ *p++ = 0xAF;
+ p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.src->Xrmi.Reg.reg);
+ goto done;
+ case Xrmi_Imm:
+ if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
+ *p++ = 0x6B;
+ p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
+ *p++ = 0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32;
+ goto done;
+ } else {
+ goto bad;
+ }
+
+ default: goto bad;
+ }
+ }
+ /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP */
opc = opc_rr = subopc_imm = opc_imma = 0;
switch (i->Xin.Alu32R.op) {
case Xalu_ADD: opc = 0x03; opc_rr = 0x01;
subopc_imm = 5; opc_imma = 0x2D; break;
case Xalu_AND: opc = 0x23; opc_rr = 0x21;
subopc_imm = 4; opc_imma = 0x25; break;
+ case Xalu_XOR: opc = 0x33; opc_rr = 0x31;
+ subopc_imm = 6; opc_imma = 0x35; break;
+ case Xalu_OR: opc = 0x0B; opc_rr = 0x09;
+ subopc_imm = 1; opc_imma = 0x0D; break;
+ case Xalu_CMP: opc = 0x3B; opc_rr = 0x39;
+ subopc_imm = 7; opc_imma = 0x3D; break;
default: goto bad;
}
switch (i->Xin.Alu32R.src->tag) {
goto bad;
}
}
- /* ADD/SUB/ADC/SBB/AND/OR/XOR/TEST/CMP */
+ /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP. MUL is not
+ allowed here. */
opc = subopc_imm = opc_imma = 0;
switch (i->Xin.Alu32M.op) {
case Xalu_ADD: opc = 0x01; subopc_imm = 0; break;
}
break;
+ case Xin_Sh32:
+ opc_cl = opc_imm = subopc = 0;
+ switch (i->Xin.Sh32.op) {
+ case Xsh_SHR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 5; break;
+ case Xsh_SHL: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 4; break;
+ default: goto bad;
+ }
+ if (i->Xin.Sh32.src == 0) {
+ *p++ = opc_cl;
+ switch (i->Xin.Sh32.dst->tag) {
+ case Xrm_Reg:
+ p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst->Xrm.Reg.reg);
+ goto done;
+ default:
+ goto bad;
+ }
+ } else {
+ goto bad;
+ }
+ break;
+
+ case Xin_Test32:
+ if (i->Xin.Test32.src->tag == Xri_Imm
+ && i->Xin.Test32.dst->tag == Xrm_Reg) {
+ /* testl $imm32, %reg */
+ *p++ = 0xF7;
+ p = doAMode_R(p, fake(0), i->Xin.Test32.dst->Xrm.Reg.reg);
+ p = emit32(p, i->Xin.Test32.src->Xri.Imm.imm32);
+ goto done;
+ }
+ break;
+
+ case Xin_Unary32:
+ if (i->Xin.Unary32.op == Xun_Not) {
+ *p++ = 0xF7;
+ if (i->Xin.Unary32.dst->tag == Xrm_Reg) {
+ p = doAMode_R(p, fake(2), i->Xin.Unary32.dst->Xrm.Reg.reg);
+ goto done;
+ } else {
+ goto bad;
+ }
+ }
+ break;
+
+ case Xin_Push:
+ switch (i->Xin.Push.src->tag) {
+ case Xrmi_Mem:
+ *p++ = 0xFF;
+ p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am);
+ goto done;
+ default: goto bad;
+ }
+
+ case Xin_Call:
+ *p++ = 0xFF;
+ p = doAMode_R(p, fake(2), i->Xin.Call.target);
+ goto done;
+
case Xin_Goto:
+ /* unconditional jump to immediate */
if (i->Xin.Goto.cond == Xcc_ALWAYS
&& i->Xin.Goto.dst->tag == Xri_Imm) {
/* movl $immediate, %eax ; ret */
p = emit32(p, i->Xin.Goto.dst->Xri.Imm.imm32);
*p++ = 0xC3;
goto done;
- }
+ }
+ /* unconditional jump to reg */
if (i->Xin.Goto.cond == Xcc_ALWAYS
&& i->Xin.Goto.dst->tag == Xri_Reg) {
/* movl %reg, %eax ; ret */
- *p++ = 0x89;
- p = doAMode_R(p, i->Xin.Goto.dst->Xri.Reg.reg, hregX86_EAX());
+ if (i->Xin.Goto.dst->Xri.Reg.reg != hregX86_EAX()) {
+ *p++ = 0x89;
+ p = doAMode_R(p, i->Xin.Goto.dst->Xri.Reg.reg, hregX86_EAX());
+ }
+ *p++ = 0xC3;
+ goto done;
+ }
+ /* conditional jump to immediate */
+ if (i->Xin.Goto.cond != Xcc_ALWAYS
+ && i->Xin.Goto.dst->tag == Xri_Imm) {
+ /* jmp fwds if !condition */
+ *p++ = 0x70 + (i->Xin.Goto.cond ^ 1);
+ *p++ = 6; /* # of bytes in the next bit */
+ /* movl $immediate, %eax ; ret */
+ *p++ = 0xB8;
+ p = emit32(p, i->Xin.Goto.dst->Xri.Imm.imm32);
*p++ = 0xC3;
goto done;
- }
+ }
+ break;
+ case Xin_CMov32:
+ vassert(i->Xin.CMov32.cond != Xcc_ALWAYS);
+ *p++ = 0x0F;
+ *p++ = 0x40 + i->Xin.CMov32.cond;
+ if (i->Xin.CMov32.src->tag == Xrm_Reg) {
goto bad;
+ }
+ if (i->Xin.CMov32.src->tag == Xrm_Mem) {
+ p = doAMode_M(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Mem.am);
+ goto done;
+ }
+ break;
+
+ case Xin_LoadEX:
+ if (i->Xin.LoadEX.szSmall == 1 && !i->Xin.LoadEX.syned) {
+ /* movzbl */
+ *p++ = 0x0F;
+ *p++ = 0xB6;
+ p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
+ goto done;
+ }
+ if (i->Xin.LoadEX.szSmall == 2 && !i->Xin.LoadEX.syned) {
+ /* movzwl */
+ *p++ = 0x0F;
+ *p++ = 0xB7;
+ p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
+ goto done;
+ }
+ break;
+
+ case Xin_Store:
+ if (i->Xin.Store.sz == 1) {
+ /* we have to do complex dodging and weaving if
+ src is not the low 8 bits of %eax/%ebx/%ecx/%edx. */
+ if (iregNo(i->Xin.Store.src) < 4) {
+ /* we're OK, can do it directly */
+ *p++ = 0x88;
+ p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
+ goto done;
+ } else {
+ /* bleh. This means the source is %edi or %esi. Since the
+address mode can only mention three registers, at least one of
+%eax/%ebx/%ecx/%edx
+must be available to temporarily swap the source into, so the
+store can happen. */
+ HReg eax = hregX86_EAX(), ebx = hregX86_EBX(), ecx = hregX86_ECX(), edx = hregX86_EDX();
+ Bool a_ok = True, b_ok = True, c_ok = True, d_ok = True;
+ HRegUsage u;
+ Int j;
+ initHRegUsage(&u);
+ addRegUsage_X86AMode(&u, i->Xin.Store.dst);
+ for (j = 0; j < u.n_used; j++) {
+ HReg r = u.hreg[j];
+ if (r == eax) a_ok = False;
+ if (r == ebx) b_ok = False;
+ if (r == ecx) c_ok = False;
+ if (r == edx) d_ok = False;
+ }
+ HReg swap = INVALID_HREG;
+ if (a_ok) swap = eax;
+ if (b_ok) swap = ebx;
+ if (c_ok) swap = ecx;
+ if (d_ok) swap = edx;
+ vassert(swap != INVALID_HREG);
+ /* xchgl %source, %swap */
+ *p++ = 0x87;
+ p = doAMode_R(p, i->Xin.Store.src, swap);
+ /* movb lo8{%swap}, (dst) */
+ *p++ = 0x88;
+ p = doAMode_M(p, swap, i->Xin.Store.dst);
+ /* xchgl %source, %swap */
+ *p++ = 0x87;
+ p = doAMode_R(p, i->Xin.Store.src, swap);
+ goto done;
+ }
+ }
+ break;
default:
goto bad;
Xalu_INVALID,
Xalu_MOV,
Xalu_CMP,
- Xalu_TEST,
Xalu_ADD, Xalu_SUB, Xalu_ADC, Xalu_SBB,
Xalu_AND, Xalu_OR, Xalu_XOR,
Xalu_MUL
enum {
Xin_Alu32R, /* 32-bit mov/arith/logical, dst=REG */
Xin_Alu32M, /* 32-bit mov/arith/logical, dst=MEM */
+ Xin_Sh32, /* 32-bit shift/rotate, dst=REG or MEM */
+ Xin_Test32, /* 32-bit test (AND, set flags, discard result) */
Xin_Unary32, /* 32-bit not and neg */
Xin_MulL, /* widening multiply */
Xin_Div, /* div and mod */
- Xin_Sh32, /* 32-bit shift/rotate, dst=REG or MEM */
Xin_Sh3232, /* shldl or shrdl */
Xin_Push, /* push (32-bit?) value on stack */
Xin_Call, /* call to address in register */
X86RI* src;
X86AMode* dst;
} Alu32M;
+ struct {
+ X86ShiftOp op;
+ UInt src; /* shift amount, or 0 means %cl */
+ X86RM* dst;
+ } Sh32;
+ struct {
+ X86RI* src;
+ X86RM* dst;
+ } Test32;
/* Not and Neg */
struct {
X86UnaryOp op;
- X86RM* dst;
+ X86RM* dst;
} Unary32;
/* DX:AX = AX *s/u r/m16, or EDX:EAX = EAX *s/u r/m32 */
struct {
X86ScalarSz ssz;
X86RM* src;
} Div;
- struct {
- X86ShiftOp op;
- UInt src; /* shift amount, or 0 means %cl */
- X86RM* dst;
- } Sh32;
/* shld/shrd. op may only be Xsh_SHL or Xsh_SHR */
struct {
X86ShiftOp op;
- UInt amt; /* shift amount, or 0 means %cl */
- HReg rHi;
- HReg rLo;
+ UInt amt; /* shift amount, or 0 means %cl */
+ HReg rHi;
+ HReg rLo;
} Sh3232;
struct {
X86RMI* src;
be the bogus Xcc_ALWAYS. */
struct {
X86CondCode cond;
- X86RM* src;
- HReg dst;
+ X86RM* src;
+ HReg dst;
} CMov32;
/* Sign/Zero extending loads. Dst size is always 32 bits. */
struct {
/* 16/8 bit stores, which are troublesome (particularly
8-bit) */
struct {
- UChar sz; /* only 1 or 2 */
- HReg src;
+ UChar sz; /* only 1 or 2 */
+ HReg src;
X86AMode* dst;
} Store;
} Xin;
extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg );
extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* );
extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst );
+extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* );
+extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst );
extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* );
extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* );
-extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* );
extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg rHi, HReg rLo );
extern X86Instr* X86Instr_Push ( X86RMI* );
extern X86Instr* X86Instr_Call ( HReg );