diff options
author | Sam Clegg <sbc@chromium.org> | 2024-05-15 12:53:31 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-15 12:53:31 -0700 |
commit | 2b60f8a212c0e744d0dbf3346498b08c9a27a39e (patch) | |
tree | ee80a2e5a894c2af40972c269f2bb69089e9fdc0 /src/passes/Table64Lowering.cpp | |
parent | 2cc5e06549a4019eeed7303bfab32b95c32507bc (diff) | |
download | binaryen-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.cpp | 145 |
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 |