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/MemoryPacking.cpp80
-rw-r--r--src/passes/pass.cpp3
-rw-r--r--src/passes/passes.h3
-rw-r--r--src/tools/asm2wasm.cpp5
5 files changed, 91 insertions, 1 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index b8a0a3986..e47a7d892 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -7,6 +7,7 @@ SET(passes_SOURCES
ExtractFunction.cpp
Inlining.cpp
LegalizeJSInterface.cpp
+ MemoryPacking.cpp
MergeBlocks.cpp
Metrics.cpp
NameManager.cpp
diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp
new file mode 100644
index 000000000..1ba004886
--- /dev/null
+++ b/src/passes/MemoryPacking.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 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 <wasm.h>
+#include <pass.h>
+#include <wasm-builder.h>
+
+namespace wasm {
+
+// Adding segments adds overhead, this is a rough estimate
+const Index OVERHEAD = 8;
+
+struct MemoryPacking : public Pass {
+ void run(PassRunner* runner, Module* module) override {
+ if (!module->memory.exists) return;
+ std::vector<Memory::Segment> packed;
+ for (auto& segment : module->memory.segments) {
+ // skip final zeros
+ while (segment.data.size() > 0 && segment.data.back() == 0) {
+ segment.data.pop_back();
+ }
+ // we can only handle a constant offset for splitting
+ if (auto* offset = segment.offset->dynCast<Const>()) {
+ // Find runs of zeros, and split
+ auto& data = segment.data;
+ auto base = offset->value.geti32();
+ Index start = 0;
+ // create new segments
+ while (start < data.size()) {
+ // skip initial zeros
+ while (start < data.size() && data[start] == 0) {
+ start++;
+ }
+ Index end = start; // end of data-containing part
+ Index next = end; // after zeros we can skip. preserves next >= end
+ while (next < data.size() && (next - end < OVERHEAD)) {
+ if (data[end] != 0) {
+ end++;
+ next = end; // we can try to skip zeros from here
+ } else {
+ // end is on a zero, we are looking to skip
+ if (data[next] != 0) {
+ end = next; // we must extend the segment, including some zeros
+ } else {
+ next++;
+ }
+ }
+ }
+ if (end != start) {
+ packed.emplace_back(Builder(*module).makeConst(Literal(int32_t(base + start))), &data[start], end - start);
+ }
+ start = next;
+ }
+ } else {
+ packed.push_back(segment);
+ }
+ }
+ module->memory.segments.swap(packed);
+ }
+};
+
+Pass *createMemoryPackingPass() {
+ return new MemoryPacking();
+}
+
+} // namespace wasm
+
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index c8704db89..c307fea46 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -71,6 +71,7 @@ void PassRegistry::registerPasses() {
registerPass("extract-function", "leaves just one function (useful for debugging)", createExtractFunctionPass);
registerPass("inlining", "inlines functions (currently only ones with a single use)", createInliningPass);
registerPass("legalize-js-interface", "legalizes i64 types on the import/export boundary", createLegalizeJSInterfacePass);
+ registerPass("memory-packing", "packs memory into separate segments, skipping zeros", createMemoryPackingPass);
registerPass("merge-blocks", "merges blocks to their parents", createMergeBlocksPass);
registerPass("metrics", "reports metrics", createMetricsPass);
registerPass("nm", "name list", createNameListPass);
@@ -100,6 +101,7 @@ void PassRunner::addDefaultOptimizationPasses() {
addDefaultFunctionOptimizationPasses();
add("duplicate-function-elimination"); // optimizations show more functions as duplicate
add("remove-unused-functions");
+ add("memory-packing");
}
void PassRunner::addDefaultFunctionOptimizationPasses() {
@@ -127,6 +129,7 @@ void PassRunner::addDefaultFunctionOptimizationPasses() {
void PassRunner::addDefaultGlobalOptimizationPasses() {
add("duplicate-function-elimination");
add("remove-unused-functions");
+ add("memory-packing");
}
void PassRunner::run() {
diff --git a/src/passes/passes.h b/src/passes/passes.h
index bb577f86a..c71831e73 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -32,8 +32,9 @@ Pass *createFullPrinterPass();
Pass *createInliningPass();
Pass *createLegalizeJSInterfacePass();
Pass *createLowerIfElsePass();
-Pass *createMinifiedPrinterPass();
+Pass *createMemoryPackingPass();
Pass *createMergeBlocksPass();
+Pass *createMinifiedPrinterPass();
Pass *createMetricsPass();
Pass *createNameListPass();
Pass *createNameManagerPass();
diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp
index 6761ed28a..c5590c5eb 100644
--- a/src/tools/asm2wasm.cpp
+++ b/src/tools/asm2wasm.cpp
@@ -116,6 +116,11 @@ int main(int argc, const char *argv[]) {
init = Builder(wasm).makeConst(Literal(int32_t(atoi(memBase->second.c_str()))));
}
wasm.memory.segments.emplace_back(init, data);
+ if (runOptimizationPasses) {
+ PassRunner runner(&wasm);
+ runner.add("memory-packing");
+ runner.run();
+ }
}
if (options.debug) std::cerr << "printing..." << std::endl;