Skip to content

Commit 204c3f8

Browse files
authored
Fix Memory64Lowering table.copy size wrapping for mixed tables (#8319)
`visitTableCopy` wrapped `curr->size` using only the dest table's type, but the wasm spec (and `child-typer.h`) defines the size type as i64 only when **both** source and dest tables are 64-bit. When copying between a 64-bit and a 32-bit table, the size is i32, but wrapping checks only the dest table — causing an assertion failure (`assert(ptr->type == Type::i64)`) when dest is 64-bit but source is 32-bit. **Fix:** Check both tables before wrapping the size operand, matching the type logic in `child-typer.h`.
1 parent 0c9f9c1 commit 204c3f8

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/passes/Memory64Lowering.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,12 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
278278
void visitTableCopy(TableCopy* curr) {
279279
wrapTableAddress64(curr->dest, curr->destTable);
280280
wrapTableAddress64(curr->source, curr->sourceTable);
281-
wrapTableAddress64(curr->size, curr->destTable);
281+
// The size type is i64 only when both tables are 64-bit.
282+
auto& module = *getModule();
283+
if (module.getTable(curr->destTable)->is64() &&
284+
module.getTable(curr->sourceTable)->is64()) {
285+
wrapAddress64(curr->size, curr->destTable, true);
286+
}
282287
}
283288

284289
void visitTableInit(TableInit* curr) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
3+
;; RUN: foreach %s %t wasm-opt --memory64-lowering --enable-memory64 --enable-reference-types --enable-bulk-memory -S -o - | filecheck %s
4+
5+
;; Test that table.copy with mixed 32/64-bit tables correctly handles the
6+
;; size operand type.
7+
(module
8+
;; CHECK: (type $0 (func))
9+
10+
;; CHECK: (table $t64 10 funcref)
11+
(table $t64 i64 10 funcref)
12+
;; CHECK: (table $t32 10 funcref)
13+
(table $t32 10 funcref)
14+
15+
;; CHECK: (func $table-copy-mixed-64-to-32
16+
;; CHECK-NEXT: (table.copy $t32 $t64
17+
;; CHECK-NEXT: (i32.const 0)
18+
;; CHECK-NEXT: (i32.wrap_i64
19+
;; CHECK-NEXT: (i64.const 0)
20+
;; CHECK-NEXT: )
21+
;; CHECK-NEXT: (i32.const 5)
22+
;; CHECK-NEXT: )
23+
;; CHECK-NEXT: )
24+
(func $table-copy-mixed-64-to-32
25+
;; Copy from 64-bit table to 32-bit table. The size is i32 because not
26+
;; both tables are 64-bit, so no wrapping of size should occur.
27+
(table.copy $t32 $t64 (i32.const 0) (i64.const 0) (i32.const 5))
28+
)
29+
30+
;; CHECK: (func $table-copy-mixed-32-to-64
31+
;; CHECK-NEXT: (table.copy $t64 $t32
32+
;; CHECK-NEXT: (i32.wrap_i64
33+
;; CHECK-NEXT: (i64.const 0)
34+
;; CHECK-NEXT: )
35+
;; CHECK-NEXT: (i32.const 0)
36+
;; CHECK-NEXT: (i32.const 5)
37+
;; CHECK-NEXT: )
38+
;; CHECK-NEXT: )
39+
(func $table-copy-mixed-32-to-64
40+
;; Copy from 32-bit table to 64-bit table. The size is i32 because not
41+
;; both tables are 64-bit, so no wrapping of size should occur.
42+
(table.copy $t64 $t32 (i64.const 0) (i32.const 0) (i32.const 5))
43+
)
44+
45+
;; CHECK: (func $table-copy-both-64
46+
;; CHECK-NEXT: (table.copy $t64 $t64
47+
;; CHECK-NEXT: (i32.wrap_i64
48+
;; CHECK-NEXT: (i64.const 0)
49+
;; CHECK-NEXT: )
50+
;; CHECK-NEXT: (i32.wrap_i64
51+
;; CHECK-NEXT: (i64.const 5)
52+
;; CHECK-NEXT: )
53+
;; CHECK-NEXT: (i32.wrap_i64
54+
;; CHECK-NEXT: (i64.const 3)
55+
;; CHECK-NEXT: )
56+
;; CHECK-NEXT: )
57+
;; CHECK-NEXT: )
58+
(func $table-copy-both-64
59+
;; Copy between same 64-bit table. All operands including size are i64
60+
;; and should be wrapped.
61+
(table.copy $t64 $t64 (i64.const 0) (i64.const 5) (i64.const 3))
62+
)
63+
)

0 commit comments

Comments
 (0)