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:
Saúl Cabrera
2023-02-13 16:20:36 -05:00
committed by GitHub
parent 19f337e29b
commit 91c8114f00
21 changed files with 370 additions and 0 deletions

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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);