Skip to content

Commit 944ae82

Browse files
authored
Winch: Fix issue with multivalue returns (bytecodealliance#10370)
1 parent c7cbdf0 commit 944ae82

File tree

4 files changed

+120
-17
lines changed

4 files changed

+120
-17
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
;;! target = "x86_64"
2+
;;! test = "winch"
3+
4+
(module
5+
(func (export "") (param v128) (result i64 v128 i64)
6+
i64.const 0
7+
local.get 0
8+
i64.const 0
9+
)
10+
)
11+
;; wasm[0]::function[0]:
12+
;; pushq %rbp
13+
;; movq %rsp, %rbp
14+
;; movq 8(%rsi), %r11
15+
;; movq 0x10(%r11), %r11
16+
;; addq $0x48, %r11
17+
;; cmpq %rsp, %r11
18+
;; ja 0x90
19+
;; 1c: movq %rsi, %r14
20+
;; subq $0x30, %rsp
21+
;; movq %rsi, 0x28(%rsp)
22+
;; movq %rdx, 0x20(%rsp)
23+
;; movdqu %xmm0, 0x10(%rsp)
24+
;; movq %rdi, 8(%rsp)
25+
;; movq $0, %rax
26+
;; movdqu 0x10(%rsp), %xmm15
27+
;; subq $0x10, %rsp
28+
;; movdqu %xmm15, (%rsp)
29+
;; subq $8, %rsp
30+
;; movq 8(%rsp), %r11
31+
;; movq %r11, (%rsp)
32+
;; movq 0x10(%rsp), %r11
33+
;; movq %r11, 8(%rsp)
34+
;; movq $0, 0x10(%rsp)
35+
;; movq 0x20(%rsp), %rcx
36+
;; movdqu (%rsp), %xmm15
37+
;; addq $0x10, %rsp
38+
;; movdqu %xmm15, (%rcx)
39+
;; popq %r11
40+
;; movq %r11, 0x10(%rcx)
41+
;; addq $0x30, %rsp
42+
;; popq %rbp
43+
;; retq
44+
;; 90: ud2
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
;;! simd = true
2+
3+
;; See https://github.com/bytecodealliance/wasmtime/issues/10357
4+
5+
(module
6+
(func (export "test") (result i64 v128 v128)
7+
i32.const 0
8+
v128.const i32x4 0x00000000 0x00000000 0x68732efe 0x74727473
9+
i64.const 1
10+
call 1
11+
)
12+
13+
(func (param i32 v128 i64) (result i64 v128 v128)
14+
i64.const 0
15+
local.get 1
16+
v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000
17+
)
18+
)
19+
20+
(assert_return (invoke "test") (i64.const 0) (v128.const i32x4 0x00000000 0x00000000 0x68732efe 0x74727473) (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000))

tests/misc_testsuite/winch/simd_multivalue.wast

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@
77
;; test 0 consts
88
(module (func (export "consts") (result v128) (result v128) (v128.const i64x2 0 0) (v128.const i64x2 0 0)))
99
(assert_return (invoke "consts") (v128.const i64x2 0 0) (v128.const i64x2 0 0))
10+
11+
;; test case where vector is neither the first return value nor the last return value
12+
(module
13+
(func (export "not-first-nor-last") (param v128) (result i64 v128 i64)
14+
i64.const 0
15+
local.get 0
16+
i64.const 0
17+
)
18+
)
19+
(assert_return (invoke "not-first-nor-last" (v128.const i32x4 1 2 3 4)) (i64.const 0) (v128.const i32x4 1 2 3 4) (i64.const 0))

winch/codegen/src/masm.rs

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,31 +1471,60 @@ pub(crate) trait MacroAssembler {
14711471
let word_bytes = <Self::ABI as abi::ABI>::word_bytes();
14721472
let scratch = scratch!(Self);
14731473

1474-
let mut dst_offs = dst.as_u32() - bytes;
1475-
let mut src_offs = src.as_u32() - bytes;
1476-
14771474
let word_bytes = word_bytes as u32;
1478-
while remaining >= word_bytes {
1479-
remaining -= word_bytes;
1480-
dst_offs += word_bytes;
1481-
src_offs += word_bytes;
14821475

1483-
self.load_ptr(
1484-
self.address_from_sp(SPOffset::from_u32(src_offs))?,
1485-
writable!(scratch),
1486-
)?;
1487-
self.store_ptr(
1488-
scratch.into(),
1489-
self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1490-
)?;
1476+
let mut dst_offs;
1477+
let mut src_offs;
1478+
match direction {
1479+
MemMoveDirection::LowToHigh => {
1480+
dst_offs = dst.as_u32() - bytes;
1481+
src_offs = src.as_u32() - bytes;
1482+
while remaining >= word_bytes {
1483+
remaining -= word_bytes;
1484+
dst_offs += word_bytes;
1485+
src_offs += word_bytes;
1486+
1487+
self.load_ptr(
1488+
self.address_from_sp(SPOffset::from_u32(src_offs))?,
1489+
writable!(scratch),
1490+
)?;
1491+
self.store_ptr(
1492+
scratch.into(),
1493+
self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1494+
)?;
1495+
}
1496+
}
1497+
MemMoveDirection::HighToLow => {
1498+
// Go from the end to the beginning to handle overlapping addresses.
1499+
src_offs = src.as_u32();
1500+
dst_offs = dst.as_u32();
1501+
while remaining >= word_bytes {
1502+
self.load_ptr(
1503+
self.address_from_sp(SPOffset::from_u32(src_offs))?,
1504+
writable!(scratch),
1505+
)?;
1506+
self.store_ptr(
1507+
scratch.into(),
1508+
self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1509+
)?;
1510+
1511+
remaining -= word_bytes;
1512+
src_offs -= word_bytes;
1513+
dst_offs -= word_bytes;
1514+
}
1515+
}
14911516
}
14921517

14931518
if remaining > 0 {
14941519
let half_word = word_bytes / 2;
14951520
let ptr_size = OperandSize::from_bytes(half_word as u8);
14961521
debug_assert!(remaining == half_word);
1497-
dst_offs += half_word;
1498-
src_offs += half_word;
1522+
// Need to move the offsets ahead in the `LowToHigh` case to
1523+
// compensate for the initial subtraction of `bytes`.
1524+
if direction == MemMoveDirection::LowToHigh {
1525+
dst_offs += half_word;
1526+
src_offs += half_word;
1527+
}
14991528

15001529
self.load(
15011530
self.address_from_sp(SPOffset::from_u32(src_offs))?,

0 commit comments

Comments
 (0)