diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ir/memory-utils.cpp | 72 | ||||
-rw-r--r-- | src/ir/memory-utils.h | 40 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 43 |
4 files changed, 99 insertions, 57 deletions
diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index 08149e15e..5b6417091 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -5,6 +5,7 @@ set(ir_SOURCES eh-utils.cpp intrinsics.cpp lubs.cpp + memory-utils.cpp names.cpp properties.cpp LocalGraph.cpp diff --git a/src/ir/memory-utils.cpp b/src/ir/memory-utils.cpp new file mode 100644 index 000000000..b7c92fe9e --- /dev/null +++ b/src/ir/memory-utils.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2022 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. + */ + +#include "ir/memory-utils.h" +#include "wasm.h" + +namespace wasm::MemoryUtils { + +bool flatten(Module& wasm) { + // The presence of any MemoryInit instructions is a problem because they care + // about segment identity, which flattening gets rid of ( when it merges them + // all into one big segment). + ModuleUtils::ParallelFunctionAnalysis<bool> analysis( + wasm, [&](Function* func, bool& hasMemoryInit) { + if (func->imported()) { + return; + } + hasMemoryInit = FindAll<MemoryInit>(func->body).list.size() > 0; + }); + + for (auto& [func, hasMemoryInit] : analysis.map) { + if (hasMemoryInit) { + return false; + } + } + + auto& memory = wasm.memory; + + if (memory.segments.size() == 0) { + return true; + } + + std::vector<char> data; + for (auto& segment : memory.segments) { + if (segment.isPassive) { + return false; + } + auto* offset = segment.offset->dynCast<Const>(); + if (!offset) { + return false; + } + } + for (auto& segment : memory.segments) { + auto* offset = segment.offset->dynCast<Const>(); + Index start = offset->value.getInteger(); + Index end = start + segment.data.size(); + if (end > data.size()) { + data.resize(end); + } + std::copy(segment.data.begin(), segment.data.end(), data.begin() + start); + } + memory.segments.resize(1); + memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0)); + memory.segments[0].data.swap(data); + + return true; +} + +} // namespace wasm::MemoryUtils diff --git a/src/ir/memory-utils.h b/src/ir/memory-utils.h index 3a0862cd7..9b3325329 100644 --- a/src/ir/memory-utils.h +++ b/src/ir/memory-utils.h @@ -29,46 +29,8 @@ namespace wasm::MemoryUtils { // Flattens memory into a single data segment, or no segment. If there is // a segment, it starts at 0. -// If ensuredSegmentSize is provided, then a segment is always emitted, -// and of at least that size. // Returns true if successful (e.g. relocatable segments cannot be flattened). -inline bool flatten(Memory& memory, - Index ensuredSegmentSize = 0, - Module* module = nullptr) { - if (memory.segments.size() == 0) { - if (ensuredSegmentSize > 0) { - assert(module); // must provide a module if ensuring a size. - Builder builder(*module); - memory.segments.emplace_back(builder.makeConst(int32_t(0))); - memory.segments[0].data.resize(ensuredSegmentSize); - } - return true; - } - std::vector<char> data; - data.resize(ensuredSegmentSize); - for (auto& segment : memory.segments) { - if (segment.isPassive) { - return false; - } - auto* offset = segment.offset->dynCast<Const>(); - if (!offset) { - return false; - } - } - for (auto& segment : memory.segments) { - auto* offset = segment.offset->dynCast<Const>(); - Index start = offset->value.getInteger(); - Index end = start + segment.data.size(); - if (end > data.size()) { - data.resize(end); - } - std::copy(segment.data.begin(), segment.data.end(), data.begin() + start); - } - memory.segments.resize(1); - memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0)); - memory.segments[0].data.swap(data); - return true; -} +bool flatten(Module& wasm); // Ensures that the memory exists (of minimal size). inline void ensureExists(Memory& memory) { diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index e6883e351..3923d137c 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -663,11 +663,6 @@ void evalCtors(Module& wasm, CtorEvalExternalInterface interface(linkedInstances); try { - // flatten memory, so we do not depend on the layout of data segments - if (!MemoryUtils::flatten(wasm.memory)) { - Fatal() << " ...stopping since could not flatten memory\n"; - } - // create an instance for evalling EvallingModuleInstance instance(wasm, &interface, linkedInstances); // we should not add new globals from here on; as a result, using @@ -712,6 +707,16 @@ void evalCtors(Module& wasm, } } +static bool canEval(Module& wasm) { + // Check if we can flatten memory. We need to do so currently because of how + // we assume memory is simple and flat. TODO + if (!MemoryUtils::flatten(wasm)) { + std::cout << " ...stopping since could not flatten memory\n"; + return false; + } + return true; +} + } // anonymous namespace // @@ -808,19 +813,21 @@ int main(int argc, const char* argv[]) { Fatal() << "error in validating input"; } - evalCtors(wasm, ctors, keptExports); - - // Do some useful optimizations after the evalling - { - PassRunner passRunner(&wasm); - passRunner.add("memory-packing"); // we flattened it, so re-optimize - // TODO: just do -Os for the one function - passRunner.add("remove-unused-names"); - passRunner.add("dce"); - passRunner.add("merge-blocks"); - passRunner.add("vacuum"); - passRunner.add("remove-unused-module-elements"); - passRunner.run(); + if (canEval(wasm)) { + evalCtors(wasm, ctors, keptExports); + + // Do some useful optimizations after the evalling + { + PassRunner passRunner(&wasm); + passRunner.add("memory-packing"); // we flattened it, so re-optimize + // TODO: just do -Os for the one function + passRunner.add("remove-unused-names"); + passRunner.add("dce"); + passRunner.add("merge-blocks"); + passRunner.add("vacuum"); + passRunner.add("remove-unused-module-elements"); + passRunner.run(); + } } if (options.extra.count("output") > 0) { |