case CC_OP_RORW: ACTIONS_ROR( 16, UShort );
case CC_OP_RORL: ACTIONS_ROR( 32, UInt );
- case CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, ULong );
+ case CC_OP_UMULB: ACTIONS_UMUL( 8, UChar, UShort );
+ case CC_OP_UMULW: ACTIONS_UMUL( 16, UShort, UInt );
+ case CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, ULong );
- case CC_OP_SMULL: ACTIONS_SMUL( 32, Int, Long );
+ case CC_OP_SMULB: ACTIONS_SMUL( 8, Char, Short );
+ case CC_OP_SMULW: ACTIONS_SMUL( 16, Short, Int );
+ case CC_OP_SMULL: ACTIONS_SMUL( 32, Int, Long );
default:
/* shouldn't really make these calls from generated code */
assign( t1, getIReg(sz, R_EAX) );
switch (ty) {
- case Ity_I32: {
- IRTemp res64 = newTemp(Ity_I64);
- IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
- UInt thunkOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
- setFlags_MUL ( Ity_I32, t1, tmp, thunkOp );
- assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
- putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
- putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
- break;
- }
-#if 0
- case Ity_I16: {
- IRTemp res32 = newTemp(Ity_I32);
- IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
- UInt thunkOp = syned ? CC_OP_MULLSB : CC_OP_MULLUB;
- setFlags_MUL ( Ity_I16, t1, tmp, thunkOp );
- assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
- putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
- putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
- break;
- }
-#endif
- default:
- vpanic("codegen_mulL_A_D(x86)");
+ case Ity_I32: {
+ IRTemp res64 = newTemp(Ity_I64);
+ IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
+ UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+ setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
+ assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
+ putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
+ putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
+ break;
+ }
+ case Ity_I16: {
+ IRTemp res32 = newTemp(Ity_I32);
+ IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
+ UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+ setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
+ assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
+ putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
+ putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
+ break;
+ }
+ case Ity_I8: {
+ IRTemp res16 = newTemp(Ity_I16);
+ IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
+ UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+ setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
+ assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
+ putIReg(2, R_EAX, mkexpr(res16));
+ break;
+ }
+ default:
+ vpanic("codegen_mulL_A_D(x86)");
}
DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
}
UInt delta,
Int litsize )
{
- Int d32;
- Char dis_buf[50];
- UChar rm = getIByte(delta);
- // ta = INVALID_TEMPREG;
+ Int d32;
+ Char dis_buf[50];
+ UChar rm = getIByte(delta);
IRType ty = szToITy(size);
IRTemp te = newTemp(ty);
IRTemp tl = newTemp(ty);
+ vassert(size == 1 || size == 2 || size == 4);
+
if (epartIsReg(rm)) {
assign(te, getIReg(size, eregOfRM(rm)));
delta++;
d32 = getSDisp(litsize,delta);
delta += litsize;
+ if (size == 1) d32 &= 0xFF;
+ if (size == 2) d32 &= 0xFFFF;
+
assign(tl, mkU(ty,d32));
setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
putIReg(size, gregOfRM(rm),
aluOp = Xalu_OR; break;
case Iop_Xor8: case Iop_Xor16: case Iop_Xor32:
aluOp = Xalu_XOR; break;
- case Iop_Mul32: aluOp = Xalu_MUL; break;
- default: aluOp = Xalu_INVALID; break;
+ case Iop_Mul16: case Iop_Mul32:
+ aluOp = Xalu_MUL; break;
+ default:
+ aluOp = Xalu_INVALID; break;
}
/* For commutative ops we assume any literal
values are on the second operand. */
nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
vassert(nshift >= 0);
if (nshift > 0)
+ /* Can't allow nshift==0 since that means %cl */
addInstr(env, X86Instr_Sh32(
shOp,
nshift,
return hi16;
}
+ if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8
+ || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) {
+ HReg a16 = newVRegI(env);
+ HReg b16 = newVRegI(env);
+ HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
+ HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ Int shift = (e->Iex.Binop.op == Iop_MullS8
+ || e->Iex.Binop.op == Iop_MullU8)
+ ? 24 : 16;
+ X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8
+ || e->Iex.Binop.op == Iop_MullS16)
+ ? Xsh_SAR : Xsh_SHR;
+
+ addInstr(env, mk_MOVsd_RR(a16s, a16));
+ addInstr(env, mk_MOVsd_RR(b16s, b16));
+ addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16)));
+ addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16)));
+ addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(a16)));
+ addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(b16)));
+ addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16));
+ return b16;
+ }
+
break;
}
iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
return rLo; /* similar stupid comment to the above ... */
}
+ case Iop_16HIto8:
case Iop_32HIto16: {
- HReg dst = newVRegI(env);
- HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ HReg dst = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
addInstr(env, mk_MOVsd_RR(src,dst) );
- addInstr(env, X86Instr_Sh32(Xsh_SHR, 16, X86RM_Reg(dst)));
+ addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
return dst;
}
+ case Iop_16to8:
case Iop_32to8:
case Iop_32to16:
- /* These are both no-ops. */
+ /* These are no-ops. */
return iselIntExpr_R(env, e->Iex.Unop.arg);
default:
case Iop_DivModU64to32: vex_printf("DivModU64to32"); return;
case Iop_DivModS64to32: vex_printf("DivModS64to32"); return;
+ case Iop_16HIto8: vex_printf("16HIto8"); return;
+ case Iop_16to8: vex_printf("16to8"); return;
+ case Iop_8HLto16: vex_printf("8HLto16"); return;
+
case Iop_32HIto16: vex_printf("32HIto16"); return;
case Iop_32to16: vex_printf("32to16"); return;
case Iop_16HLto32: vex_printf("16HLto32"); return;
case Iop_CmpEQ64: case Iop_CmpNE64:
COMPARISON(Ity_I64);
+ case Iop_MullU8: case Iop_MullS8:
+ BINARY(Ity_I16,Ity_I8,Ity_I8);
+ case Iop_MullU16: case Iop_MullS16:
+ BINARY(Ity_I32,Ity_I16,Ity_I16);
case Iop_MullU32: case Iop_MullS32:
BINARY(Ity_I64,Ity_I32,Ity_I32);
case Iop_DivModS64to32:
BINARY(Ity_I64,Ity_I64,Ity_I32);
+ case Iop_16HIto8: case Iop_16to8:
+ UNARY(Ity_I8,Ity_I16);
+ case Iop_8HLto16:
+ BINARY(Ity_I16,Ity_I8,Ity_I8);
+
case Iop_32HIto16: case Iop_32to16:
UNARY(Ity_I16,Ity_I32);
case Iop_16HLto32:
Iop_8Sto16, Iop_8Sto32, Iop_16Sto32,
/* Narrowing conversions */
Iop_32to8,
+ /* 8 <-> 16 bit conversions */
+ Iop_16to8, // :: I16 -> I8, low half
+ Iop_16HIto8, // :: I16 -> I8, high half
+ Iop_8HLto16, // :: (I8,I8) -> I16
/* 16 <-> 32 bit conversions */
Iop_32to16, // :: I32 -> I16, low half
Iop_32HIto16, // :: I32 -> I16, high half