winch: Add support for integer multiplication in x64. (#5769)
This commit adds support for the `<i32|i64>.mul` WebAssembly instructions in x64.
This commit is contained in:
@@ -147,6 +147,10 @@ impl Masm for MacroAssembler {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn mul(&mut self, _dst: RegImm, _lhs: RegImm, _rhs: RegImm, _size: OperandSize) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn zero(&mut self, reg: Reg) {
|
||||
self.asm.load_constant(0, reg);
|
||||
}
|
||||
|
||||
@@ -242,6 +242,50 @@ impl Assembler {
|
||||
});
|
||||
}
|
||||
|
||||
/// Signed multiplication instruction.
|
||||
pub fn mul(&mut self, src: Operand, dst: Operand, size: OperandSize) {
|
||||
match &(src, dst) {
|
||||
(Operand::Imm(imm), Operand::Reg(dst)) => {
|
||||
if let Ok(val) = i32::try_from(*imm) {
|
||||
self.mul_ir(val, *dst, size);
|
||||
} else {
|
||||
let scratch = regs::scratch();
|
||||
self.mov_ir(*imm as u64, scratch, size);
|
||||
self.mul_rr(scratch, *dst, size);
|
||||
}
|
||||
}
|
||||
(Operand::Reg(src), Operand::Reg(dst)) => self.mul_rr(*src, *dst, size),
|
||||
_ => panic!(
|
||||
"Invalid operand combination for mul; src = {:?} dst = {:?}",
|
||||
src, dst
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiply immediate and register.
|
||||
pub fn mul_ir(&mut self, imm: i32, dst: Reg, size: OperandSize) {
|
||||
let imm = RegMemImm::imm(imm as u32);
|
||||
|
||||
self.emit(Inst::AluRmiR {
|
||||
size: size.into(),
|
||||
op: AluRmiROpcode::Mul,
|
||||
src1: dst.into(),
|
||||
src2: GprMemImm::new(imm).expect("valid immediate"),
|
||||
dst: dst.into(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Multiply register and register.
|
||||
pub fn mul_rr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
|
||||
self.emit(Inst::AluRmiR {
|
||||
size: size.into(),
|
||||
op: AluRmiROpcode::Mul,
|
||||
src1: dst.into(),
|
||||
src2: src.into(),
|
||||
dst: dst.into(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Add instruction variants.
|
||||
pub fn add(&mut self, src: Operand, dst: Operand, size: OperandSize) {
|
||||
match &(src, dst) {
|
||||
|
||||
@@ -139,6 +139,19 @@ impl Masm for MacroAssembler {
|
||||
self.asm.sub(src, dst, size);
|
||||
}
|
||||
|
||||
fn mul(&mut self, dst: RegImm, lhs: RegImm, rhs: RegImm, size: OperandSize) {
|
||||
let (src, dst): (Operand, Operand) = if dst == lhs {
|
||||
(rhs.into(), dst.into())
|
||||
} else {
|
||||
panic!(
|
||||
"the destination and first source argument must be the same, dst={:?}, lhs={:?}",
|
||||
dst, lhs
|
||||
);
|
||||
};
|
||||
|
||||
self.asm.mul(src, dst, size);
|
||||
}
|
||||
|
||||
fn epilogue(&mut self, locals_size: u32) {
|
||||
assert!(self.sp_offset == locals_size);
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ pub(crate) trait MacroAssembler {
|
||||
/// Perform subtraction operation.
|
||||
fn sub(&mut self, dst: RegImm, lhs: RegImm, rhs: RegImm, size: OperandSize);
|
||||
|
||||
/// Perform multiplication operation.
|
||||
fn mul(&mut self, dst: RegImm, lhs: RegImm, rhs: RegImm, size: OperandSize);
|
||||
|
||||
/// Push the register to the stack, returning the offset.
|
||||
fn push(&mut self, src: Reg) -> u32;
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ macro_rules! def_unsupported {
|
||||
(emit I32Add $($rest:tt)*) => {};
|
||||
(emit I64Add $($rest:tt)*) => {};
|
||||
(emit I32Sub $($rest:tt)*) => {};
|
||||
(emit I32Mul $($rest:tt)*) => {};
|
||||
(emit I64Mul $($rest:tt)*) => {};
|
||||
(emit I64Sub $($rest:tt)*) => {};
|
||||
(emit LocalGet $($rest:tt)*) => {};
|
||||
(emit LocalSet $($rest:tt)*) => {};
|
||||
@@ -86,6 +88,20 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_i32_mul(&mut self) {
|
||||
self.context
|
||||
.i32_binop(&mut self.regalloc, &mut |masm: &mut M, dst, src, size| {
|
||||
masm.mul(dst, dst, src, size);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_i64_mul(&mut self) {
|
||||
self.context
|
||||
.i64_binop(&mut self.regalloc, &mut |masm: &mut M, dst, src, size| {
|
||||
masm.mul(dst, dst, src, size);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_end(&mut self) {}
|
||||
|
||||
fn visit_local_get(&mut self, index: u32) {
|
||||
|
||||
Reference in New Issue
Block a user