From: Julian Seward Date: Fri, 23 Jul 2004 01:34:11 +0000 (+0000) Subject: Fill in many (most) x86 emission cases. X-Git-Tag: svn/VALGRIND_3_0_1^2~1227 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=66d77829bf3a0c553b8f7ace22f4249a6cbae261;p=thirdparty%2Fvalgrind.git Fill in many (most) x86 emission cases. git-svn-id: svn://svn.valgrind.org/vex/trunk@107 --- diff --git a/VEX/priv/host-x86/isel_x86.c b/VEX/priv/host-x86/isel_x86.c index 35a45f6873..598bf2031d 100644 --- a/VEX/priv/host-x86/isel_x86.c +++ b/VEX/priv/host-x86/isel_x86.c @@ -460,8 +460,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) HReg dst = newVRegI(env); addInstr(env, mk_MOVsd_RR(rX,dst)); HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); - addInstr(env, X86Instr_Alu32R(Xalu_TEST, - X86RMI_Imm(0xFF), r8)); + addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst)); return dst; } @@ -766,7 +765,7 @@ static void iselIntExpr64 ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) those regs are legitimately modifiable. */ addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tHi, tLo)); addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo))); - addInstr(env, X86Instr_Alu32R(Xalu_TEST, X86RMI_Imm(32), hregX86_ECX())); + addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX()))); addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi)); addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp)); addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo)); diff --git a/VEX/priv/host-x86/x86host_defs.c b/VEX/priv/host-x86/x86host_defs.c index 97343f6011..50bcd42b07 100644 --- a/VEX/priv/host-x86/x86host_defs.c +++ b/VEX/priv/host-x86/x86host_defs.c @@ -376,7 +376,6 @@ Char* showX86AluOp ( X86AluOp op ) { 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"; @@ -414,6 +413,22 @@ X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) { 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 ) { @@ -439,14 +454,6 @@ X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz ssz, X86RM* src ) { 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; @@ -521,6 +528,20 @@ void ppX86Instr ( X86Instr* i ) { 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); @@ -537,14 +558,6 @@ void ppX86Instr ( X86Instr* i ) { 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) @@ -612,8 +625,7 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) 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; } @@ -623,6 +635,15 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) 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; @@ -636,11 +657,6 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) 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); @@ -698,6 +714,13 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i) 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; @@ -707,9 +730,6 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i) 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); @@ -911,7 +931,7 @@ static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg ) 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); @@ -945,7 +965,28 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) 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; @@ -954,6 +995,12 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) 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) { @@ -1006,7 +1053,8 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) 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; @@ -1036,7 +1084,66 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) } 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 */ @@ -1044,17 +1151,109 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) 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; diff --git a/VEX/priv/host-x86/x86host_defs.h b/VEX/priv/host-x86/x86host_defs.h index 3714083194..c48716bdca 100644 --- a/VEX/priv/host-x86/x86host_defs.h +++ b/VEX/priv/host-x86/x86host_defs.h @@ -221,7 +221,6 @@ typedef Xalu_INVALID, Xalu_MOV, Xalu_CMP, - Xalu_TEST, Xalu_ADD, Xalu_SUB, Xalu_ADC, Xalu_SBB, Xalu_AND, Xalu_OR, Xalu_XOR, Xalu_MUL @@ -248,10 +247,11 @@ typedef 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 */ @@ -278,10 +278,19 @@ typedef 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 { @@ -295,17 +304,12 @@ typedef 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; @@ -323,8 +327,8 @@ typedef 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 { @@ -336,8 +340,8 @@ typedef /* 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; @@ -347,9 +351,10 @@ typedef 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 );