diff --git a/src/passes/Memory64Lowering.cpp b/src/passes/Memory64Lowering.cpp index 9d7a2a4252c..e588de2cce5 100644 --- a/src/passes/Memory64Lowering.cpp +++ b/src/passes/Memory64Lowering.cpp @@ -237,7 +237,12 @@ struct Memory64Lowering : public WalkerPass> { void visitTableCopy(TableCopy* curr) { wrapTableAddress64(curr->dest, curr->destTable); wrapTableAddress64(curr->source, curr->sourceTable); - wrapTableAddress64(curr->size, curr->destTable); + // The size type is i64 only when both tables are 64-bit. + auto& module = *getModule(); + if (module.getTable(curr->destTable)->is64() && + module.getTable(curr->sourceTable)->is64()) { + wrapAddress64(curr->size, curr->destTable, true); + } } void visitTableInit(TableInit* curr) { diff --git a/test/lit/passes/memory64-lowering-table-copy.wast b/test/lit/passes/memory64-lowering-table-copy.wast new file mode 100644 index 00000000000..afdaeb9f11f --- /dev/null +++ b/test/lit/passes/memory64-lowering-table-copy.wast @@ -0,0 +1,63 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: foreach %s %t wasm-opt --memory64-lowering --enable-memory64 --enable-reference-types --enable-bulk-memory -S -o - | filecheck %s + +;; Test that table.copy with mixed 32/64-bit tables correctly handles the +;; size operand type. +(module + ;; CHECK: (type $0 (func)) + + ;; CHECK: (table $t64 10 funcref) + (table $t64 i64 10 funcref) + ;; CHECK: (table $t32 10 funcref) + (table $t32 10 funcref) + + ;; CHECK: (func $table-copy-mixed-64-to-32 + ;; CHECK-NEXT: (table.copy $t32 $t64 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $table-copy-mixed-64-to-32 + ;; Copy from 64-bit table to 32-bit table. The size is i32 because not + ;; both tables are 64-bit, so no wrapping of size should occur. + (table.copy $t32 $t64 (i32.const 0) (i64.const 0) (i32.const 5)) + ) + + ;; CHECK: (func $table-copy-mixed-32-to-64 + ;; CHECK-NEXT: (table.copy $t64 $t32 + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $table-copy-mixed-32-to-64 + ;; Copy from 32-bit table to 64-bit table. The size is i32 because not + ;; both tables are 64-bit, so no wrapping of size should occur. + (table.copy $t64 $t32 (i64.const 0) (i32.const 0) (i32.const 5)) + ) + + ;; CHECK: (func $table-copy-both-64 + ;; CHECK-NEXT: (table.copy $t64 $t64 + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $table-copy-both-64 + ;; Copy between same 64-bit table. All operands including size are i64 + ;; and should be wrapped. + (table.copy $t64 $t64 (i64.const 0) (i64.const 5) (i64.const 3)) + ) +)