Browse Source

winch: Add support for integer multiplication in x64. (#5769)

This commit adds support for the `<i32|i64>.mul` WebAssembly instructions in x64.
pull/5772/head
Saúl Cabrera 2 years ago
committed by GitHub
parent
commit
91c8114f00
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      winch/codegen/src/isa/aarch64/masm.rs
  2. 44
      winch/codegen/src/isa/x64/asm.rs
  3. 13
      winch/codegen/src/isa/x64/masm.rs
  4. 3
      winch/codegen/src/masm.rs
  5. 16
      winch/codegen/src/visitor.rs
  6. 15
      winch/filetests/filetests/x64/i32_mul/const.wat
  7. 33
      winch/filetests/filetests/x64/i32_mul/locals.wat
  8. 14
      winch/filetests/filetests/x64/i32_mul/max.wat
  9. 15
      winch/filetests/filetests/x64/i32_mul/max_one.wat
  10. 15
      winch/filetests/filetests/x64/i32_mul/mixed.wat
  11. 21
      winch/filetests/filetests/x64/i32_mul/params.wat
  12. 15
      winch/filetests/filetests/x64/i32_mul/signed.wat
  13. 15
      winch/filetests/filetests/x64/i32_mul/unsigned_with_zero.wat
  14. 15
      winch/filetests/filetests/x64/i64_mul/const.wat
  15. 35
      winch/filetests/filetests/x64/i64_mul/locals.wat
  16. 15
      winch/filetests/filetests/x64/i64_mul/max.wat
  17. 16
      winch/filetests/filetests/x64/i64_mul/max_one.wat
  18. 15
      winch/filetests/filetests/x64/i64_mul/mixed.wat
  19. 21
      winch/filetests/filetests/x64/i64_mul/params.wat
  20. 15
      winch/filetests/filetests/x64/i64_mul/signed.wat
  21. 15
      winch/filetests/filetests/x64/i64_mul/unsigned_with_zero.wat

4
winch/codegen/src/isa/aarch64/masm.rs

@ -147,6 +147,10 @@ impl Masm for MacroAssembler {
todo!() todo!()
} }
fn mul(&mut self, _dst: RegImm, _lhs: RegImm, _rhs: RegImm, _size: OperandSize) {
todo!()
}
fn zero(&mut self, reg: Reg) { fn zero(&mut self, reg: Reg) {
self.asm.load_constant(0, reg); self.asm.load_constant(0, reg);
} }

44
winch/codegen/src/isa/x64/asm.rs

