case Iop_Sub8: case Iop_Sub16: case Iop_Sub32:
aluOp = Xalu_SUB; break;
- case Iop_And8:
- case Iop_And32: aluOp = Xalu_AND; break;
+ case Iop_And8: case Iop_And16: case Iop_And32:
+ aluOp = Xalu_AND; break;
case Iop_Or8: case Iop_Or32:
aluOp = Xalu_OR; break;
/* Perhaps a shift op? */
switch (e->Iex.Binop.op) {
case Iop_Shl32: shOp = Xsh_SHL; break;
- case Iop_Shr32: shOp = Xsh_SHR; break;
+ case Iop_Shr8: case Iop_Shr32:
+ shOp = Xsh_SHR; break;
case Iop_Sar32: shOp = Xsh_SAR; break;
default: shOp = Xsh_INVALID; break;
}
HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2);
addInstr(env, mk_MOVsd_RR(regL,dst));
addInstr(env, mk_MOVsd_RR(regR,hregX86_ECX()));
+ /* Do any necessary widening for 16/8 bit operands */
+ switch (e->Iex.Binop.op) {
+ case Iop_Shr8:
+ addInstr(env, X86Instr_Alu32R(
+ Xalu_AND, X86RMI_Imm(0xFF), dst));
+ break;
+ case Iop_Shr16:
+ addInstr(env, X86Instr_Alu32R(
+ Xalu_AND, X86RMI_Imm(0xFFFF), dst));
+ break;
+ case Iop_Sar8: case Iop_Sar16: vassert(0); // fill this in!
+ default: break;
+ }
addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst)));
return dst;
}
HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
addInstr(env, X86Instr_Alu32R(Xalu_TEST,
X86RMI_Imm(0xFF), r8));
- addInstr(env, X86Instr_CMovZ(r0,dst));
+ addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst));
return dst;
}
break;
return;
}
+ /* 64 x 32 -> (32(rem),32(div)) division */
+ if (e->tag == Iex_Binop
+ && (e->Iex.Binop.op == Iop_DivModU64to32
+ || e->Iex.Binop.op == Iop_DivModS64to32)) {
+ /* Get the 64-bit operand into edx:eax, and the other
+ into any old R/M. */
+ HReg sHi, sLo;
+ Bool syned = e->Iex.Binop.op == Iop_MullS32;
+ X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
+ iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
+ addInstr(env, mk_MOVsd_RR(sHi, hregX86_EDX()));
+ addInstr(env, mk_MOVsd_RR(sLo, hregX86_EAX()));
+ addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
+ *rHi = hregX86_EDX();
+ *rLo = hregX86_EAX();
+ return;
+ }
+
+ /* 32HLto64(e1,e2) */
+ if (e->tag == Iex_Binop
+ && e->Iex.Binop.op == Iop_32HLto64) {
+ *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
+ *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ return;
+ }
+
+ /* 64-bit shifts */
+ if (e->tag == Iex_Binop
+ && e->Iex.Binop.op == Iop_Shl64) {
+ /* We use the same ingenious scheme as gcc. Put the value
+ to be shifted into %hi:%lo, and the shift amount into %cl.
+ Then (dsts on right, a la ATT syntax):
+
+ shldl %cl, %lo, %hi -- make %hi be right for the shift amt
+ -- %cl % 32
+ shll %cl, %lo -- make %lo be right for the shift amt
+ -- %cl % 32
+
+ Now, if (shift amount % 64) is in the range 32 .. 63, we have
+ to do a fixup, which puts the result low half into the result
+ high half, and zeroes the low half:
+
+ testl $32, %ecx
+
+ cmovnz %lo, %hi
+ movl $0, %tmp -- sigh; need yet another reg
+ cmovnz %tmp, %lo
+ */
+ HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
+ tLo = newVRegI(env);
+ tHi = newVRegI(env);
+ tTemp = newVRegI(env);
+ rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
+ addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
+ addInstr(env, mk_MOVsd_RR(sHi, tHi));
+ addInstr(env, mk_MOVsd_RR(sLo, tLo));
+ /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
+ 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_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));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
ppIRExpr(e);
vpanic("iselIntExpr64");
}
i->Xin.MulL.src = src;
return i;
}
+X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz ssz, X86RM* src ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Div;
+ i->Xin.Div.syned = syned;
+ i->Xin.Div.ssz = ssz;
+ 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.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;
+ i->Xin.Sh3232.op = op;
+ i->Xin.Sh3232.amt = amt;
+ i->Xin.Sh3232.rHi = rHi;
+ i->Xin.Sh3232.rLo = rLo;
+ vassert(op == Xsh_SHL || op == Xsh_SHR);
+ return i;
+}
X86Instr* X86Instr_Push( X86RMI* src ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_Push;
i->Xin.Goto.dst = dst;
return i;
}
-X86Instr* X86Instr_CMovZ ( X86RM* src, HReg dst ) {
- X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
- i->tag = Xin_CMovZ;
- i->Xin.CMovZ.src = src;
- i->Xin.CMovZ.dst = dst;
+X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_CMov32;
+ i->Xin.CMov32.cond = cond;
+ i->Xin.CMov32.src = src;
+ i->Xin.CMov32.dst = dst;
+ vassert(cond != Xcc_ALWAYS);
return i;
}
X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
showX86ScalarSz(i->Xin.MulL.ssz));
ppX86RM(i->Xin.MulL.src);
return;
+ case Xin_Div:
+ vex_printf("%cdiv%s ",
+ i->Xin.Div.syned ? 's' : 'u',
+ 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(" $%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)
+ vex_printf(" %%cl,");
+ else
+ vex_printf(" $%d,", i->Xin.Sh3232.amt);
+ ppHRegX86(i->Xin.Sh3232.rLo);
+ vex_printf(",");
+ ppHRegX86(i->Xin.Sh3232.rHi);
+ return;
case Xin_Push:
vex_printf("pushl ");
ppX86RMI(i->Xin.Push.src);
vex_printf(",%%eax ; ret }");
}
return;
- case Xin_CMovZ:
- vex_printf("cmovz ");
- ppX86RM(i->Xin.CMovZ.src);
+ case Xin_CMov32:
+ vex_printf("cmovl%s ", showX86CondCode(i->Xin.CMov32.cond));
+ ppX86RM(i->Xin.CMov32.src);
vex_printf(",");
- ppHRegX86(i->Xin.CMovZ.dst);
+ ppHRegX86(i->Xin.CMov32.dst);
return;
case Xin_LoadEX:
vex_printf("mov%c%cl ",
Xin_Alu32M, /* 32-bit mov/arith/logical, dst=MEM */
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 */
Xin_Goto, /* conditional/unconditional jmp to dst */
- Xin_CMovZ, /* conditional move when Z flag set */
+ Xin_CMov32, /* conditional move */
Xin_LoadEX, /* mov{s,z}{b,w}l from mem to reg */
Xin_Store /* store 16/8 bit value in memory */
}
X86ScalarSz ssz;
X86RM* src;
} MulL;
+ /* x86 div/idiv instruction */
+ struct {
+ Bool syned;
+ 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;
+ } Sh3232;
struct {
X86RMI* src;
} Push;
X86CondCode cond;
X86RI* dst;
} Goto;
- /* Mov src to dst (both 32-bit regs?) when the Z flag is
- set. */
+ /* Mov src to dst on the given condition, which may not
+ be the bogus Xcc_ALWAYS. */
struct {
+ X86CondCode cond;
X86RM* src;
HReg dst;
- } CMovZ;
+ } CMov32;
/* Sign/Zero extending loads. Dst size is always 32 bits. */
struct {
UChar szSmall;
extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* );
extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, 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 );
extern X86Instr* X86Instr_Goto ( X86CondCode cond, X86RI* dst );
-extern X86Instr* X86Instr_CMovZ ( X86RM* src, HReg dst );
+extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst );
extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
X86AMode* src, HReg dst );
extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst );