Skip to content

Commit 4d954f5

Browse files
authored
winch: Add support for <i32|i64>.rem_* WebAssembly instructions (bytecodealliance#5823)
This commit adds support for i32 and i64 remainder instructions for x64.
1 parent c26a65a commit 4d954f5

File tree

25 files changed

+579
-4
lines changed

25 files changed

+579
-4
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
abi::local::LocalSlot,
88
codegen::CodeGenContext,
99
isa::reg::Reg,
10-
masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm},
10+
masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm, RemKind},
1111
};
1212
use cranelift_codegen::{settings, Final, MachBufferFinalized};
1313

@@ -156,6 +156,10 @@ impl Masm for MacroAssembler {
156156
todo!()
157157
}
158158

159+
fn rem(&mut self, _context: &mut CodeGenContext, _kind: RemKind, _size: OperandSize) {
160+
todo!()
161+
}
162+
159163
fn zero(&mut self, reg: Reg) {
160164
self.asm.load_constant(0, reg);
161165
}

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::{
44
isa::reg::Reg,
5-
masm::{DivKind, OperandSize},
5+
masm::{DivKind, OperandSize, RemKind},
66
};
77
use cranelift_codegen::{
88
isa::x64::{
@@ -73,6 +73,15 @@ impl From<DivKind> for DivOrRemKind {
7373
}
7474
}
7575

76+
impl From<RemKind> for DivOrRemKind {
77+
fn from(kind: RemKind) -> Self {
78+
match kind {
79+
RemKind::Signed => DivOrRemKind::SignedRem,
80+
RemKind::Unsigned => DivOrRemKind::UnsignedRem,
81+
}
82+
}
83+
}
84+
7685
/// Low level assembler implementation for x64.
7786
pub(crate) struct Assembler {
7887
/// The machine instruction buffer.
@@ -299,6 +308,26 @@ impl Assembler {
299308
});
300309
}
301310

311+
/// Signed/unsigned remainder.
312+
///
313+
/// Emits a sequence of instructions to ensure the correctness of the
314+
/// division invariants and ultimately calculate the remainder.
315+
/// This function assumes that the
316+
/// caller has correctly allocated the dividend as `(rdx:rax)` and
317+
/// accounted for the remainder to be stored in `rdx`.
318+
pub fn rem(&mut self, divisor: Reg, dst: (Reg, Reg), kind: RemKind, size: OperandSize) {
319+
self.emit(Inst::CheckedDivOrRemSeq {
320+
kind: kind.into(),
321+
size: size.into(),
322+
divisor: divisor.into(),
323+
dividend_lo: dst.0.into(),
324+
dividend_hi: dst.1.into(),
325+
dst_quotient: dst.0.into(),
326+
dst_remainder: dst.1.into(),
327+
tmp: None,
328+
});
329+
}
330+
302331
/// Multiply immediate and register.
303332
pub fn mul_ir(&mut self, imm: i32, dst: Reg, size: OperandSize) {
304333
let imm = RegMemImm::imm(imm as u32);

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::{
44
regs::{self, rbp, rsp},
55
};
66
use crate::isa::reg::Reg;
7-
use crate::masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm};
7+
use crate::masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm, RemKind};
88
use crate::{abi::LocalSlot, codegen::CodeGenContext, stack::Val};
99
use cranelift_codegen::{isa::x64::settings as x64_settings, settings, Final, MachBufferFinalized};
1010

@@ -174,6 +174,28 @@ impl Masm for MacroAssembler {
174174
context.stack.push(Val::reg(rax));
175175
}
176176

177+
fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize) {
178+
// Allocate rdx:rax.
179+
let rdx = context.gpr(regs::rdx(), self);
180+
let rax = context.gpr(regs::rax(), self);
181+
182+
// Allocate the divisor, which can be any gpr.
183+
let divisor = context.pop_to_reg(self, size);
184+
185+
// Mark rax as allocatable.
186+
context.regalloc.free_gpr(rax);
187+
// Move the top value to rax.
188+
let rax = context.pop_to_named_reg(self, rax, size);
189+
self.asm.rem(divisor, (rax, rdx), kind, size);
190+
191+
// Free the divisor and rax.
192+
context.free_gpr(divisor);
193+
context.free_gpr(rax);
194+
195+
// Push the remainder.
196+
context.stack.push(Val::reg(rdx));
197+
}
198+
177199
fn epilogue(&mut self, locals_size: u32) {
178200
assert!(self.sp_offset == locals_size);
179201

winch/codegen/src/masm.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ pub(crate) enum DivKind {
1313
Unsigned,
1414
}
1515

16+
/// Remainder kind.
17+
pub(crate) enum RemKind {
18+
/// Signed remainder.
19+
Signed,
20+
/// Unsigned remainder.
21+
Unsigned,
22+
}
23+
1624
/// Operand size, in bits.
1725
#[derive(Copy, Clone, Eq, PartialEq)]
1826
pub(crate) enum OperandSize {
@@ -116,6 +124,9 @@ pub(crate) trait MacroAssembler {
116124
/// functions.
117125
fn div(&mut self, context: &mut CodeGenContext, kind: DivKind, size: OperandSize);
118126

127+
/// Calculate remainder.
128+
fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize);
129+
119130
/// Push the register to the stack, returning the offset.
120131
fn push(&mut self, src: Reg) -> u32;
121132

winch/codegen/src/visitor.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! machine code emitter.
66
77
use crate::codegen::CodeGen;
8-
use crate::masm::{DivKind, MacroAssembler, OperandSize, RegImm};
8+
use crate::masm::{DivKind, MacroAssembler, OperandSize, RegImm, RemKind};
99
use crate::stack::Val;
1010
use wasmparser::ValType;
1111
use wasmparser::VisitOperator;
@@ -41,6 +41,10 @@ macro_rules! def_unsupported {
4141
(emit I32DivU $($rest:tt)*) => {};
4242
(emit I64DivS $($rest:tt)*) => {};
4343
(emit I64DivU $($rest:tt)*) => {};
44+
(emit I64RemU $($rest:tt)*) => {};
45+
(emit I64RemS $($rest:tt)*) => {};
46+
(emit I32RemU $($rest:tt)*) => {};
47+
(emit I32RemS $($rest:tt)*) => {};
4448
(emit I64Mul $($rest:tt)*) => {};
4549
(emit I64Sub $($rest:tt)*) => {};
4650
(emit LocalGet $($rest:tt)*) => {};
@@ -134,6 +138,34 @@ where
134138
self.masm.div(&mut self.context, Unsigned, S64);
135139
}
136140

141+
fn visit_i32_rem_s(&mut self) {
142+
use OperandSize::*;
143+
use RemKind::*;
144+
145+
self.masm.rem(&mut self.context, Signed, S32);
146+
}
147+
148+
fn visit_i32_rem_u(&mut self) {
149+
use OperandSize::*;
150+
use RemKind::*;
151+
152+
self.masm.rem(&mut self.context, Unsigned, S32);
153+
}
154+
155+
fn visit_i64_rem_s(&mut self) {
156+
use OperandSize::*;
157+
use RemKind::*;
158+
159+
self.masm.rem(&mut self.context, Signed, S64);
160+
}
161+
162+
fn visit_i64_rem_u(&mut self) {
163+
use OperandSize::*;
164+
use RemKind::*;
165+
166+
self.masm.rem(&mut self.context, Unsigned, S64);
167+
}
168+
137169
fn visit_end(&mut self) {}
138170

139171
fn visit_local_get(&mut self, index: u32) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;;! target = "x86_64"
2+
3+
(module
4+
(func (result i32)
5+
(i32.const 7)
6+
(i32.const 5)
7+
(i32.rem_s)
8+
)
9+
)
10+
;; 0: 55 push rbp
11+
;; 1: 4889e5 mov rbp, rsp
12+
;; 4: b905000000 mov ecx, 5
13+
;; 9: b807000000 mov eax, 7
14+
;; e: 83f900 cmp ecx, 0
15+
;; 11: 0f8502000000 jne 0x19
16+
;; 17: 0f0b ud2
17+
;; 19: 83f9ff cmp ecx, -1
18+
;; 1c: 0f850a000000 jne 0x2c
19+
;; 22: b800000000 mov eax, 0
20+
;; 27: e903000000 jmp 0x2f
21+
;; 2c: 99 cdq
22+
;; 2d: f7f9 idiv ecx
23+
;; 2f: 4889d0 mov rax, rdx
24+
;; 32: 5d pop rbp
25+
;; 33: c3 ret
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;;! target = "x86_64"
2+
3+
(module
4+
(func (result i32)
5+
(i32.const 1)
6+
(i32.const 0)
7+
(i32.rem_s)
8+
)
9+
)
10+
;; 0: 55 push rbp
11+
;; 1: 4889e5 mov rbp, rsp
12+
;; 4: b900000000 mov ecx, 0
13+
;; 9: b801000000 mov eax, 1
14+
;; e: 83f900 cmp ecx, 0
15+
;; 11: 0f8502000000 jne 0x19
16+
;; 17: 0f0b ud2
17+
;; 19: 83f9ff cmp ecx, -1
18+
;; 1c: 0f850a000000 jne 0x2c
19+
;; 22: b800000000 mov eax, 0
20+
;; 27: e903000000 jmp 0x2f
21+
;; 2c: 99 cdq
22+
;; 2d: f7f9 idiv ecx
23+
;; 2f: 4889d0 mov rax, rdx
24+
;; 32: 5d pop rbp
25+
;; 33: c3 ret
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;;! target = "x86_64"
2+
3+
(module
4+
(func (result i32)
5+
(i32.const 0x80000000)
6+
(i32.const -1)
7+
(i32.rem_s)
8+
)
9+
)
10+
;; 0: 55 push rbp
11+
;; 1: 4889e5 mov rbp, rsp
12+
;; 4: b9ffffffff mov ecx, 0xffffffff
13+
;; 9: b800000080 mov eax, 0x80000000
14+
;; e: 83f900 cmp ecx, 0
15+
;; 11: 0f8502000000 jne 0x19
16+
;; 17: 0f0b ud2
17+
;; 19: 83f9ff cmp ecx, -1
18+
;; 1c: 0f850a000000 jne 0x2c
19+
;; 22: b800000000 mov eax, 0
20+
;; 27: e903000000 jmp 0x2f
21+
;; 2c: 99 cdq
22+
;; 2d: f7f9 idiv ecx
23+
;; 2f: 4889d0 mov rax, rdx
24+
;; 32: 5d pop rbp
25+
;; 33: c3 ret
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
;;! target = "x86_64"
2+
3+
(module
4+
(func (param i32) (param i32) (result i32)
5+
(local.get 0)
6+
(local.get 1)
7+
(i32.rem_s)
8+
)
9+
)
10+
;; 0: 55 push rbp
11+
;; 1: 4889e5 mov rbp, rsp
12+
;; 4: 4883ec08 sub rsp, 8
13+
;; 8: 897c2404 mov dword ptr [rsp + 4], edi
14+
;; c: 893424 mov dword ptr [rsp], esi
15+
;; f: 8b0c24 mov ecx, dword ptr [rsp]
16+
;; 12: 8b442404 mov eax, dword ptr [rsp + 4]
17+
;; 16: 83f900 cmp ecx, 0
18+
;; 19: 0f8502000000 jne 0x21
19+
;; 1f: 0f0b ud2
20+
;; 21: 83f9ff cmp ecx, -1
21+
;; 24: 0f850a000000 jne 0x34
22+
;; 2a: b800000000 mov eax, 0
23+
;; 2f: e903000000 jmp 0x37
24+
;; 34: 99 cdq
25+
;; 35: f7f9 idiv ecx
26+
;; 37: 4889d0 mov rax, rdx
27+
;; 3a: 4883c408 add rsp, 8
28+
;; 3e: 5d pop rbp
29+
;; 3f: c3 ret
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;;! target = "x86_64"
2+
3+
(module
4+
(func (result i32)
5+
(i32.const 0)
6+
(i32.const 0)
7+
(i32.rem_s)
8+
)
9+
)
10+
;; 0: 55 push rbp
11+
;; 1: 4889e5 mov rbp, rsp
12+
;; 4: b900000000 mov ecx, 0
13+
;; 9: b800000000 mov eax, 0
14+
;; e: 83f900 cmp ecx, 0
15+
;; 11: 0f8502000000 jne 0x19
16+
;; 17: 0f0b ud2
17+
;; 19: 83f9ff cmp ecx, -1
18+
;; 1c: 0f850a000000 jne 0x2c
19+
;; 22: b800000000 mov eax, 0
20+
;; 27: e903000000 jmp 0x2f
21+
;; 2c: 99 cdq
22+
;; 2d: f7f9 idiv ecx
23+
;; 2f: 4889d0 mov rax, rdx
24+
;; 32: 5d pop rbp
25+
;; 33: c3 ret

0 commit comments

Comments
 (0)