@ -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. /// Add instruction variants.
pub fn add(&mut self, src: Operand, dst: Operand, size: OperandSize) { pub fn add(&mut self, src: Operand, dst: Operand, size: OperandSize) {
match &(src, dst) { match &(src, dst) {

13
winch/codegen/src/isa/x64/masm.rs

@ -139,6 +139,19 @@ impl Masm for MacroAssembler {
self.asm.sub(src, dst, size); 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) { fn epilogue(&mut self, locals_size: u32) {
assert!(self.sp_offset == locals_size); assert!(self.sp_offset == locals_size);

3
winch/codegen/src/masm.rs

@ -91,6 +91,9 @@ pub(crate) trait MacroAssembler {
/// Perform subtraction operation. /// Perform subtraction operation.
fn sub(&mut self, dst: RegImm, lhs: RegImm, rhs: RegImm, size: OperandSize); 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. /// Push the register to the stack, returning the offset.
fn push(&mut self, src: Reg) -> u32; fn push(&mut self, src: Reg) -> u32;

16
winch/codegen/src/visitor.rs

@ -36,6 +36,8 @@ macro_rules! def_unsupported {
(emit I32Add $($rest:tt)*) => {}; (emit I32Add $($rest:tt)*) => {};
(emit I64Add $($rest:tt)*) => {}; (emit I64Add $($rest:tt)*) => {};
(emit I32Sub $($rest:tt)*) => {}; (emit I32Sub $($rest:tt)*) => {};
(emit I32Mul $($rest:tt)*) => {};
(emit I64Mul $($rest:tt)*) => {};
(emit I64Sub $($rest:tt)*) => {}; (emit I64Sub $($rest:tt)*) => {};
(emit LocalGet $($rest:tt)*) => {}; (emit LocalGet $($rest:tt)*) => {};
(emit LocalSet $($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_end(&mut self) {}
fn visit_local_get(&mut self, index: u32) { fn visit_local_get(&mut self, index: u32) {

15
winch/filetests/filetests/x64/i32_mul/const.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i32)
(i32.const 10)
(i32.const 20)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: b80a000000 mov eax, 0xa
;; 9: 6bc014 imul eax, eax, 0x14
;; c: 5d pop rbp
;; d: c3 ret

33
winch/filetests/filetests/x64/i32_mul/locals.wat

@ -0,0 +1,33 @@
;;! target = "x86_64"
(module
(func (result i32)
(local $foo i32)
(local $bar i32)
(i32.const 10)
(local.set $foo)
(i32.const 20)
(local.set $bar)
(local.get $foo)
(local.get $bar)
i32.mul
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 4883ec08 sub rsp, 8
;; 8: 48c7042400000000 mov qword ptr [rsp], 0
;; 10: b80a000000 mov eax, 0xa
;; 15: 89442404 mov dword ptr [rsp + 4], eax
;; 19: b814000000 mov eax, 0x14
;; 1e: 890424 mov dword ptr [rsp], eax
;; 21: 8b0424 mov eax, dword ptr [rsp]
;; 24: 8b4c2404 mov ecx, dword ptr [rsp + 4]
;; 28: 0fafc8 imul ecx, eax
;; 2b: 4889c8 mov rax, rcx
;; 2e: 4883c408 add rsp, 8
;; 32: 5d pop rbp
;; 33: c3 ret

14
winch/filetests/filetests/x64/i32_mul/max.wat

@ -0,0 +1,14 @@
;;! target = "x86_64"
(module
(func (result i32)
(i32.const 0x7fffffff)
(i32.const -1)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: b8ffffff7f mov eax, 0x7fffffff
;; 9: 6bc0ff imul eax, eax, -1
;; c: 5d pop rbp
;; d: c3 ret

15
winch/filetests/filetests/x64/i32_mul/max_one.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i32)
(i32.const 0x80000000)
(i32.const -1)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: b800000080 mov eax, 0x80000000
;; 9: 6bc0ff imul eax, eax, -1
;; c: 5d pop rbp
;; d: c3 ret

15
winch/filetests/filetests/x64/i32_mul/mixed.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i32)
(i32.const -1)
(i32.const 1)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: b8ffffffff mov eax, 0xffffffff
;; 9: 6bc001 imul eax, eax, 1
;; c: 5d pop rbp
;; d: c3 ret

21
winch/filetests/filetests/x64/i32_mul/params.wat

@ -0,0 +1,21 @@
;;! target = "x86_64"
(module
(func (param i32) (param i32) (result i32)
(local.get 0)
(local.get 1)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 4883ec08 sub rsp, 8
;; 8: 897c2404 mov dword ptr [rsp + 4], edi
;; c: 893424 mov dword ptr [rsp], esi
;; f: 8b0424 mov eax, dword ptr [rsp]
;; 12: 8b4c2404 mov ecx, dword ptr [rsp + 4]
;; 16: 0fafc8 imul ecx, eax
;; 19: 4889c8 mov rax, rcx
;; 1c: 4883c408 add rsp, 8
;; 20: 5d pop rbp
;; 21: c3 ret

15
winch/filetests/filetests/x64/i32_mul/signed.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i32)
(i32.const -1)
(i32.const -1)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: b8ffffffff mov eax, 0xffffffff
;; 9: 6bc0ff imul eax, eax, -1
;; c: 5d pop rbp
;; d: c3 ret

15
winch/filetests/filetests/x64/i32_mul/unsigned_with_zero.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i32)
(i32.const 1)
(i32.const 0)
(i32.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: b801000000 mov eax, 1
;; 9: 6bc000 imul eax, eax, 0
;; c: 5d pop rbp
;; d: c3 ret

15
winch/filetests/filetests/x64/i64_mul/const.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i64)
(i64.const 10)
(i64.const 20)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 48c7c00a000000 mov rax, 0xa
;; b: 486bc014 imul rax, rax, 0x14
;; f: 5d pop rbp
;; 10: c3 ret

35
winch/filetests/filetests/x64/i64_mul/locals.wat

@ -0,0 +1,35 @@
;;! target = "x86_64"
(module
(func (result i64)
(local $foo i64)
(local $bar i64)
(i64.const 10)
(local.set $foo)
(i64.const 20)
(local.set $bar)
(local.get $foo)
(local.get $bar)
i64.mul
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 4883ec10 sub rsp, 0x10
;; 8: 4531db xor r11d, r11d
;; b: 4c895c2408 mov qword ptr [rsp + 8], r11
;; 10: 4c891c24 mov qword ptr [rsp], r11
;; 14: 48c7c00a000000 mov rax, 0xa
;; 1b: 4889442408 mov qword ptr [rsp + 8], rax
;; 20: 48c7c014000000 mov rax, 0x14
;; 27: 48890424 mov qword ptr [rsp], rax
;; 2b: 488b0424 mov rax, qword ptr [rsp]
;; 2f: 488b4c2408 mov rcx, qword ptr [rsp + 8]
;; 34: 480fafc8 imul rcx, rax
;; 38: 4889c8 mov rax, rcx
;; 3b: 4883c410 add rsp, 0x10
;; 3f: 5d pop rbp
;; 40: c3 ret

15
winch/filetests/filetests/x64/i64_mul/max.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i64)
(i64.const 0x7fffffffffffffff)
(i64.const -1)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 48b8ffffffffffffff7f
;; movabs rax, 0x7fffffffffffffff
;; e: 486bc0ff imul rax, rax, -1
;; 12: 5d pop rbp
;; 13: c3 ret

16
winch/filetests/filetests/x64/i64_mul/max_one.wat

@ -0,0 +1,16 @@
;;! target = "x86_64"
(module
(func (result i64)
(i64.const 0x8000000000000000)
(i64.const -1)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 48b80000000000000080
;; movabs rax, 0x8000000000000000
;; e: 486bc0ff imul rax, rax, -1
;; 12: 5d pop rbp
;; 13: c3 ret

15
winch/filetests/filetests/x64/i64_mul/mixed.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i64)
(i64.const -1)
(i64.const 1)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 48c7c0ffffffff mov rax, 0xffffffffffffffff
;; b: 486bc001 imul rax, rax, 1
;; f: 5d pop rbp
;; 10: c3 ret

21
winch/filetests/filetests/x64/i64_mul/params.wat

@ -0,0 +1,21 @@
;;! target = "x86_64"
(module
(func (param i64) (param i64) (result i64)
(local.get 0)
(local.get 1)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 4883ec10 sub rsp, 0x10
;; 8: 48897c2408 mov qword ptr [rsp + 8], rdi
;; d: 48893424 mov qword ptr [rsp], rsi
;; 11: 488b0424 mov rax, qword ptr [rsp]
;; 15: 488b4c2408 mov rcx, qword ptr [rsp + 8]
;; 1a: 480fafc8 imul rcx, rax
;; 1e: 4889c8 mov rax, rcx
;; 21: 4883c410 add rsp, 0x10
;; 25: 5d pop rbp
;; 26: c3 ret

15
winch/filetests/filetests/x64/i64_mul/signed.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i64)
(i64.const -1)
(i64.const -1)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 48c7c0ffffffff mov rax, 0xffffffffffffffff
;; b: 486bc0ff imul rax, rax, -1
;; f: 5d pop rbp
;; 10: c3 ret

15
winch/filetests/filetests/x64/i64_mul/unsigned_with_zero.wat

@ -0,0 +1,15 @@
;;! target = "x86_64"
(module
(func (result i64)
(i64.const 1)
(i64.const 0)
(i64.mul)
)
)
;; 0: 55 push rbp
;; 1: 4889e5 mov rbp, rsp
;; 4: 48c7c001000000 mov rax, 1
;; b: 486bc000 imul rax, rax, 0
;; f: 5d pop rbp
;; 10: c3 ret
Loading…
Cancel
Save