diff options
author | Alon Zakai <alonzakai@gmail.com> | 2017-09-12 11:28:18 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-12 11:28:18 -0700 |
commit | 6977feb0f371c31f35ab8b1304c97dc3ac155d92 (patch) | |
tree | 906215a5d915a49ff8a3e96e86f16ed26bf6c117 | |
parent | 72f72c8b4a005bbd728d7246f87b9d347c2a775f (diff) | |
download | binaryen-6977feb0f371c31f35ab8b1304c97dc3ac155d92.tar.gz binaryen-6977feb0f371c31f35ab8b1304c97dc3ac155d92.tar.bz2 binaryen-6977feb0f371c31f35ab8b1304c97dc3ac155d92.zip |
Const hoisting (#1176)
A pass that hoists repeating constants to a local, and replaces their uses with a get of that local. This can reduce binary size, but can also *increase* gzip size, so it's mostly for experimentation and not used by default.
-rw-r--r-- | src/ast/ExpressionAnalyzer.cpp | 2 | ||||
-rw-r--r-- | src/literal.h | 26 | ||||
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/ConstHoisting.cpp | 131 | ||||
-rw-r--r-- | src/passes/DuplicateFunctionElimination.cpp | 2 | ||||
-rw-r--r-- | src/passes/pass.cpp | 1 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | src/support/hash.h | 5 | ||||
-rw-r--r-- | src/wasm-binary.h | 2 | ||||
-rw-r--r-- | src/wasm-builder.h | 6 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 6 | ||||
-rw-r--r-- | test/passes/const-hoisting.txt | 630 | ||||
-rw-r--r-- | test/passes/const-hoisting.wast | 201 |
13 files changed, 1005 insertions, 9 deletions
diff --git a/src/ast/ExpressionAnalyzer.cpp b/src/ast/ExpressionAnalyzer.cpp index b8e2ae34c..8a372c2db 100644 --- a/src/ast/ExpressionAnalyzer.cpp +++ b/src/ast/ExpressionAnalyzer.cpp @@ -313,7 +313,7 @@ uint32_t ExpressionAnalyzer::hash(Expression* curr) { digest = rehash(digest, hash); }; auto hash64 = [&digest](uint64_t hash) { - digest = rehash(rehash(digest, hash >> 32), uint32_t(hash)); + digest = rehash(rehash(digest, uint32_t(hash >> 32)), uint32_t(hash)); }; std::vector<Name> nameStack; diff --git a/src/literal.h b/src/literal.h index af87e620d..560895e7a 100644 --- a/src/literal.h +++ b/src/literal.h @@ -18,6 +18,8 @@ #define wasm_literal_h #include <iostream> + +#include "support/hash.h" #include "support/utilities.h" #include "compiler-support.h" #include "wasm-type.h" @@ -69,9 +71,9 @@ private: float reinterpretf32() const { assert(type == WasmType::i32); return bit_cast<float>(i32); } double reinterpretf64() const { assert(type == WasmType::i64); return bit_cast<double>(i64); } - int64_t getInteger(); - double getFloat(); - int64_t getBits(); + int64_t getInteger() const; + double getFloat() const; + int64_t getBits() const; bool operator==(const Literal& other) const; bool operator!=(const Literal& other) const; @@ -148,4 +150,22 @@ private: } // namespace wasm +namespace std { +template<> struct hash<wasm::Literal> { + size_t operator()(const wasm::Literal& a) const { + return wasm::rehash( + hash<size_t>()(size_t(a.type)), + hash<int64_t>()(a.getBits()) + ); + } +}; +template<> struct less<wasm::Literal> { + bool operator()(const wasm::Literal& a, const wasm::Literal& b) const { + if (a.type < b.type) return true; + if (a.type > b.type) return false; + return a.getBits() < b.getBits(); + } +}; +} + #endif // wasm_literal_h diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index edbf945cf..6870259c4 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -3,6 +3,7 @@ SET(passes_SOURCES CoalesceLocals.cpp CodePushing.cpp CodeFolding.cpp + ConstHoisting.cpp DeadCodeElimination.cpp DuplicateFunctionElimination.cpp ExtractFunction.cpp diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp new file mode 100644 index 000000000..bddc0b5c5 --- /dev/null +++ b/src/passes/ConstHoisting.cpp @@ -0,0 +1,131 @@ +/* + * Copyright 2017 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. + */ + +// +// Hoists repeated constants to a local. A get_local takes 2 bytes +// in most cases, and if a const is larger than that, it may be +// better to store it to a local, then get it from that local. +// +// WARNING: this often shrinks code size, but can *increase* gzip +// size. apparently having the constants in their proper +// places lets them be compressed better, across +// functions, etc. +// + +#include <map> + +#include <wasm.h> +#include <pass.h> +#include <wasm-binary.h> +#include <wasm-builder.h> + +namespace wasm { + +// with fewer uses than this, it is never beneficial to hoist +static const Index MIN_USES = 2; + +struct ConstHoisting : public WalkerPass<PostWalker<ConstHoisting>> { + bool isFunctionParallel() override { return true; } + + Pass* create() override { return new ConstHoisting; } + + std::map<Literal, std::vector<Expression**>> uses; + + void visitConst(Const* curr) { + uses[curr->value].push_back(getCurrentPointer()); + } + + void visitFunction(Function* curr) { + std::vector<Expression*> prelude; + for (auto& pair : uses) { + auto value = pair.first; + auto& vec = pair.second; + auto num = vec.size(); + if (worthHoisting(value, num)) { + prelude.push_back(hoist(vec)); + } + } + if (!prelude.empty()) { + Builder builder(*getModule()); + // merge-blocks can optimize this into a single block later in most cases + curr->body = builder.makeSequence( + builder.makeBlock(prelude), + curr->body + ); + } + } + +private: + bool worthHoisting(Literal value, Index num) { + if (num < MIN_USES) return false; + // measure the size of the constant + Index size; + switch (value.type) { + case i32: { + size = getWrittenSize(S32LEB(value.geti32())); + break; + } + case i64: { + size = getWrittenSize(S64LEB(value.geti64())); + break; + } + case f32: + case f64: { + size = getWasmTypeSize(value.type); + break; + } + default: WASM_UNREACHABLE(); + } + // compute the benefit, of replacing the uses with + // one use + a set and then a get for each use + // doing the algebra, the criterion here is when + // size > 2(1+num)/(num-1) + // or + // num > (size+2)/(size-2) + auto before = num * size; + auto after = size + 2 /* set_local */ + (2 /* get_local */ * num); + return after < before; + } + + template<typename T> + Index getWrittenSize(const T& thing) { + BufferWithRandomAccess buffer; + buffer << thing; + return buffer.size(); + } + + // replace all the uses with gets, for a local set at the top. returns + // the set. + Expression* hoist(std::vector<Expression**>& vec) { + auto type = (*(vec[0]))->type; + Builder builder(*getModule()); + auto temp = builder.addVar(getFunction(), type); + auto* ret = builder.makeSetLocal( + temp, + *(vec[0]) + ); + for (auto item : vec) { + *item = builder.makeGetLocal(temp, type); + } + return ret; + } +}; + +Pass *createConstHoistingPass() { + return new ConstHoisting(); +} + +} // namespace wasm diff --git a/src/passes/DuplicateFunctionElimination.cpp b/src/passes/DuplicateFunctionElimination.cpp index 5d55c7318..a96bd8fdf 100644 --- a/src/passes/DuplicateFunctionElimination.cpp +++ b/src/passes/DuplicateFunctionElimination.cpp @@ -56,7 +56,7 @@ private: digest = rehash(digest, hash); } void hash64(uint64_t hash) { - digest = rehash(rehash(digest, hash >> 32), uint32_t(hash)); + digest = rehash(rehash(digest, uint32_t(hash >> 32)), uint32_t(hash)); }; }; diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 728fe2371..4ec454a50 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -68,6 +68,7 @@ void PassRegistry::registerPasses() { registerPass("coalesce-locals-learning", "reduce # of locals by coalescing and learning", createCoalesceLocalsWithLearningPass); registerPass("code-pushing", "push code forward, potentially making it not always execute", createCodePushingPass); registerPass("code-folding", "fold code, merging duplicates", createCodeFoldingPass); + registerPass("const-hoisting", "hoist repeated constants to a local", createConstHoistingPass); registerPass("dce", "removes unreachable code", createDeadCodeEliminationPass); registerPass("duplicate-function-elimination", "removes duplicate functions", createDuplicateFunctionEliminationPass); registerPass("extract-function", "leaves just one function (useful for debugging)", createExtractFunctionPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index b1a6cb5c6..4e039f4bf 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -26,6 +26,7 @@ Pass *createCoalesceLocalsPass(); Pass *createCoalesceLocalsWithLearningPass(); Pass *createCodeFoldingPass(); Pass *createCodePushingPass(); +Pass *createConstHoistingPass(); Pass *createDeadCodeEliminationPass(); Pass *createDuplicateFunctionEliminationPass(); Pass *createExtractFunctionPass(); diff --git a/src/support/hash.h b/src/support/hash.h index e2d393d25..5ee3b8a3d 100644 --- a/src/support/hash.h +++ b/src/support/hash.h @@ -17,6 +17,7 @@ #ifndef wasm_support_hash_h #define wasm_support_hash_h +#include <functional> #include <stdint.h> namespace wasm { @@ -34,6 +35,10 @@ inline uint32_t rehash(uint32_t x, uint32_t y) { // see http://www.cse.yorku.ca/ return hash; } +inline size_t rehash(uint64_t x, uint64_t y) { // see boost and https://stackoverflow.com/a/2595226/1176841 + return x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2)); +} + } // namespace wasm #endif // wasm_support_hash_h diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 256cea75c..677f7ac62 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -142,7 +142,7 @@ class BufferWithRandomAccess : public std::vector<uint8_t> { bool debug; public: - BufferWithRandomAccess(bool debug) : debug(debug) {} + BufferWithRandomAccess(bool debug = false) : debug(debug) {} BufferWithRandomAccess& operator<<(int8_t x) { if (debug) std::cerr << "writeInt8: " << (int)(uint8_t)x << " (at " << size() << ")" << std::endl; diff --git a/src/wasm-builder.h b/src/wasm-builder.h index ad404c337..e451f9e2b 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -82,6 +82,12 @@ public: ret->name = name; return ret; } + Block* makeBlock(const std::vector<Expression*>& items) { + auto* ret = allocator.alloc<Block>(); + ret->list.set(items); + ret->finalize(); + return ret; + } If* makeIf(Expression* condition, Expression* ifTrue, Expression* ifFalse = nullptr) { auto* ret = allocator.alloc<If>(); ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse; diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index d6d7848d0..be1363dde 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -53,7 +53,7 @@ Literal Literal::castToI64() { return ret; } -int64_t Literal::getInteger() { +int64_t Literal::getInteger() const { switch (type) { case WasmType::i32: return i32; case WasmType::i64: return i64; @@ -61,7 +61,7 @@ int64_t Literal::getInteger() { } } -double Literal::getFloat() { +double Literal::getFloat() const { switch (type) { case WasmType::f32: return getf32(); case WasmType::f64: return getf64(); @@ -69,7 +69,7 @@ double Literal::getFloat() { } } -int64_t Literal::getBits() { +int64_t Literal::getBits() const { switch (type) { case WasmType::i32: case WasmType::f32: return i32; case WasmType::i64: case WasmType::f64: return i64; diff --git a/test/passes/const-hoisting.txt b/test/passes/const-hoisting.txt new file mode 100644 index 000000000..7023a5d6c --- /dev/null +++ b/test/passes/const-hoisting.txt @@ -0,0 +1,630 @@ +(module + (type $0 (func)) + (memory $0 0) + (func $10-of-each (type $0) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (block + (set_local $0 + (i32.const -1048577) + ) + (set_local $1 + (i32.const -1048576) + ) + (set_local $2 + (i32.const -8193) + ) + (set_local $3 + (i32.const 8192) + ) + (set_local $4 + (i32.const 1048575) + ) + (set_local $5 + (i32.const 1048576) + ) + ) + (block + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 63) + ) + (drop + (i32.const 64) + ) + (drop + (i32.const 8191) + ) + (drop + (get_local $3) + ) + (drop + (get_local $4) + ) + (drop + (get_local $5) + ) + (drop + (i32.const -64) + ) + (drop + (i32.const -65) + ) + (drop + (i32.const -8192) + ) + (drop + (get_local $2) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + ) + ) + (func $floats-10-times (type $0) + (local $0 f32) + (local $1 f64) + (block + (set_local $0 + (f32.const 0) + ) + (set_local $1 + (f64.const 0) + ) + ) + (block + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + (drop + (get_local $0) + ) + (drop + (get_local $1) + ) + ) + ) + (func $too-few (type $0) + (drop + (i32.const 8192) + ) + (drop + (i32.const 8192) + ) + (drop + (i32.const 8192) + ) + (drop + (i32.const 8192) + ) + (drop + (i32.const 8192) + ) + ) + (func $just-enough (type $0) + (local $0 i32) + (block + (set_local $0 + (i32.const 8192) + ) + ) + (block + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + ) + ) + (func $too-few-b (type $0) + (drop + (i32.const 1048576) + ) + (drop + (i32.const 1048576) + ) + (drop + (i32.const 1048576) + ) + ) + (func $enough-b (type $0) + (local $0 i32) + (block + (set_local $0 + (i32.const 1048576) + ) + ) + (block + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + ) + ) + (func $too-few-c (type $0) + (drop + (f32.const 0) + ) + (drop + (f32.const 0) + ) + (drop + (f32.const 0) + ) + ) + (func $enough-c (type $0) + (local $0 f32) + (block + (set_local $0 + (f32.const 0) + ) + ) + (block + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + ) + ) + (func $too-few-d (type $0) + (drop + (f64.const 0) + ) + ) + (func $enough-d (type $0) + (local $0 f64) + (block + (set_local $0 + (f64.const 0) + ) + ) + (block + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + ) + ) +) diff --git a/test/passes/const-hoisting.wast b/test/passes/const-hoisting.wast new file mode 100644 index 000000000..66f79bc14 --- /dev/null +++ b/test/passes/const-hoisting.wast @@ -0,0 +1,201 @@ +(module + (func $10-of-each + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + (drop (i32.const 0)) ;; 1 byte + (drop (i32.const 63)) ;; 1 byte + (drop (i32.const 64)) ;; 2 bytes + (drop (i32.const 8191)) ;; 2 bytes + (drop (i32.const 8192)) ;; 3 bytes + (drop (i32.const 1048575)) ;; 3 bytes + (drop (i32.const 1048576)) ;; 4 bytes + (drop (i32.const -64)) ;; 1 byte + (drop (i32.const -65)) ;; 2 bytes + (drop (i32.const -8192)) ;; 2 bytes + (drop (i32.const -8193)) ;; 3 bytes + (drop (i32.const -1048576)) ;; 3 bytes + (drop (i32.const -1048577)) ;; 4 bytes + ) + (func $floats-10-times + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + (drop (f32.const 0)) ;; 4 bytes + (drop (f64.const 0)) ;; 8 bytes + ) + (func $too-few + (drop (i32.const 8192)) ;; 3 bytes, need 6 appearances + (drop (i32.const 8192)) + (drop (i32.const 8192)) + (drop (i32.const 8192)) + (drop (i32.const 8192)) + ) + (func $just-enough + (drop (i32.const 8192)) ;; 3 bytes, need 6 appearances + (drop (i32.const 8192)) + (drop (i32.const 8192)) + (drop (i32.const 8192)) + (drop (i32.const 8192)) + (drop (i32.const 8192)) + ) + (func $too-few-b + (drop (i32.const 1048576)) ;; 4 bytes, need 4 appearances + (drop (i32.const 1048576)) + (drop (i32.const 1048576)) + ) + (func $enough-b + (drop (i32.const 1048576)) ;; 4 bytes, need 4 appearances + (drop (i32.const 1048576)) + (drop (i32.const 1048576)) + (drop (i32.const 1048576)) + ) + (func $too-few-c + (drop (f32.const 0)) ;; 4 bytes, need 4 appearances + (drop (f32.const 0)) + (drop (f32.const 0)) + ) + (func $enough-c + (drop (f32.const 0)) ;; 4 bytes, need 4 appearances + (drop (f32.const 0)) + (drop (f32.const 0)) + (drop (f32.const 0)) + ) + (func $too-few-d + (drop (f64.const 0)) ;; 8 bytes, need 2 appearances + ) + (func $enough-d + (drop (f64.const 0)) ;; 4 bytes, need 4 appearances + (drop (f64.const 0)) + ) +) + |