summaryrefslogtreecommitdiff
path: root/src/passes/Table64Lowering.cpp
diff options
context:
space:
mode:
authorSam Clegg <sbc@chromium.org>2024-05-15 12:53:31 -0700
committerGitHub <noreply@github.com>2024-05-15 12:53:31 -0700
commit2b60f8a212c0e744d0dbf3346498b08c9a27a39e (patch)
treeee80a2e5a894c2af40972c269f2bb69089e9fdc0 /src/passes/Table64Lowering.cpp
parent2cc5e06549a4019eeed7303bfab32b95c32507bc (diff)
downloadbinaryen-2b60f8a212c0e744d0dbf3346498b08c9a27a39e.tar.gz
binaryen-2b60f8a212c0e744d0dbf3346498b08c9a27a39e.tar.bz2
binaryen-2b60f8a212c0e744d0dbf3346498b08c9a27a39e.zip
Add table64 lowering pass (#6595)
Changes to wasm-validator.cpp here are mostly for consistency between elem and data segment validation.
Diffstat (limited to 'src/passes/Table64Lowering.cpp')
-rw-r--r--src/passes/Table64Lowering.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/passes/Table64Lowering.cpp b/src/passes/Table64Lowering.cpp
new file mode 100644
index 000000000..3c4086a01
--- /dev/null
+++ b/src/passes/Table64Lowering.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2024 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Lowers a module with a 64-bit table to one with a 32-bit table.
+//
+// This pass can be deleted once table64 is implemented in Wasm engines:
+// https://github.com/WebAssembly/memory64/issues/51
+//
+
+#include "ir/bits.h"
+#include "ir/import-utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+static Name TABLE_BASE("__table_base");
+static Name TABLE_BASE32("__table_base32");
+
+struct Table64Lowering : public WalkerPass<PostWalker<Table64Lowering>> {
+
+ void wrapAddress64(Expression*& ptr, Name tableName) {
+ if (ptr->type == Type::unreachable) {
+ return;
+ }
+ auto& module = *getModule();
+ auto* table = module.getTable(tableName);
+ if (table->is64()) {
+ assert(ptr->type == Type::i64);
+ ptr = Builder(module).makeUnary(UnaryOp::WrapInt64, ptr);
+ }
+ }
+
+ void extendAddress64(Expression*& ptr, Name tableName) {
+ if (ptr->type == Type::unreachable) {
+ return;
+ }
+ auto& module = *getModule();
+ auto* table = module.getTable(tableName);
+ if (table->is64()) {
+ assert(ptr->type == Type::i64);
+ ptr->type = Type::i32;
+ ptr = Builder(module).makeUnary(UnaryOp::ExtendUInt32, ptr);
+ }
+ }
+
+ void visitTableSize(TableSize* curr) {
+ auto& module = *getModule();
+ auto* table = module.getTable(curr->table);
+ if (table->is64()) {
+ auto* size = static_cast<Expression*>(curr);
+ extendAddress64(size, curr->table);
+ replaceCurrent(size);
+ }
+ }
+
+ void visitTableGrow(TableGrow* curr) {
+ auto& module = *getModule();
+ auto* table = module.getTable(curr->table);
+ if (table->is64()) {
+ wrapAddress64(curr->delta, curr->table);
+ auto* size = static_cast<Expression*>(curr);
+ extendAddress64(size, curr->table);
+ replaceCurrent(size);
+ }
+ }
+
+ void visitTableFill(TableFill* curr) {
+ wrapAddress64(curr->dest, curr->table);
+ wrapAddress64(curr->size, curr->table);
+ }
+
+ void visitTableCopy(TableCopy* curr) {
+ wrapAddress64(curr->dest, curr->destTable);
+ wrapAddress64(curr->source, curr->sourceTable);
+ wrapAddress64(curr->size, curr->destTable);
+ }
+
+ void visitCallIndirect(CallIndirect* curr) {
+ wrapAddress64(curr->target, curr->table);
+ }
+
+ void visitTable(Table* table) {
+ // This is visited last.
+ if (table->is64()) {
+ table->indexType = Type::i32;
+ }
+ }
+
+ void visitElementSegment(ElementSegment* segment) {
+ if (segment->table.isNull()) {
+ // Passive segments don't have any offset to update.
+ return;
+ }
+
+ if (auto* c = segment->offset->dynCast<Const>()) {
+ c->value = Literal(static_cast<uint32_t>(c->value.geti64()));
+ c->type = Type::i32;
+ } else if (auto* get = segment->offset->dynCast<GlobalGet>()) {
+ auto& module = *getModule();
+ auto* g = module.getGlobal(get->name);
+ if (g->imported() && g->base == TABLE_BASE) {
+ ImportInfo info(module);
+ auto* memoryBase32 = info.getImportedGlobal(g->module, TABLE_BASE32);
+ if (!memoryBase32) {
+ Builder builder(module);
+ memoryBase32 = builder
+ .makeGlobal(TABLE_BASE32,
+ Type::i32,
+ builder.makeConst(int32_t(0)),
+ Builder::Immutable)
+ .release();
+ memoryBase32->module = g->module;
+ memoryBase32->base = TABLE_BASE32;
+ module.addGlobal(memoryBase32);
+ }
+ // Use this alternative import when initializing the segment.
+ assert(memoryBase32);
+ get->type = Type::i32;
+ get->name = memoryBase32->name;
+ }
+ } else {
+ WASM_UNREACHABLE("unexpected elem offset");
+ }
+ }
+};
+
+Pass* createTable64LoweringPass() { return new Table64Lowering(); }
+
+} // namespace wasm