machinst x64: add support for umulhi/smulhi;
This commit is contained in:
@@ -589,6 +589,32 @@ pub(crate) fn emit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inst::MulHi { size, signed, rhs } => {
|
||||||
|
let (prefix, rex_flags) = match size {
|
||||||
|
2 => (LegacyPrefix::_66, RexFlags::clear_w()),
|
||||||
|
4 => (LegacyPrefix::None, RexFlags::clear_w()),
|
||||||
|
8 => (LegacyPrefix::None, RexFlags::set_w()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let subopcode = if *signed { 5 } else { 4 };
|
||||||
|
match rhs {
|
||||||
|
RegMem::Reg { reg } => {
|
||||||
|
let src = int_reg_enc(*reg);
|
||||||
|
emit_std_enc_enc(sink, prefix, 0xF7, 1, subopcode, src, rex_flags)
|
||||||
|
}
|
||||||
|
RegMem::Mem { addr: src } => emit_std_enc_mem(
|
||||||
|
sink,
|
||||||
|
prefix,
|
||||||
|
0xF7,
|
||||||
|
1,
|
||||||
|
subopcode,
|
||||||
|
&src.finalize(state),
|
||||||
|
rex_flags,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Inst::SignExtendRaxRdx { size } => {
|
Inst::SignExtendRaxRdx { size } => {
|
||||||
match size {
|
match size {
|
||||||
2 => sink.put1(0x66),
|
2 => sink.put1(0x66),
|
||||||
|
|||||||
@@ -1197,6 +1197,29 @@ fn test_x64_emit() {
|
|||||||
"div %rdi",
|
"div %rdi",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// MulHi
|
||||||
|
insns.push((
|
||||||
|
Inst::mul_hi(4, true /*signed*/, RegMem::reg(regs::rsi())),
|
||||||
|
"F7EE",
|
||||||
|
"imul %esi",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::mul_hi(8, true /*signed*/, RegMem::reg(regs::r15())),
|
||||||
|
"49F7EF",
|
||||||
|
"imul %r15",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::mul_hi(4, false /*signed*/, RegMem::reg(regs::r14())),
|
||||||
|
"41F7E6",
|
||||||
|
"mul %r14d",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::mul_hi(8, false /*signed*/, RegMem::reg(regs::rdi())),
|
||||||
|
"48F7E7",
|
||||||
|
"mul %rdi",
|
||||||
|
));
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// 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"));
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ pub enum Inst {
|
|||||||
loc: SourceLoc,
|
loc: SourceLoc,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// The high result of a (un)signed multiply: imul/mul using RAX:RDX.
|
||||||
|
MulHi { size: u8, signed: bool, rhs: RegMem },
|
||||||
|
|
||||||
/// A synthetic sequence to implement the right inline checks for remainder and division,
|
/// A synthetic sequence to implement the right inline checks for remainder and division,
|
||||||
/// assuming the dividend is in $rax.
|
/// assuming the dividend is in $rax.
|
||||||
/// Puts the result back into $rax if is_div, $rdx if !is_div, to mimic what the div
|
/// Puts the result back into $rax if is_div, $rdx if !is_div, to mimic what the div
|
||||||
@@ -301,6 +304,12 @@ impl Inst {
|
|||||||
loc,
|
loc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mul_hi(size: u8, signed: bool, rhs: RegMem) -> Inst {
|
||||||
|
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
|
||||||
|
Inst::MulHi { size, signed, rhs }
|
||||||
|
}
|
||||||
|
|
||||||
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 }
|
||||||
@@ -581,6 +590,17 @@ impl ShowWithRRU for Inst {
|
|||||||
}),
|
}),
|
||||||
divisor.show_rru_sized(mb_rru, *size)
|
divisor.show_rru_sized(mb_rru, *size)
|
||||||
),
|
),
|
||||||
|
Inst::MulHi {
|
||||||
|
size, signed, rhs, ..
|
||||||
|
} => format!(
|
||||||
|
"{} {}",
|
||||||
|
ljustify(if *signed {
|
||||||
|
"imul".to_string()
|
||||||
|
} else {
|
||||||
|
"mul".to_string()
|
||||||
|
}),
|
||||||
|
rhs.show_rru_sized(mb_rru, *size)
|
||||||
|
),
|
||||||
Inst::CheckedDivOrRemSeq {
|
Inst::CheckedDivOrRemSeq {
|
||||||
is_div,
|
is_div,
|
||||||
is_signed,
|
is_signed,
|
||||||
@@ -796,6 +816,11 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
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, .. } => {
|
||||||
|
collector.add_mod(Writable::from_reg(regs::rax()));
|
||||||
|
collector.add_def(Writable::from_reg(regs::rdx()));
|
||||||
|
rhs.get_regs_as_uses(collector);
|
||||||
|
}
|
||||||
Inst::CheckedDivOrRemSeq { divisor, .. } => {
|
Inst::CheckedDivOrRemSeq { divisor, .. } => {
|
||||||
collector.add_mod(Writable::from_reg(regs::rax()));
|
collector.add_mod(Writable::from_reg(regs::rax()));
|
||||||
collector.add_mod(Writable::from_reg(regs::rdx()));
|
collector.add_mod(Writable::from_reg(regs::rdx()));
|
||||||
@@ -994,6 +1019,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
|||||||
map_mod(mapper, dst);
|
map_mod(mapper, dst);
|
||||||
}
|
}
|
||||||
Inst::Div { divisor, .. } => divisor.map_uses(mapper),
|
Inst::Div { divisor, .. } => divisor.map_uses(mapper),
|
||||||
|
Inst::MulHi { rhs, .. } => rhs.map_uses(mapper),
|
||||||
Inst::CheckedDivOrRemSeq { divisor, .. } => {
|
Inst::CheckedDivOrRemSeq { divisor, .. } => {
|
||||||
map_use(mapper, divisor);
|
map_use(mapper, divisor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -747,6 +747,29 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opcode::Umulhi | Opcode::Smulhi => {
|
||||||
|
let input_ty = ctx.input_ty(insn, 0);
|
||||||
|
let size = input_ty.bytes() as u8;
|
||||||
|
|
||||||
|
let lhs = input_to_reg(ctx, inputs[0]);
|
||||||
|
let rhs = input_to_reg_mem(ctx, inputs[1]);
|
||||||
|
let dst = output_to_reg(ctx, outputs[0]);
|
||||||
|
|
||||||
|
// Move lhs in %rax.
|
||||||
|
ctx.emit(Inst::gen_move(
|
||||||
|
Writable::from_reg(regs::rax()),
|
||||||
|
lhs,
|
||||||
|
input_ty,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Emit the actual mul or imul.
|
||||||
|
let signed = op == Opcode::Smulhi;
|
||||||
|
ctx.emit(Inst::mul_hi(size, signed, rhs));
|
||||||
|
|
||||||
|
// Read the result from the high part (stored in %rdx).
|
||||||
|
ctx.emit(Inst::gen_move(dst, regs::rdx(), input_ty));
|
||||||
|
}
|
||||||
|
|
||||||
Opcode::IaddImm
|
Opcode::IaddImm
|
||||||
| Opcode::ImulImm
|
| Opcode::ImulImm
|
||||||
| Opcode::UdivImm
|
| Opcode::UdivImm
|
||||||
|
|||||||
Reference in New Issue
Block a user