diff options
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/Memory64Lowering.cpp | 87 | ||||
-rw-r--r-- | src/passes/pass.cpp | 4 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt | 167 | ||||
-rw-r--r-- | test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast | 30 |
6 files changed, 290 insertions, 0 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index 12914e590..d352e841b 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -39,6 +39,7 @@ set(passes_SOURCES LocalCSE.cpp LogExecution.cpp LoopInvariantCodeMotion.cpp + Memory64Lowering.cpp MemoryPacking.cpp MergeBlocks.cpp MergeLocals.cpp diff --git a/src/passes/Memory64Lowering.cpp b/src/passes/Memory64Lowering.cpp new file mode 100644 index 000000000..7905c944f --- /dev/null +++ b/src/passes/Memory64Lowering.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2020 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 loads and stores that access a 64-bit memory with +// one that works as-is on wasm32. +// +// TODO(wvo): make this run in parallel if needed. + +#include "ir/bits.h" +#include "pass.h" +#include "wasm-builder.h" +#include "wasm.h" + +namespace wasm { + +struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> { + + void run(PassRunner* runner, Module* module) override { + if (module->memory.is64()) { + super::run(runner, module); + } + } + + void WrapAddress64(Expression*& ptr) { + if (ptr->type == Type::unreachable) { + return; + } + auto& module = *getModule(); + assert(module.memory.is64()); + assert(ptr->type == Type::i64); + Builder builder(module); + ptr = builder.makeUnary(UnaryOp::WrapInt64, ptr); + } + + void visitLoad(Load* curr) { WrapAddress64(curr->ptr); } + + void visitStore(Store* curr) { WrapAddress64(curr->ptr); } + + void visitMemorySize(MemorySize* curr) { + auto size = static_cast<Expression*>(curr); + WrapAddress64(size); + replaceCurrent(size); + } + + void visitMemoryGrow(MemoryGrow* curr) { + WrapAddress64(curr->delta); + auto size = static_cast<Expression*>(curr); + WrapAddress64(size); + replaceCurrent(size); + } + + void visitMemoryInit(MemoryInit* curr) { WrapAddress64(curr->dest); } + + void visitMemoryFill(MemoryFill* curr) { + WrapAddress64(curr->dest); + WrapAddress64(curr->size); + } + + void visitMemoryCopy(MemoryCopy* curr) { + WrapAddress64(curr->dest); + WrapAddress64(curr->source); + WrapAddress64(curr->size); + } + + void visitMemory(Memory* memory) { + // This is visited last. + memory->indexType = Type::i32; + } +}; + +Pass* createMemory64LoweringPass() { return new Memory64Lowering(); } + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index b653269bf..d115b4533 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -190,6 +190,10 @@ void PassRegistry::registerPasses() { registerPass("limit-segments", "attempt to merge segments to fit within web limits", createLimitSegmentsPass); + registerPass("memory64-lowering", + "lower loads and stores to a 64-bit memory to instead use a " + "32-bit one", + createMemory64LoweringPass); registerPass("memory-packing", "packs memory into separate segments, skipping zeros", createMemoryPackingPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index 53a7d3aa2..434b6e382 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -63,6 +63,7 @@ Pass* createLogExecutionPass(); Pass* createInstrumentLocalsPass(); Pass* createInstrumentMemoryPass(); Pass* createLoopInvariantCodeMotionPass(); +Pass* createMemory64LoweringPass(); Pass* createMemoryPackingPass(); Pass* createMergeBlocksPass(); Pass* createMergeLocalsPass(); diff --git a/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt b/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt new file mode 100644 index 000000000..3553c393c --- /dev/null +++ b/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt @@ -0,0 +1,167 @@ +(module + (type $none_=>_none (func)) + (memory $0 1 1) + (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00") + (func $func_1 + (drop + (i32.load + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load align=1 + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load align=2 + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load offset=100 + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load offset=100 align=1 + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load offset=100 align=2 + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load offset=100 + (i32.wrap_i64 + (i64.const 4) + ) + ) + ) + (drop + (i32.load offset=100 align=1 + (unreachable) + ) + ) + (i32.store + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store align=1 + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store align=2 + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store offset=100 + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store offset=100 align=1 + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store offset=100 align=2 + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store offset=100 + (i32.wrap_i64 + (i64.const 4) + ) + (i32.const 8) + ) + (i32.store offset=100 align=1 + (unreachable) + (i32.const 8) + ) + (i32.store offset=100 align=1 + (i32.wrap_i64 + (i64.const 4) + ) + (unreachable) + ) + (drop + (i32.wrap_i64 + (memory.size) + ) + ) + (drop + (i32.wrap_i64 + (memory.grow + (i32.wrap_i64 + (i64.const 1) + ) + ) + ) + ) + (memory.init 0 + (i32.wrap_i64 + (i64.const 1) + ) + (i32.const 2) + (i32.const 3) + ) + (memory.fill + (i32.wrap_i64 + (i64.const 1) + ) + (i32.const 2) + (i32.wrap_i64 + (i64.const 3) + ) + ) + (memory.copy + (i32.wrap_i64 + (i64.const 1) + ) + (i32.wrap_i64 + (i64.const 2) + ) + (i32.wrap_i64 + (i64.const 3) + ) + ) + ) +) diff --git a/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast b/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast new file mode 100644 index 000000000..433d509c3 --- /dev/null +++ b/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast @@ -0,0 +1,30 @@ +(module + (memory $0 i64 1 1) + (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00") + (func $func_1 + (drop (i32.load (i64.const 4))) + (drop (i32.load align=1 (i64.const 4))) + (drop (i32.load align=2 (i64.const 4))) + (drop (i32.load align=4 (i64.const 4))) + (drop (i32.load offset=100 (i64.const 4))) + (drop (i32.load offset=100 align=1 (i64.const 4))) + (drop (i32.load offset=100 align=2 (i64.const 4))) + (drop (i32.load offset=100 align=4 (i64.const 4))) + (drop (i32.load offset=100 align=1 (unreachable))) + (i32.store (i64.const 4) (i32.const 8)) + (i32.store align=1 (i64.const 4) (i32.const 8)) + (i32.store align=2 (i64.const 4) (i32.const 8)) + (i32.store align=4 (i64.const 4) (i32.const 8)) + (i32.store offset=100 (i64.const 4) (i32.const 8)) + (i32.store offset=100 align=1 (i64.const 4) (i32.const 8)) + (i32.store offset=100 align=2 (i64.const 4) (i32.const 8)) + (i32.store offset=100 align=4 (i64.const 4) (i32.const 8)) + (i32.store offset=100 align=1 (unreachable) (i32.const 8)) + (i32.store offset=100 align=1 (i64.const 4) (unreachable)) + (drop (memory.size)) + (drop (memory.grow (i64.const 1))) + (memory.init 0 (i64.const 1) (i32.const 2) (i32.const 3)) + (memory.fill (i64.const 1) (i32.const 2) (i64.const 3)) + (memory.copy (i64.const 1) (i64.const 2) (i64.const 3)) + ) +) |