summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/Memory64Lowering.cpp126
-rw-r--r--src/passes/Table64Lowering.cpp155
-rw-r--r--src/passes/pass.cpp4
4 files changed, 119 insertions, 167 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index 6b78e487d..61c1b2f46 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -112,7 +112,6 @@ set(passes_SOURCES
ReorderGlobals.cpp
ReorderLocals.cpp
ReReloop.cpp
- Table64Lowering.cpp
TrapMode.cpp
TypeGeneralizing.cpp
TypeRefining.cpp
diff --git a/src/passes/Memory64Lowering.cpp b/src/passes/Memory64Lowering.cpp
index a3913c759..714f3aa5b 100644
--- a/src/passes/Memory64Lowering.cpp
+++ b/src/passes/Memory64Lowering.cpp
@@ -31,33 +31,58 @@ namespace wasm {
static Name MEMORY_BASE("__memory_base");
static Name MEMORY_BASE32("__memory_base32");
+static Name TABLE_BASE("__table_base");
+static Name TABLE_BASE32("__table_base32");
+
struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
- void wrapAddress64(Expression*& ptr, Name memoryName) {
+ void wrapAddress64(Expression*& ptr,
+ Name memoryOrTableName,
+ bool isTable = false) {
if (ptr->type == Type::unreachable) {
return;
}
auto& module = *getModule();
- auto* memory = module.getMemory(memoryName);
- if (memory->is64()) {
+ bool is64 = false;
+ if (isTable) {
+ is64 = module.getTable(memoryOrTableName)->is64();
+ } else {
+ is64 = module.getMemory(memoryOrTableName)->is64();
+ }
+ if (is64) {
assert(ptr->type == Type::i64);
ptr = Builder(module).makeUnary(UnaryOp::WrapInt64, ptr);
}
}
- void extendAddress64(Expression*& ptr, Name memoryName) {
+ void extendAddress64(Expression*& ptr,
+ Name memoryOrTableName,
+ bool isTable = false) {
if (ptr->type == Type::unreachable) {
return;
}
auto& module = *getModule();
- auto* memory = module.getMemory(memoryName);
- if (memory->is64()) {
+ bool is64 = false;
+ if (isTable) {
+ is64 = module.getTable(memoryOrTableName)->is64();
+ } else {
+ is64 = module.getMemory(memoryOrTableName)->is64();
+ }
+ if (is64) {
assert(ptr->type == Type::i64);
ptr->type = Type::i32;
ptr = Builder(module).makeUnary(UnaryOp::ExtendUInt32, ptr);
}
}
+ void wrapTableAddress64(Expression*& ptr, Name tableName) {
+ return wrapAddress64(ptr, tableName, true);
+ }
+
+ void extendTableAddress64(Expression*& ptr, Name tableName) {
+ return extendAddress64(ptr, tableName, true);
+ }
+
void visitLoad(Load* curr) { wrapAddress64(curr->ptr, curr->memory); }
void visitStore(Store* curr) { wrapAddress64(curr->ptr, curr->memory); }
@@ -177,14 +202,92 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
}
}
+ void visitTableSize(TableSize* curr) {
+ auto& module = *getModule();
+ auto* table = module.getTable(curr->table);
+ if (table->is64()) {
+ auto* size = static_cast<Expression*>(curr);
+ extendTableAddress64(size, curr->table);
+ replaceCurrent(size);
+ }
+ }
+
+ void visitTableGrow(TableGrow* curr) {
+ auto& module = *getModule();
+ auto* table = module.getTable(curr->table);
+ if (table->is64()) {
+ wrapTableAddress64(curr->delta, curr->table);
+ auto* size = static_cast<Expression*>(curr);
+ extendTableAddress64(size, curr->table);
+ replaceCurrent(size);
+ }
+ }
+
+ void visitTableFill(TableFill* curr) {
+ wrapTableAddress64(curr->dest, curr->table);
+ wrapTableAddress64(curr->size, curr->table);
+ }
+
+ void visitTableCopy(TableCopy* curr) {
+ wrapTableAddress64(curr->dest, curr->destTable);
+ wrapTableAddress64(curr->source, curr->sourceTable);
+ wrapTableAddress64(curr->size, curr->destTable);
+ }
+
+ void visitTableInit(TableInit* curr) {
+ wrapTableAddress64(curr->dest, curr->table);
+ }
+
+ void visitCallIndirect(CallIndirect* curr) {
+ wrapTableAddress64(curr->target, curr->table);
+ }
+
+ void visitElementSegment(ElementSegment* segment) {
+ auto& module = *getModule();
+
+ // Passive segments don't have any offset to update.
+ if (segment->table.isNull() || !module.getTable(segment->table)->is64()) {
+ 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* 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");
+ }
+ }
+
void run(Module* module) override {
if (!module->features.has(FeatureSet::Memory64)) {
return;
}
Super::run(module);
- // Don't modify the memories themselves until after the traversal since we
- // that would require memories to be the last thing that get visited, and
- // we don't want to depend on that specific ordering.
+ // Don't modify the memories or tables themselves until after the traversal
+ // since we that would require memories to be the last thing that get
+ // visited, and we don't want to depend on that specific ordering.
for (auto& memory : module->memories) {
if (memory->is64()) {
memory->addressType = Type::i32;
@@ -193,6 +296,11 @@ struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
}
}
}
+ for (auto& table : module->tables) {
+ if (table->is64()) {
+ table->addressType = Type::i32;
+ }
+ }
module->features.disable(FeatureSet::Memory64);
}
};
diff --git a/src/passes/Table64Lowering.cpp b/src/passes/Table64Lowering.cpp
deleted file mode 100644
index 1167515de..000000000
--- a/src/passes/Table64Lowering.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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 visitTableInit(TableInit* curr) {
- wrapAddress64(curr->dest, curr->table);
- }
-
- void visitCallIndirect(CallIndirect* curr) {
- wrapAddress64(curr->target, curr->table);
- }
-
- void visitElementSegment(ElementSegment* segment) {
- auto& module = *getModule();
-
- // Passive segments don't have any offset to update.
- if (segment->table.isNull() || !module.getTable(segment->table)->is64()) {
- 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* 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");
- }
- }
-
- void run(Module* module) override {
- Super::run(module);
- // Don't modify the tables themselves until after the traversal since we
- // that would require tables to be the last thing that get visited, and
- // we don't want to depend on that specific ordering.
- for (auto& table : module->tables) {
- if (table->is64()) {
- table->addressType = Type::i32;
- }
- }
- }
-};
-
-Pass* createTable64LoweringPass() { return new Table64Lowering(); }
-
-} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 7f6985e0f..ab95300d0 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -273,8 +273,8 @@ void PassRegistry::registerPasses() {
"32-bit one",
createMemory64LoweringPass);
registerPass("table64-lowering",
- "lower 64-bit tables 32-bit ones",
- createTable64LoweringPass);
+ "alias for memory64-lowering",
+ createMemory64LoweringPass);
registerPass("llvm-memory-copy-fill-lowering",
"Lower memory.copy and memory.fill to wasm mvp and disable "
"the bulk-memory feature.",