x64: Fix udiv and sdiv for 8bit integers
This commit is contained in:
@@ -662,11 +662,12 @@ pub(crate) fn emit(
|
|||||||
divisor,
|
divisor,
|
||||||
loc,
|
loc,
|
||||||
} => {
|
} => {
|
||||||
let (prefix, rex_flags) = match size {
|
let (opcode, prefix, rex_flags) = match size {
|
||||||
2 => (LegacyPrefixes::_66, RexFlags::clear_w()),
|
1 => (0xF6, LegacyPrefixes::None, RexFlags::clear_w()),
|
||||||
4 => (LegacyPrefixes::None, RexFlags::clear_w()),
|
2 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
|
||||||
8 => (LegacyPrefixes::None, RexFlags::set_w()),
|
4 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
|
||||||
_ => unreachable!(),
|
8 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
|
||||||
|
_ => unreachable!("{}", size),
|
||||||
};
|
};
|
||||||
|
|
||||||
sink.add_trap(*loc, TrapCode::IntegerDivisionByZero);
|
sink.add_trap(*loc, TrapCode::IntegerDivisionByZero);
|
||||||
@@ -675,12 +676,12 @@ pub(crate) fn emit(
|
|||||||
match divisor {
|
match divisor {
|
||||||
RegMem::Reg { reg } => {
|
RegMem::Reg { reg } => {
|
||||||
let src = int_reg_enc(*reg);
|
let src = int_reg_enc(*reg);
|
||||||
emit_std_enc_enc(sink, prefix, 0xF7, 1, subopcode, src, rex_flags)
|
emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, src, rex_flags)
|
||||||
}
|
}
|
||||||
RegMem::Mem { addr: src } => emit_std_enc_mem(
|
RegMem::Mem { addr: src } => emit_std_enc_mem(
|
||||||
sink,
|
sink,
|
||||||
prefix,
|
prefix,
|
||||||
0xF7,
|
opcode,
|
||||||
1,
|
1,
|
||||||
subopcode,
|
subopcode,
|
||||||
&src.finalize(state),
|
&src.finalize(state),
|
||||||
@@ -715,6 +716,11 @@ pub(crate) fn emit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inst::SignExtendAlAh => {
|
||||||
|
sink.put1(0x66);
|
||||||
|
sink.put1(0x98);
|
||||||
|
}
|
||||||
|
|
||||||
Inst::SignExtendRaxRdx { size } => {
|
Inst::SignExtendRaxRdx { size } => {
|
||||||
match size {
|
match size {
|
||||||
2 => sink.put1(0x66),
|
2 => sink.put1(0x66),
|
||||||
|
|||||||
@@ -1354,6 +1354,10 @@ fn test_x64_emit() {
|
|||||||
"mul %rdi",
|
"mul %rdi",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// cbw
|
||||||
|
insns.push((Inst::sign_extend_al_to_ah(), "6698", "cbw"));
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// cdq family: SignExtendRaxRdx
|
// cdq family: SignExtendRaxRdx
|
||||||
insns.push((Inst::sign_extend_rax_to_rdx(2), "6699", "cwd"));
|
insns.push((Inst::sign_extend_rax_to_rdx(2), "6699", "cwd"));
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ pub enum Inst {
|
|||||||
loc: SourceLoc,
|
loc: SourceLoc,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Do a sign-extend based on the sign of the value in al into ah: (cbw)
|
||||||
|
SignExtendAlAh,
|
||||||
|
|
||||||
/// Do a sign-extend based on the sign of the value in rax into rdx: (cwd cdq cqo)
|
/// Do a sign-extend based on the sign of the value in rax into rdx: (cwd cdq cqo)
|
||||||
SignExtendRaxRdx {
|
SignExtendRaxRdx {
|
||||||
size: u8, // 1, 2, 4 or 8
|
size: u8, // 1, 2, 4 or 8
|
||||||
@@ -574,6 +577,10 @@ impl Inst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sign_extend_al_to_ah() -> Inst {
|
||||||
|
Inst::SignExtendAlAh
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn sign_extend_rax_to_rdx(size: u8) -> Inst {
|
pub(crate) fn sign_extend_rax_to_rdx(size: u8) -> Inst {
|
||||||
debug_assert!(size == 8 || size == 4 || size == 2);
|
debug_assert!(size == 8 || size == 4 || size == 2);
|
||||||
Inst::SignExtendRaxRdx { size }
|
Inst::SignExtendRaxRdx { size }
|
||||||
@@ -1259,6 +1266,8 @@ impl ShowWithRRU for Inst {
|
|||||||
show_ireg_sized(divisor.to_reg(), mb_rru, *size),
|
show_ireg_sized(divisor.to_reg(), mb_rru, *size),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
Inst::SignExtendAlAh => "cbw".into(),
|
||||||
|
|
||||||
Inst::SignExtendRaxRdx { size } => match size {
|
Inst::SignExtendRaxRdx { size } => match size {
|
||||||
2 => "cwd",
|
2 => "cwd",
|
||||||
4 => "cdq",
|
4 => "cdq",
|
||||||
@@ -1687,9 +1696,13 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
Inst::Neg { src, .. } => {
|
Inst::Neg { src, .. } => {
|
||||||
collector.add_mod(*src);
|
collector.add_mod(*src);
|
||||||
}
|
}
|
||||||
Inst::Div { divisor, .. } => {
|
Inst::Div { size, divisor, .. } => {
|
||||||
collector.add_mod(Writable::from_reg(regs::rax()));
|
collector.add_mod(Writable::from_reg(regs::rax()));
|
||||||
|
if *size == 1 {
|
||||||
|
collector.add_def(Writable::from_reg(regs::rdx()));
|
||||||
|
} else {
|
||||||
collector.add_mod(Writable::from_reg(regs::rdx()));
|
collector.add_mod(Writable::from_reg(regs::rdx()));
|
||||||
|
}
|
||||||
divisor.get_regs_as_uses(collector);
|
divisor.get_regs_as_uses(collector);
|
||||||
}
|
}
|
||||||
Inst::MulHi { rhs, .. } => {
|
Inst::MulHi { rhs, .. } => {
|
||||||
@@ -1708,6 +1721,9 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
collector.add_def(*tmp);
|
collector.add_def(*tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Inst::SignExtendAlAh => {
|
||||||
|
collector.add_mod(Writable::from_reg(regs::rax()));
|
||||||
|
}
|
||||||
Inst::SignExtendRaxRdx { .. } => {
|
Inst::SignExtendRaxRdx { .. } => {
|
||||||
collector.add_use(regs::rax());
|
collector.add_use(regs::rax());
|
||||||
collector.add_def(Writable::from_reg(regs::rdx()));
|
collector.add_def(Writable::from_reg(regs::rdx()));
|
||||||
@@ -2012,7 +2028,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
|||||||
map_def(mapper, tmp)
|
map_def(mapper, tmp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::SignExtendRaxRdx { .. } => {}
|
Inst::SignExtendAlAh | Inst::SignExtendRaxRdx { .. } => {}
|
||||||
Inst::XmmUnaryRmR {
|
Inst::XmmUnaryRmR {
|
||||||
ref mut src,
|
ref mut src,
|
||||||
ref mut dst,
|
ref mut dst,
|
||||||
|
|||||||
@@ -2381,6 +2381,19 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
let divisor = input_to_reg_mem(ctx, inputs[1]);
|
let divisor = input_to_reg_mem(ctx, inputs[1]);
|
||||||
|
|
||||||
// Fill in the high parts:
|
// Fill in the high parts:
|
||||||
|
if input_ty == types::I8 {
|
||||||
|
if kind.is_signed() {
|
||||||
|
// sign-extend the sign-bit of al into ah, for signed opcodes.
|
||||||
|
ctx.emit(Inst::sign_extend_al_to_ah());
|
||||||
|
} else {
|
||||||
|
ctx.emit(Inst::movzx_rm_r(
|
||||||
|
ExtMode::BL,
|
||||||
|
RegMem::reg(regs::rax()),
|
||||||
|
Writable::from_reg(regs::rax()),
|
||||||
|
/* infallible */ None,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if kind.is_signed() {
|
if kind.is_signed() {
|
||||||
// sign-extend the sign-bit of rax into rdx, for signed opcodes.
|
// sign-extend the sign-bit of rax into rdx, for signed opcodes.
|
||||||
ctx.emit(Inst::sign_extend_rax_to_rdx(size));
|
ctx.emit(Inst::sign_extend_rax_to_rdx(size));
|
||||||
@@ -2392,6 +2405,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
Writable::from_reg(regs::rdx()),
|
Writable::from_reg(regs::rdx()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Emit the actual idiv.
|
// Emit the actual idiv.
|
||||||
ctx.emit(Inst::div(size, kind.is_signed(), divisor, ctx.srcloc(insn)));
|
ctx.emit(Inst::div(size, kind.is_signed(), divisor, ctx.srcloc(insn)));
|
||||||
|
|||||||
Reference in New Issue
Block a user